This source file includes following definitions.
- pcmk__op_key
- convert_interval
- match_before
- parse_op_key
- pcmk__notify_key
- decode_transition_magic
- pcmk__transition_key
- decode_transition_key
- should_filter_for_digest
- pcmk__filter_op_for_digest
- rsc_op_expected_rc
- did_rsc_op_fail
- crm_create_op_xml
- crm_op_needs_metadata
- pcmk__is_fencing_action
- pcmk_is_probe
- pcmk_xe_is_probe
- pcmk_xe_mask_probe_failure
1
2
3
4
5
6
7
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 <sys/types.h>
20 #include <ctype.h>
21
22 #include <crm/crm.h>
23 #include <crm/lrmd.h>
24 #include <crm/msg_xml.h>
25 #include <crm/common/xml.h>
26 #include <crm/common/xml_internal.h>
27 #include <crm/common/util.h>
28
29
30
31
32
33
34
35
36
37
38
39
40
41 char *
42 pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
43 {
44 CRM_ASSERT(rsc_id != NULL);
45 CRM_ASSERT(op_type != NULL);
46 return crm_strdup_printf(PCMK__OP_FMT, rsc_id, op_type, interval_ms);
47 }
48
49 static inline gboolean
50 convert_interval(const char *s, guint *interval_ms)
51 {
52 unsigned long l;
53
54 errno = 0;
55 l = strtoul(s, NULL, 10);
56
57 if (errno != 0) {
58 return FALSE;
59 }
60
61 *interval_ms = (guint) l;
62 return TRUE;
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76 static size_t
77 match_before(const char *key, size_t position, const char **matches)
78 {
79 for (int i = 0; matches[i] != NULL; ++i) {
80 const size_t match_len = strlen(matches[i]);
81
82
83 if (position > (match_len + 1)) {
84 const size_t possible = position - match_len - 1;
85
86 if ((key[possible] == '_')
87 && (strncmp(key + possible + 1, matches[i], match_len) == 0)) {
88 return possible;
89 }
90 }
91 }
92 return 0;
93 }
94
95 gboolean
96 parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
97 {
98 guint local_interval_ms = 0;
99 const size_t key_len = (key == NULL)? 0 : strlen(key);
100
101
102 size_t action_underbar = 0;
103 size_t interval_underbar = 0;
104 size_t possible = 0;
105
106
107
108
109 const char *actions_with_underbars[] = {
110 PCMK_ACTION_MIGRATE_FROM,
111 PCMK_ACTION_MIGRATE_TO,
112 NULL
113 };
114 const char *action_prefixes_with_underbars[] = {
115 "pre_" PCMK_ACTION_NOTIFY,
116 "post_" PCMK_ACTION_NOTIFY,
117 "confirmed-pre_" PCMK_ACTION_NOTIFY,
118 "confirmed-post_" PCMK_ACTION_NOTIFY,
119 NULL,
120 };
121
122
123 if (rsc_id) {
124 *rsc_id = NULL;
125 }
126 if (op_type) {
127 *op_type = NULL;
128 }
129 if (interval_ms) {
130 *interval_ms = 0;
131 }
132
133
134 if (key_len < 5) {
135 return FALSE;
136 }
137
138
139 interval_underbar = key_len - 2;
140 while ((interval_underbar > 2) && (key[interval_underbar] != '_')) {
141 --interval_underbar;
142 }
143 if ((interval_underbar == 2)
144 || !convert_interval(key + interval_underbar + 1, &local_interval_ms)) {
145 return FALSE;
146 }
147
148
149 action_underbar = match_before(key, interval_underbar,
150 actions_with_underbars);
151 if (action_underbar == 0) {
152 action_underbar = interval_underbar - 2;
153 while ((action_underbar > 0) && (key[action_underbar] != '_')) {
154 --action_underbar;
155 }
156 if (action_underbar == 0) {
157 return FALSE;
158 }
159 }
160 possible = match_before(key, action_underbar,
161 action_prefixes_with_underbars);
162 if (possible != 0) {
163 action_underbar = possible;
164 }
165
166
167 if (rsc_id != NULL) {
168 *rsc_id = strndup(key, action_underbar);
169 CRM_ASSERT(*rsc_id != NULL);
170 }
171 if (op_type != NULL) {
172 *op_type = strndup(key + action_underbar + 1,
173 interval_underbar - action_underbar - 1);
174 CRM_ASSERT(*op_type != NULL);
175 }
176 if (interval_ms != NULL) {
177 *interval_ms = local_interval_ms;
178 }
179 return TRUE;
180 }
181
182 char *
183 pcmk__notify_key(const char *rsc_id, const char *notify_type,
184 const char *op_type)
185 {
186 CRM_CHECK(rsc_id != NULL, return NULL);
187 CRM_CHECK(op_type != NULL, return NULL);
188 CRM_CHECK(notify_type != NULL, return NULL);
189 return crm_strdup_printf("%s_%s_notify_%s_0",
190 rsc_id, notify_type, op_type);
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 gboolean
209 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
210 int *op_status, int *op_rc, int *target_rc)
211 {
212 int res = 0;
213 char *key = NULL;
214 gboolean result = TRUE;
215 int local_op_status = -1;
216 int local_op_rc = -1;
217
218 CRM_CHECK(magic != NULL, return FALSE);
219
220 #ifdef HAVE_SSCANF_M
221 res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
222 #else
223 key = calloc(1, strlen(magic) - 3);
224 CRM_ASSERT(key);
225 res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
226 #endif
227 if (res == EOF) {
228 crm_err("Could not decode transition information '%s': %s",
229 magic, pcmk_rc_str(errno));
230 result = FALSE;
231 } else if (res < 3) {
232 crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
233 magic, res);
234 result = FALSE;
235 } else {
236 if (op_status) {
237 *op_status = local_op_status;
238 }
239 if (op_rc) {
240 *op_rc = local_op_rc;
241 }
242 result = decode_transition_key(key, uuid, transition_id, action_id,
243 target_rc);
244 }
245 free(key);
246 return result;
247 }
248
249 char *
250 pcmk__transition_key(int transition_id, int action_id, int target_rc,
251 const char *node)
252 {
253 CRM_CHECK(node != NULL, return NULL);
254 return crm_strdup_printf("%d:%d:%d:%-*s",
255 action_id, transition_id, target_rc, 36, node);
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271 gboolean
272 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
273 int *target_rc)
274 {
275 int local_transition_id = -1;
276 int local_action_id = -1;
277 int local_target_rc = -1;
278 char local_uuid[37] = { '\0' };
279
280
281 if (uuid) {
282 *uuid = NULL;
283 }
284 if (transition_id) {
285 *transition_id = -1;
286 }
287 if (action_id) {
288 *action_id = -1;
289 }
290 if (target_rc) {
291 *target_rc = -1;
292 }
293
294 CRM_CHECK(key != NULL, return FALSE);
295 if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
296 &local_target_rc, local_uuid) != 4) {
297 crm_err("Invalid transition key '%s'", key);
298 return FALSE;
299 }
300 if (strlen(local_uuid) != 36) {
301 crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
302 }
303 if (uuid) {
304 *uuid = strdup(local_uuid);
305 CRM_ASSERT(*uuid);
306 }
307 if (transition_id) {
308 *transition_id = local_transition_id;
309 }
310 if (action_id) {
311 *action_id = local_action_id;
312 }
313 if (target_rc) {
314 *target_rc = local_target_rc;
315 }
316 return TRUE;
317 }
318
319
320 static bool
321 should_filter_for_digest(xmlAttrPtr a, void *user_data)
322 {
323 if (strncmp((const char *) a->name, CRM_META "_",
324 sizeof(CRM_META " ") - 1) == 0) {
325 return true;
326 }
327 return pcmk__str_any_of((const char *) a->name,
328 XML_ATTR_ID,
329 XML_ATTR_CRM_VERSION,
330 XML_LRM_ATTR_OP_DIGEST,
331 XML_LRM_ATTR_TARGET,
332 XML_LRM_ATTR_TARGET_UUID,
333 "pcmk_external_ip",
334 NULL);
335 }
336
337
338
339
340
341
342
343 void
344 pcmk__filter_op_for_digest(xmlNode *param_set)
345 {
346 char *key = NULL;
347 char *timeout = NULL;
348 guint interval_ms = 0;
349
350 if (param_set == NULL) {
351 return;
352 }
353
354
355
356
357 key = crm_meta_name(XML_LRM_ATTR_INTERVAL_MS);
358 if (crm_element_value_ms(param_set, key, &interval_ms) != pcmk_ok) {
359 interval_ms = 0;
360 }
361 free(key);
362 key = NULL;
363 if (interval_ms != 0) {
364 key = crm_meta_name(XML_ATTR_TIMEOUT);
365 timeout = crm_element_value_copy(param_set, key);
366 }
367
368
369 pcmk__xe_remove_matching_attrs(param_set, should_filter_for_digest, NULL);
370
371
372 if (timeout != NULL) {
373 crm_xml_add(param_set, key, timeout);
374 }
375 free(timeout);
376 free(key);
377 }
378
379 int
380 rsc_op_expected_rc(const lrmd_event_data_t *op)
381 {
382 int rc = 0;
383
384 if (op && op->user_data) {
385 decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
386 }
387 return rc;
388 }
389
390 gboolean
391 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
392 {
393 switch (op->op_status) {
394 case PCMK_EXEC_CANCELLED:
395 case PCMK_EXEC_PENDING:
396 return FALSE;
397
398 case PCMK_EXEC_NOT_SUPPORTED:
399 case PCMK_EXEC_TIMEOUT:
400 case PCMK_EXEC_ERROR:
401 case PCMK_EXEC_NOT_CONNECTED:
402 case PCMK_EXEC_NO_FENCE_DEVICE:
403 case PCMK_EXEC_NO_SECRETS:
404 case PCMK_EXEC_INVALID:
405 return TRUE;
406
407 default:
408 if (target_rc != op->rc) {
409 return TRUE;
410 }
411 }
412
413 return FALSE;
414 }
415
416
417
418
419
420
421
422
423
424
425
426
427 xmlNode *
428 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
429 const char *interval_spec, const char *timeout)
430 {
431 xmlNode *xml_op;
432
433 CRM_CHECK(prefix && task && interval_spec, return NULL);
434
435 xml_op = create_xml_node(parent, XML_ATTR_OP);
436 crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
437 crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval_spec);
438 crm_xml_add(xml_op, "name", task);
439 if (timeout) {
440 crm_xml_add(xml_op, XML_ATTR_TIMEOUT, timeout);
441 }
442 return xml_op;
443 }
444
445
446
447
448
449
450
451
452
453
454 bool
455 crm_op_needs_metadata(const char *rsc_class, const char *op)
456 {
457
458
459
460
461 CRM_CHECK((rsc_class != NULL) || (op != NULL), return false);
462
463 if ((rsc_class != NULL)
464 && !pcmk_is_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
465
466 return false;
467 }
468 if (op == NULL) {
469 return true;
470 }
471
472
473 return pcmk__str_any_of(op, PCMK_ACTION_START, PCMK_ACTION_MONITOR,
474 PCMK_ACTION_PROMOTE, PCMK_ACTION_DEMOTE,
475 PCMK_ACTION_RELOAD, PCMK_ACTION_RELOAD_AGENT,
476 PCMK_ACTION_MIGRATE_TO, PCMK_ACTION_MIGRATE_FROM,
477 PCMK_ACTION_NOTIFY, NULL);
478 }
479
480
481
482
483
484
485
486
487
488 bool
489 pcmk__is_fencing_action(const char *action)
490 {
491 return pcmk__str_any_of(action, PCMK_ACTION_OFF, PCMK_ACTION_REBOOT,
492 "poweroff", NULL);
493 }
494
495 bool
496 pcmk_is_probe(const char *task, guint interval)
497 {
498 if (task == NULL) {
499 return false;
500 }
501
502 return (interval == 0)
503 && pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_none);
504 }
505
506 bool
507 pcmk_xe_is_probe(const xmlNode *xml_op)
508 {
509 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
510 const char *interval_ms_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL_MS);
511 int interval_ms;
512
513 pcmk__scan_min_int(interval_ms_s, &interval_ms, 0);
514 return pcmk_is_probe(task, interval_ms);
515 }
516
517 bool
518 pcmk_xe_mask_probe_failure(const xmlNode *xml_op)
519 {
520 int status = PCMK_EXEC_UNKNOWN;
521 int rc = PCMK_OCF_OK;
522
523 if (!pcmk_xe_is_probe(xml_op)) {
524 return false;
525 }
526
527 crm_element_value_int(xml_op, XML_LRM_ATTR_OPSTATUS, &status);
528 crm_element_value_int(xml_op, XML_LRM_ATTR_RC, &rc);
529
530 return rc == PCMK_OCF_NOT_INSTALLED || rc == PCMK_OCF_INVALID_PARAM ||
531 status == PCMK_EXEC_NOT_INSTALLED;
532 }