pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
pcmk_resource.c
Go to the documentation of this file.
1 /*
2  * Copyright 2021-2023 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <errno.h>
13 #include <glib.h>
14 #include <libxml/tree.h>
15 
16 #include <crm/common/mainloop.h>
17 #include <crm/common/results.h>
19 #include <crm/pengine/internal.h>
20 
21 #include <pacemaker.h>
22 #include <pacemaker-internal.h>
23 
24 // Search path for resource operation history (takes node name and resource ID)
25 #define XPATH_OP_HISTORY "//" XML_CIB_TAG_STATUS \
26  "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
27  "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES \
28  "/" XML_LRM_TAG_RESOURCE "[@" XML_ATTR_ID "='%s']"
29 
30 static xmlNode *
31 best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
32 {
33  char *xpath = NULL;
34  xmlNode *history = NULL;
35  xmlNode *best = NULL;
36  bool best_effective_op = false;
37  guint best_interval = 0;
38  bool best_failure = false;
39  const char *best_digest = NULL;
40 
41  // Find node's resource history
42  xpath = crm_strdup_printf(XPATH_OP_HISTORY, node->details->uname, rsc->id);
43  history = get_xpath_object(xpath, rsc->cluster->input, LOG_NEVER);
44  free(xpath);
45 
46  // Examine each history entry
47  for (xmlNode *lrm_rsc_op = first_named_child(history, XML_LRM_TAG_RSC_OP);
48  lrm_rsc_op != NULL; lrm_rsc_op = crm_next_same_xml(lrm_rsc_op)) {
49 
50  const char *digest = crm_element_value(lrm_rsc_op,
52  guint interval_ms = 0;
53  const char *task = crm_element_value(lrm_rsc_op, XML_LRM_ATTR_TASK);
54  bool effective_op = false;
55  bool failure = pcmk__ends_with(ID(lrm_rsc_op), "_last_failure_0");
56 
57 
58  crm_element_value_ms(lrm_rsc_op, XML_LRM_ATTR_INTERVAL, &interval_ms);
59  effective_op = interval_ms == 0
64 
65  if (best == NULL) {
66  goto is_best;
67  }
68 
69  if (best_effective_op) {
70  // Do not use an ineffective op if there's an effective one.
71  if (!effective_op) {
72  continue;
73  }
74  // Do not use an ineffective non-recurring op if there's a recurring one
75  } else if (best_interval != 0
76  && !effective_op
77  && interval_ms == 0) {
78  continue;
79  }
80 
81  // Do not use last failure if there's a successful one.
82  if (!best_failure && failure) {
83  continue;
84  }
85 
86  // Do not use an op without a restart digest if there's one with.
87  if (best_digest != NULL && digest == NULL) {
88  continue;
89  }
90 
91  // Do not use an older op if there's a newer one.
92  if (pe__is_newer_op(best, lrm_rsc_op, true) > 0) {
93  continue;
94  }
95 
96 is_best:
97  best = lrm_rsc_op;
98  best_effective_op = effective_op;
99  best_interval = interval_ms;
100  best_failure = failure;
101  best_digest = digest;
102  }
103  return best;
104 }
105 
117 int
119  const pcmk_node_t *node, GHashTable *overrides)
120 {
121  const char *task = NULL;
122  xmlNode *xml_op = NULL;
123  op_digest_cache_t *digests = NULL;
124  guint interval_ms = 0;
125  int rc = pcmk_rc_ok;
126 
127  if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
128  return EINVAL;
129  }
130  if (rsc->variant != pcmk_rsc_variant_primitive) {
131  // Only primitives get operation digests
132  return EOPNOTSUPP;
133  }
134 
135  // Find XML of operation history to use
136  xml_op = best_op(rsc, node);
137 
138  // Generate an operation key
139  if (xml_op != NULL) {
140  task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
141  crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
142  }
143  if (task == NULL) { // Assume start if no history is available
144  task = PCMK_ACTION_START;
145  interval_ms = 0;
146  }
147 
148  // Calculate and show digests
149  digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
150  overrides, true, rsc->cluster);
151  rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
152 
153  pe__free_digests(digests);
154  return rc;
155 }
156 
157 int
159  const pcmk_node_t *node, GHashTable *overrides,
161 {
162  pcmk__output_t *out = NULL;
163  int rc = pcmk_rc_ok;
164 
165  rc = pcmk__xml_output_new(&out, xml);
166  if (rc != pcmk_rc_ok) {
167  return rc;
168  }
170  rc = pcmk__resource_digests(out, rsc, node, overrides);
171  pcmk__xml_output_finish(out, xml);
172  return rc;
173 }
int pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides, pcmk_scheduler_t *scheduler)
Calculate and output resource operation digests.
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:933
int(* message)(pcmk__output_t *out, const char *message_id,...)
#define XPATH_OP_HISTORY
Definition: pcmk_resource.c:25
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2484
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
Definition: pe_actions.c:1682
#define PCMK_ACTION_MONITOR
Definition: actions.h:59
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:300
High Level API.
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:533
Implementation of pcmk_scheduler_t.
Definition: scheduler.h:172
#define LOG_NEVER
Definition: logging.h:48
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:211
Wrappers for and extensions to glib mainloop.
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:306
Formatted output for pacemaker tools.
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:540
Implementation of pcmk_resource_t.
Definition: resources.h:399
Primitive resource.
Definition: resources.h:34
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition: output.c:236
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
op_digest_cache_t * pe__calculate_digests(pcmk_resource_t *rsc, const char *task, guint *interval_ms, const pcmk_node_t *node, const xmlNode *xml_op, GHashTable *overrides, bool calc_secure, pcmk_scheduler_t *scheduler)
Definition: pe_digest.c:306
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
#define PCMK_ACTION_START
Definition: actions.h:71
const char * uname
Node name in cluster.
Definition: nodes.h:68
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2403
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:322
void pe__free_digests(gpointer ptr)
Definition: pe_digest.c:34
Implementation of pcmk_node_t.
Definition: nodes.h:130
enum pe_obj_types variant
Resource variant.
Definition: resources.h:414
xmlNode * input
CIB XML.
Definition: scheduler.h:175
Function and executable result codes.
pcmk_scheduler_t * scheduler
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:57
This structure contains everything that makes up a single output formatter.
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:304
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
void pcmk__xml_output_finish(pcmk__output_t *out, xmlNodePtr *xml)
Definition: output.c:258
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:279
#define ID(x)
Definition: msg_xml.h:474
int pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides)
char * id
Resource ID in configuration.
Definition: resources.h:400
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2510