pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk_resource.c
Go to the documentation of this file.
1 /*
2  * Copyright 2021-2024 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/cib/internal.h>
17 #include <crm/common/mainloop.h>
18 #include <crm/common/results.h>
20 #include <crm/pengine/internal.h>
21 
22 #include <pacemaker.h>
23 #include <pacemaker-internal.h>
24 
25 // Search path for resource operation history (takes node name and resource ID)
26 #define XPATH_OP_HISTORY "//" PCMK_XE_STATUS \
27  "/" PCMK__XE_NODE_STATE \
28  "[@" PCMK_XA_UNAME "='%s']" \
29  "/" PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES \
30  "/" PCMK__XE_LRM_RESOURCE "[@" PCMK_XA_ID "='%s']"
31 
32 static xmlNode *
33 best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
34 {
35  char *xpath = NULL;
36  xmlNode *history = NULL;
37  xmlNode *best = NULL;
38  bool best_effective_op = false;
39  guint best_interval = 0;
40  bool best_failure = false;
41  const char *best_digest = NULL;
42 
43  // Find node's resource history
44  xpath = crm_strdup_printf(XPATH_OP_HISTORY, node->priv->name, rsc->id);
45  history = get_xpath_object(xpath, rsc->priv->scheduler->input, LOG_NEVER);
46  free(xpath);
47 
48  // Examine each history entry
49  for (xmlNode *lrm_rsc_op = pcmk__xe_first_child(history,
50  PCMK__XE_LRM_RSC_OP, NULL,
51  NULL);
52  lrm_rsc_op != NULL;
53  lrm_rsc_op = pcmk__xe_next(lrm_rsc_op, PCMK__XE_LRM_RSC_OP)) {
54 
55  const char *digest = crm_element_value(lrm_rsc_op,
57  guint interval_ms = 0;
58  const char *task = crm_element_value(lrm_rsc_op, PCMK_XA_OPERATION);
59  bool effective_op = false;
60  bool failure = pcmk__ends_with(pcmk__xe_id(lrm_rsc_op),
61  "_last_failure_0");
62 
63 
64  crm_element_value_ms(lrm_rsc_op, PCMK_META_INTERVAL, &interval_ms);
65  effective_op = interval_ms == 0
70 
71  if (best == NULL) {
72  goto is_best;
73  }
74 
75  if (best_effective_op) {
76  // Do not use an ineffective op if there's an effective one.
77  if (!effective_op) {
78  continue;
79  }
80  // Do not use an ineffective non-recurring op if there's a recurring one
81  } else if (best_interval != 0
82  && !effective_op
83  && interval_ms == 0) {
84  continue;
85  }
86 
87  // Do not use last failure if there's a successful one.
88  if (!best_failure && failure) {
89  continue;
90  }
91 
92  // Do not use an op without a restart digest if there's one with.
93  if (best_digest != NULL && digest == NULL) {
94  continue;
95  }
96 
97  // Do not use an older op if there's a newer one.
98  if (pe__is_newer_op(best, lrm_rsc_op) > 0) {
99  continue;
100  }
101 
102 is_best:
103  best = lrm_rsc_op;
104  best_effective_op = effective_op;
105  best_interval = interval_ms;
106  best_failure = failure;
107  best_digest = digest;
108  }
109  return best;
110 }
111 
123 int
124 pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id,
125  const char *rsc_type)
126 {
127  int rc = pcmk_rc_ok;
128  xmlNode *msg_data = NULL;
129 
130  if (cib == NULL) {
131  return ENOTCONN;
132  }
133 
134  if (rsc_id == NULL || rsc_type == NULL) {
135  return EINVAL;
136  }
137 
138  msg_data = pcmk__xe_create(NULL, rsc_type);
139  crm_xml_add(msg_data, PCMK_XA_ID, rsc_id);
140 
141  rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, msg_data, cib_opts);
142  rc = pcmk_legacy2rc(rc);
143 
144  pcmk__xml_free(msg_data);
145  return rc;
146 }
147 
148 int
149 pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
150 {
151  pcmk__output_t *out = NULL;
152  int rc = pcmk_rc_ok;
153  uint32_t cib_opts = cib_sync_call;
154  cib_t *cib = NULL;
155 
156  rc = pcmk__xml_output_new(&out, xml);
157  if (rc != pcmk_rc_ok) {
158  return rc;
159  }
160 
161  cib = cib_new();
162  if (cib == NULL) {
163  rc = pcmk_rc_cib_corrupt;
164  goto done;
165  }
166 
167  rc = cib->cmds->signon(cib, crm_system_name, cib_command);
168  rc = pcmk_legacy2rc(rc);
169 
170  if (rc != pcmk_rc_ok) {
171  goto done;
172  }
173 
174  rc = pcmk__resource_delete(cib, cib_opts, rsc_id, rsc_type);
175 
176 done:
177  if (cib != NULL) {
179  }
180 
181  pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
182  return rc;
183 }
184 
196 int
198  const pcmk_node_t *node, GHashTable *overrides)
199 {
200  const char *task = NULL;
201  xmlNode *xml_op = NULL;
202  pcmk__op_digest_t *digests = NULL;
203  guint interval_ms = 0;
204  int rc = pcmk_rc_ok;
205 
206  if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
207  return EINVAL;
208  }
209 
210  if (!pcmk__is_primitive(rsc)) {
211  // Only primitives get operation digests
212  return EOPNOTSUPP;
213  }
214 
215  // Find XML of operation history to use
216  xml_op = best_op(rsc, node);
217 
218  // Generate an operation key
219  if (xml_op != NULL) {
220  task = crm_element_value(xml_op, PCMK_XA_OPERATION);
221  crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
222  }
223  if (task == NULL) { // Assume start if no history is available
224  task = PCMK_ACTION_START;
225  interval_ms = 0;
226  }
227 
228  // Calculate and show digests
229  digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
230  overrides, true, rsc->priv->scheduler);
231  rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
232 
233  pe__free_digests(digests);
234  return rc;
235 }
236 
237 int
239  const pcmk_node_t *node, GHashTable *overrides)
240 {
241  pcmk__output_t *out = NULL;
242  int rc = pcmk_rc_ok;
243 
244  rc = pcmk__xml_output_new(&out, xml);
245  if (rc != pcmk_rc_ok) {
246  return rc;
247  }
249  rc = pcmk__resource_digests(out, rsc, node, overrides);
250  pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
251  return rc;
252 }
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
int pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
Remove a resource.
cib_t * cib_new(void)
Create a new CIB connection object.
Definition: cib_client.c:562
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1027
int(* message)(pcmk__output_t *out, const char *message_id,...)
#define XPATH_OP_HISTORY
Definition: pcmk_resource.c:26
#define PCMK_ACTION_MONITOR
Definition: actions.h:51
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:810
High Level API.
char * crm_system_name
Definition: utils.c:44
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition: output.c:271
#define PCMK__XA_OP_RESTART_DIGEST
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:610
#define LOG_NEVER
Definition: logging.h:48
#define PCMK_XA_OPERATION
Definition: xml_names.h:349
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
Wrappers for and extensions to glib mainloop.
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
pcmk__node_private_t * priv
Definition: nodes.h:85
Formatted output for pacemaker tools.
cib_api_operations_t * cmds
Definition: cib_types.h:325
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: xml_element.c:1322
pcmk_scheduler_t * scheduler
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:124
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition: output.c:244
pcmk__op_digest_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:303
int pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides)
Calculate and output resource operation digests.
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2709
#define PCMK_XA_ID
Definition: xml_names.h:301
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:667
void pe__free_digests(gpointer ptr)
Definition: pe_digest.c:33
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:920
Function and executable result codes.
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b)
Definition: pe_actions.c:1612
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
#define PCMK_META_INTERVAL
Definition: options.h:91
#define PCMK__XE_LRM_RSC_OP
xmlNode * input
Definition: scheduler.h:81
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:49
This structure contains everything that makes up a single output formatter.
int pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id, const char *rsc_type)
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:174
#define PCMK_XE_RESOURCES
Definition: xml_names.h:179
int pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1