pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
operations.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 
21 #include <crm/crm.h>
22 #include <crm/lrmd.h>
23 #include <crm/msg_xml.h>
24 #include <crm/common/xml.h>
25 #include <crm/common/util.h>
26 
38 char *
39 generate_op_key(const char *rsc_id, const char *op_type, guint interval_ms)
40 {
41  CRM_ASSERT(rsc_id != NULL);
42  CRM_ASSERT(op_type != NULL);
43  return crm_strdup_printf(CRM_OP_FMT, rsc_id, op_type, interval_ms);
44 }
45 
46 gboolean
47 parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
48 {
49  char *notify = NULL;
50  char *mutable_key = NULL;
51  char *mutable_key_ptr = NULL;
52  size_t len = 0, offset = 0;
53  unsigned long long ch = 0;
54  guint local_interval_ms = 0;
55 
56  // Initialize output variables in case of early return
57  if (rsc_id) {
58  *rsc_id = NULL;
59  }
60  if (op_type) {
61  *op_type = NULL;
62  }
63  if (interval_ms) {
64  *interval_ms = 0;
65  }
66 
67  CRM_CHECK(key && *key, return FALSE);
68 
69  // Parse interval at end of string
70  len = strlen(key);
71  offset = len - 1;
72  while ((offset > 0) && isdigit(key[offset])) {
73  ch = key[offset] - '0';
74  for (int digits = len - offset; digits > 1; --digits) {
75  ch = ch * 10;
76  }
77  local_interval_ms += ch;
78  offset--;
79  }
80  crm_trace("Operation key '%s' has interval %ums", key, local_interval_ms);
81  if (interval_ms) {
82  *interval_ms = local_interval_ms;
83  }
84 
85  CRM_CHECK((offset != (len - 1)) && (key[offset] == '_'), return FALSE);
86 
87  mutable_key = strndup(key, offset);
88  offset--;
89 
90  while (offset > 0 && key[offset] != '_') {
91  offset--;
92  }
93 
94  CRM_CHECK(key[offset] == '_',
95  free(mutable_key); return FALSE);
96 
97  mutable_key_ptr = mutable_key + offset + 1;
98 
99  crm_trace(" Action: %s", mutable_key_ptr);
100  if (op_type) {
101  *op_type = strdup(mutable_key_ptr);
102  }
103 
104  mutable_key[offset] = 0;
105  offset--;
106 
107  notify = strstr(mutable_key, "_post_notify");
108  if (notify && safe_str_eq(notify, "_post_notify")) {
109  notify[0] = 0;
110  }
111 
112  notify = strstr(mutable_key, "_pre_notify");
113  if (notify && safe_str_eq(notify, "_pre_notify")) {
114  notify[0] = 0;
115  }
116 
117  crm_trace(" Resource: %s", mutable_key);
118  if (rsc_id) {
119  *rsc_id = mutable_key;
120  } else {
121  free(mutable_key);
122  }
123 
124  return TRUE;
125 }
126 
127 char *
128 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
129 {
130  CRM_CHECK(rsc_id != NULL, return NULL);
131  CRM_CHECK(op_type != NULL, return NULL);
132  CRM_CHECK(notify_type != NULL, return NULL);
133  return crm_strdup_printf("%s_%s_notify_%s_0",
134  rsc_id, notify_type, op_type);
135 }
136 
152 gboolean
153 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
154  int *op_status, int *op_rc, int *target_rc)
155 {
156  int res = 0;
157  char *key = NULL;
158  gboolean result = TRUE;
159  int local_op_status = -1;
160  int local_op_rc = -1;
161 
162  CRM_CHECK(magic != NULL, return FALSE);
163 
164 #ifdef SSCANF_HAS_M
165  res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
166 #else
167  key = calloc(1, strlen(magic) - 3); // magic must have >=4 other characters
168  CRM_ASSERT(key);
169  res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
170 #endif
171  if (res == EOF) {
172  crm_err("Could not decode transition information '%s': %s",
173  magic, pcmk_strerror(errno));
174  result = FALSE;
175  } else if (res < 3) {
176  crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
177  magic, res);
178  result = FALSE;
179  } else {
180  if (op_status) {
181  *op_status = local_op_status;
182  }
183  if (op_rc) {
184  *op_rc = local_op_rc;
185  }
186  result = decode_transition_key(key, uuid, transition_id, action_id,
187  target_rc);
188  }
189  free(key);
190  return result;
191 }
192 
193 char *
194 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
195 {
196  CRM_CHECK(node != NULL, return NULL);
197  return crm_strdup_printf("%d:%d:%d:%-*s",
198  action_id, transition_id, target_rc, 36, node);
199 }
200 
214 gboolean
215 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
216  int *target_rc)
217 {
218  int local_transition_id = -1;
219  int local_action_id = -1;
220  int local_target_rc = -1;
221  char local_uuid[37] = { '\0' };
222 
223  // Initialize any supplied output arguments
224  if (uuid) {
225  *uuid = NULL;
226  }
227  if (transition_id) {
228  *transition_id = -1;
229  }
230  if (action_id) {
231  *action_id = -1;
232  }
233  if (target_rc) {
234  *target_rc = -1;
235  }
236 
237  CRM_CHECK(key != NULL, return FALSE);
238  if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
239  &local_target_rc, local_uuid) != 4) {
240  crm_err("Invalid transition key '%s'", key);
241  return FALSE;
242  }
243  if (strlen(local_uuid) != 36) {
244  crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
245  }
246  if (uuid) {
247  *uuid = strdup(local_uuid);
248  CRM_ASSERT(*uuid);
249  }
250  if (transition_id) {
251  *transition_id = local_transition_id;
252  }
253  if (action_id) {
254  *action_id = local_action_id;
255  }
256  if (target_rc) {
257  *target_rc = local_target_rc;
258  }
259  return TRUE;
260 }
261 
262 void
263 filter_action_parameters(xmlNode * param_set, const char *version)
264 {
265  char *key = NULL;
266  char *timeout = NULL;
267  char *interval_ms_s = NULL;
268 
269  const char *attr_filter[] = {
270  XML_ATTR_ID,
275  "pcmk_external_ip"
276  };
277 
278  gboolean do_delete = FALSE;
279  int lpc = 0;
280  static int meta_len = 0;
281 
282  if (meta_len == 0) {
283  meta_len = strlen(CRM_META);
284  }
285 
286  if (param_set == NULL) {
287  return;
288  }
289 
290  for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
291  xml_remove_prop(param_set, attr_filter[lpc]);
292  }
293 
295  interval_ms_s = crm_element_value_copy(param_set, key);
296  free(key);
297 
299  timeout = crm_element_value_copy(param_set, key);
300 
301  if (param_set) {
302  xmlAttrPtr xIter = param_set->properties;
303 
304  while (xIter) {
305  const char *prop_name = (const char *)xIter->name;
306 
307  xIter = xIter->next;
308  do_delete = FALSE;
309  if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
310  do_delete = TRUE;
311  }
312 
313  if (do_delete) {
314  xml_remove_prop(param_set, prop_name);
315  }
316  }
317  }
318 
319  if (interval_ms_s && strcmp(interval_ms_s, "0")) {
320  /* Re-instate the operation's timeout value */
321  if (timeout != NULL) {
322  crm_xml_add(param_set, key, timeout);
323  }
324  }
325 
326  free(interval_ms_s);
327  free(timeout);
328  free(key);
329 }
330 
331 int
333 {
334  int rc = 0;
335 
336  if (op && op->user_data) {
337  decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
338  }
339  return rc;
340 }
341 
342 gboolean
343 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
344 {
345  switch (op->op_status) {
347  case PCMK_LRM_OP_PENDING:
348  return FALSE;
349  break;
350 
352  case PCMK_LRM_OP_TIMEOUT:
353  case PCMK_LRM_OP_ERROR:
355  case PCMK_LRM_OP_INVALID:
356  return TRUE;
357  break;
358 
359  default:
360  if (target_rc != op->rc) {
361  return TRUE;
362  }
363  }
364 
365  return FALSE;
366 }
367 
379 xmlNode *
380 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
381  const char *interval_spec, const char *timeout)
382 {
383  xmlNode *xml_op;
384 
385  CRM_CHECK(prefix && task && interval_spec, return NULL);
386 
387  xml_op = create_xml_node(parent, XML_ATTR_OP);
388  crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
389  crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval_spec);
390  crm_xml_add(xml_op, "name", task);
391  if (timeout) {
392  crm_xml_add(xml_op, XML_ATTR_TIMEOUT, timeout);
393  }
394  return xml_op;
395 }
396 
406 bool
407 crm_op_needs_metadata(const char *rsc_class, const char *op)
408 {
409  /* Agent meta-data is used to determine whether a reload is possible, and to
410  * evaluate versioned parameters -- so if this op is not relevant to those
411  * features, we don't need the meta-data.
412  */
413 
414  CRM_CHECK(rsc_class || op, return FALSE);
415 
416  if (rsc_class
417  && is_not_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
418  /* Meta-data is only needed for resource classes that use parameters */
419  return FALSE;
420  }
421 
422  /* Meta-data is only needed for these actions */
423  if (op
424  && strcmp(op, CRMD_ACTION_START)
425  && strcmp(op, CRMD_ACTION_STATUS)
426  && strcmp(op, CRMD_ACTION_PROMOTE)
427  && strcmp(op, CRMD_ACTION_DEMOTE)
428  && strcmp(op, CRMD_ACTION_RELOAD)
429  && strcmp(op, CRMD_ACTION_MIGRATE)
430  && strcmp(op, CRMD_ACTION_MIGRATED)
431  && strcmp(op, CRMD_ACTION_NOTIFY)) {
432  return FALSE;
433  }
434 
435  return TRUE;
436 }
crm_op_needs_metadata
bool crm_op_needs_metadata(const char *rsc_class, const char *op)
Check whether an operation requires resource agent meta-data.
Definition: operations.c:407
msg_xml.h
XML_LRM_ATTR_TARGET_UUID
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:263
PCMK_LRM_OP_ERROR
@ PCMK_LRM_OP_ERROR
Definition: services.h:125
crm_create_op_xml
xmlNode * crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task, const char *interval_spec, const char *timeout)
Create a CIB XML element for an operation.
Definition: operations.c:380
CRMD_ACTION_NOTIFY
#define CRMD_ACTION_NOTIFY
Definition: crm.h:183
create_xml_node
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1970
PCMK_LRM_OP_CANCELLED
@ PCMK_LRM_OP_CANCELLED
Definition: services.h:122
lrmd_event_data_s::rc
enum ocf_exitcode rc
Definition: lrmd.h:221
PCMK_LRM_OP_NOT_CONNECTED
@ PCMK_LRM_OP_NOT_CONNECTED
Definition: services.h:129
pcmk_strerror
const char * pcmk_strerror(int rc)
Definition: results.c:188
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:157
PCMK_LRM_OP_INVALID
@ PCMK_LRM_OP_INVALID
Definition: services.h:130
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
XML_LRM_ATTR_INTERVAL
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:254
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:242
did_rsc_op_fail
gboolean did_rsc_op_fail(lrmd_event_data_t *op, int target_rc)
Definition: operations.c:343
XML_ATTR_CRM_VERSION
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:79
xml.h
Wrappers for and extensions to libxml2.
PCMK_LRM_OP_TIMEOUT
@ PCMK_LRM_OP_TIMEOUT
Definition: services.h:123
XML_ATTR_OP
#define XML_ATTR_OP
Definition: msg_xml.h:101
lrmd_event_data_s::user_data
const char * user_data
Definition: lrmd.h:207
XML_ATTR_ID
#define XML_ATTR_ID
Definition: msg_xml.h:96
PCMK_LRM_OP_NOTSUPPORTED
@ PCMK_LRM_OP_NOTSUPPORTED
Definition: services.h:124
pcmk_ra_cap_params
@ pcmk_ra_cap_params
Definition: util.h:147
CRM_META
#define CRM_META
Definition: crm.h:72
crm_xml_set_id
void crm_xml_set_id(xmlNode *xml, const char *format,...) __attribute__((__format__(__printf__
CRMD_ACTION_MIGRATED
#define CRMD_ACTION_MIGRATED
Definition: crm.h:170
CRM_OP_FMT
#define CRM_OP_FMT
Definition: crm_internal.h:133
lrmd_event_data_s
Definition: lrmd.h:198
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
PCMK_LRM_OP_PENDING
@ PCMK_LRM_OP_PENDING
Definition: services.h:120
CRMD_ACTION_START
#define CRMD_ACTION_START
Definition: crm.h:172
DIMOF
#define DIMOF(a)
Definition: crm.h:58
CRMD_ACTION_MIGRATE
#define CRMD_ACTION_MIGRATE
Definition: crm.h:169
lrmd_event_data_s::op_status
int op_status
Definition: lrmd.h:223
crm_xml_add
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:313
lrmd.h
Resource agent executor.
generate_transition_key
char * generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: operations.c:194
filter_action_parameters
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: operations.c:263
CRMD_ACTION_RELOAD
#define CRMD_ACTION_RELOAD
Definition: crm.h:168
XML_LRM_ATTR_OP_DIGEST
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:273
rsc_op_expected_rc
int rsc_op_expected_rc(lrmd_event_data_t *op)
Definition: operations.c:332
xml_remove_prop
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3325
op_status
op_status
Definition: services.h:118
parse_op_key
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:47
crm_element_value_copy
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:709
XML_LRM_ATTR_TARGET
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:262
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
CRMD_ACTION_DEMOTE
#define CRMD_ACTION_DEMOTE
Definition: crm.h:180
CRMD_ACTION_STATUS
#define CRMD_ACTION_STATUS
Definition: crm.h:186
XML_LRM_ATTR_INTERVAL_MS
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:258
version
uint32_t version
Definition: remote.c:3
generate_op_key
char * generate_op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key.
Definition: operations.c:39
decode_transition_key
gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
Parse a transition key into its constituent parts.
Definition: operations.c:215
XML_ATTR_TIMEOUT
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:90
pcmk_get_ra_caps
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
strndup
char * strndup(const char *str, size_t len)
decode_transition_magic
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Parse a transition magic string into its constituent parts.
Definition: operations.c:153
crm_internal.h
util.h
Utility functions.
crm.h
A dumping ground.
crm_meta_name
char * crm_meta_name(const char *field)
Definition: utils.c:742
CRMD_ACTION_PROMOTE
#define CRMD_ACTION_PROMOTE
Definition: crm.h:178
generate_notify_key
char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:128