This source file includes following definitions.
- pcmk__action_text
- pcmk__parse_action
- pcmk__on_fail_text
- pcmk__free_action
- pcmk__op_key
- convert_interval
- match_before
- parse_op_key
- pcmk__notify_key
- decode_transition_magic
- pcmk__transition_key
- decode_transition_key
- rsc_op_expected_rc
- did_rsc_op_fail
- crm_create_op_xml
- crm_op_needs_metadata
- pcmk__is_fencing_action
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <ctype.h>
17
18 #include <crm/crm.h>
19 #include <crm/lrmd.h>
20 #include <crm/common/xml.h>
21 #include <crm/common/xml_internal.h>
22 #include <crm/common/util.h>
23 #include <crm/common/scheduler.h>
24
25
26
27
28
29
30
31
32
33 const char *
34 pcmk__action_text(enum pcmk__action_type action)
35 {
36 switch (action) {
37 case pcmk__action_stop:
38 return PCMK_ACTION_STOP;
39
40 case pcmk__action_stopped:
41 return PCMK_ACTION_STOPPED;
42
43 case pcmk__action_start:
44 return PCMK_ACTION_START;
45
46 case pcmk__action_started:
47 return PCMK_ACTION_RUNNING;
48
49 case pcmk__action_shutdown:
50 return PCMK_ACTION_DO_SHUTDOWN;
51
52 case pcmk__action_fence:
53 return PCMK_ACTION_STONITH;
54
55 case pcmk__action_monitor:
56 return PCMK_ACTION_MONITOR;
57
58 case pcmk__action_notify:
59 return PCMK_ACTION_NOTIFY;
60
61 case pcmk__action_notified:
62 return PCMK_ACTION_NOTIFIED;
63
64 case pcmk__action_promote:
65 return PCMK_ACTION_PROMOTE;
66
67 case pcmk__action_promoted:
68 return PCMK_ACTION_PROMOTED;
69
70 case pcmk__action_demote:
71 return PCMK_ACTION_DEMOTE;
72
73 case pcmk__action_demoted:
74 return PCMK_ACTION_DEMOTED;
75
76 default:
77 return "no_action";
78 }
79 }
80
81
82
83
84
85
86
87
88
89 enum pcmk__action_type
90 pcmk__parse_action(const char *action_name)
91 {
92 if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)) {
93 return pcmk__action_stop;
94
95 } else if (pcmk__str_eq(action_name, PCMK_ACTION_STOPPED, pcmk__str_none)) {
96 return pcmk__action_stopped;
97
98 } else if (pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)) {
99 return pcmk__action_start;
100
101 } else if (pcmk__str_eq(action_name, PCMK_ACTION_RUNNING, pcmk__str_none)) {
102 return pcmk__action_started;
103
104 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DO_SHUTDOWN,
105 pcmk__str_none)) {
106 return pcmk__action_shutdown;
107
108 } else if (pcmk__str_eq(action_name, PCMK_ACTION_STONITH, pcmk__str_none)) {
109 return pcmk__action_fence;
110
111 } else if (pcmk__str_eq(action_name, PCMK_ACTION_MONITOR, pcmk__str_none)) {
112 return pcmk__action_monitor;
113
114 } else if (pcmk__str_eq(action_name, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
115 return pcmk__action_notify;
116
117 } else if (pcmk__str_eq(action_name, PCMK_ACTION_NOTIFIED,
118 pcmk__str_none)) {
119 return pcmk__action_notified;
120
121 } else if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
122 return pcmk__action_promote;
123
124 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
125 return pcmk__action_demote;
126
127 } else if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTED,
128 pcmk__str_none)) {
129 return pcmk__action_promoted;
130
131 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTED, pcmk__str_none)) {
132 return pcmk__action_demoted;
133 }
134 return pcmk__action_unspecified;
135 }
136
137
138
139
140
141
142
143
144
145 const char *
146 pcmk__on_fail_text(enum pcmk__on_fail on_fail)
147 {
148 switch (on_fail) {
149 case pcmk__on_fail_ignore:
150 return "ignore";
151
152 case pcmk__on_fail_demote:
153 return "demote";
154
155 case pcmk__on_fail_block:
156 return "block";
157
158 case pcmk__on_fail_restart:
159 return "recover";
160
161 case pcmk__on_fail_ban:
162 return "migrate";
163
164 case pcmk__on_fail_stop:
165 return "stop";
166
167 case pcmk__on_fail_fence_node:
168 return "fence";
169
170 case pcmk__on_fail_standby_node:
171 return "standby";
172
173 case pcmk__on_fail_restart_container:
174 return "restart-container";
175
176 case pcmk__on_fail_reset_remote:
177 return "reset-remote";
178 }
179 return "<unknown>";
180 }
181
182
183
184
185
186
187
188 void
189 pcmk__free_action(gpointer user_data)
190 {
191 pcmk_action_t *action = user_data;
192
193 if (action == NULL) {
194 return;
195 }
196 g_list_free_full(action->actions_before, free);
197 g_list_free_full(action->actions_after, free);
198 if (action->extra != NULL) {
199 g_hash_table_destroy(action->extra);
200 }
201 if (action->meta != NULL) {
202 g_hash_table_destroy(action->meta);
203 }
204 pcmk__free_node_copy(action->node);
205 free(action->cancel_task);
206 free(action->reason);
207 free(action->task);
208 free(action->uuid);
209 free(action);
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224 char *
225 pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
226 {
227 pcmk__assert((rsc_id != NULL) && (op_type != NULL));
228 return crm_strdup_printf(PCMK__OP_FMT, rsc_id, op_type, interval_ms);
229 }
230
231 static inline gboolean
232 convert_interval(const char *s, guint *interval_ms)
233 {
234 unsigned long l;
235
236 errno = 0;
237 l = strtoul(s, NULL, 10);
238
239 if (errno != 0) {
240 return FALSE;
241 }
242
243 *interval_ms = (guint) l;
244 return TRUE;
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258 static size_t
259 match_before(const char *key, size_t position, const char **matches)
260 {
261 for (int i = 0; matches[i] != NULL; ++i) {
262 const size_t match_len = strlen(matches[i]);
263
264
265 if (position > (match_len + 1)) {
266 const size_t possible = position - match_len - 1;
267
268 if ((key[possible] == '_')
269 && (strncmp(key + possible + 1, matches[i], match_len) == 0)) {
270 return possible;
271 }
272 }
273 }
274 return 0;
275 }
276
277 gboolean
278 parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
279 {
280 guint local_interval_ms = 0;
281 const size_t key_len = (key == NULL)? 0 : strlen(key);
282
283
284 size_t action_underbar = 0;
285 size_t interval_underbar = 0;
286 size_t possible = 0;
287
288
289
290
291 const char *actions_with_underbars[] = {
292 PCMK_ACTION_MIGRATE_FROM,
293 PCMK_ACTION_MIGRATE_TO,
294 NULL
295 };
296 const char *action_prefixes_with_underbars[] = {
297 "pre_" PCMK_ACTION_NOTIFY,
298 "post_" PCMK_ACTION_NOTIFY,
299 "confirmed-pre_" PCMK_ACTION_NOTIFY,
300 "confirmed-post_" PCMK_ACTION_NOTIFY,
301 NULL,
302 };
303
304
305 if (rsc_id) {
306 *rsc_id = NULL;
307 }
308 if (op_type) {
309 *op_type = NULL;
310 }
311 if (interval_ms) {
312 *interval_ms = 0;
313 }
314
315
316 if (key_len < 5) {
317 return FALSE;
318 }
319
320
321 interval_underbar = key_len - 2;
322 while ((interval_underbar > 2) && (key[interval_underbar] != '_')) {
323 --interval_underbar;
324 }
325 if ((interval_underbar == 2)
326 || !convert_interval(key + interval_underbar + 1, &local_interval_ms)) {
327 return FALSE;
328 }
329
330
331 action_underbar = match_before(key, interval_underbar,
332 actions_with_underbars);
333 if (action_underbar == 0) {
334 action_underbar = interval_underbar - 2;
335 while ((action_underbar > 0) && (key[action_underbar] != '_')) {
336 --action_underbar;
337 }
338 if (action_underbar == 0) {
339 return FALSE;
340 }
341 }
342 possible = match_before(key, action_underbar,
343 action_prefixes_with_underbars);
344 if (possible != 0) {
345 action_underbar = possible;
346 }
347
348
349 if (rsc_id != NULL) {
350 *rsc_id = strndup(key, action_underbar);
351 pcmk__mem_assert(*rsc_id);
352 }
353 if (op_type != NULL) {
354 *op_type = strndup(key + action_underbar + 1,
355 interval_underbar - action_underbar - 1);
356 pcmk__mem_assert(*op_type);
357 }
358 if (interval_ms != NULL) {
359 *interval_ms = local_interval_ms;
360 }
361 return TRUE;
362 }
363
364 char *
365 pcmk__notify_key(const char *rsc_id, const char *notify_type,
366 const char *op_type)
367 {
368 CRM_CHECK(rsc_id != NULL, return NULL);
369 CRM_CHECK(op_type != NULL, return NULL);
370 CRM_CHECK(notify_type != NULL, return NULL);
371 return crm_strdup_printf("%s_%s_notify_%s_0",
372 rsc_id, notify_type, op_type);
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390 gboolean
391 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
392 int *op_status, int *op_rc, int *target_rc)
393 {
394 int res = 0;
395 char *key = NULL;
396 gboolean result = TRUE;
397 int local_op_status = -1;
398 int local_op_rc = -1;
399
400 CRM_CHECK(magic != NULL, return FALSE);
401
402 #ifdef HAVE_SSCANF_M
403 res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
404 #else
405
406 key = pcmk__assert_alloc(1, strlen(magic) - 3);
407 res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
408 #endif
409 if (res == EOF) {
410 crm_err("Could not decode transition information '%s': %s",
411 magic, pcmk_rc_str(errno));
412 result = FALSE;
413 } else if (res < 3) {
414 crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
415 magic, res);
416 result = FALSE;
417 } else {
418 if (op_status) {
419 *op_status = local_op_status;
420 }
421 if (op_rc) {
422 *op_rc = local_op_rc;
423 }
424 result = decode_transition_key(key, uuid, transition_id, action_id,
425 target_rc);
426 }
427 free(key);
428 return result;
429 }
430
431 char *
432 pcmk__transition_key(int transition_id, int action_id, int target_rc,
433 const char *node)
434 {
435 CRM_CHECK(node != NULL, return NULL);
436 return crm_strdup_printf("%d:%d:%d:%-*s",
437 action_id, transition_id, target_rc, 36, node);
438 }
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453 gboolean
454 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
455 int *target_rc)
456 {
457 int local_transition_id = -1;
458 int local_action_id = -1;
459 int local_target_rc = -1;
460 char local_uuid[37] = { '\0' };
461
462
463 if (uuid) {
464 *uuid = NULL;
465 }
466 if (transition_id) {
467 *transition_id = -1;
468 }
469 if (action_id) {
470 *action_id = -1;
471 }
472 if (target_rc) {
473 *target_rc = -1;
474 }
475
476 CRM_CHECK(key != NULL, return FALSE);
477 if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
478 &local_target_rc, local_uuid) != 4) {
479 crm_err("Invalid transition key '%s'", key);
480 return FALSE;
481 }
482 if (strlen(local_uuid) != 36) {
483 crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
484 }
485 if (uuid) {
486 *uuid = pcmk__str_copy(local_uuid);
487 }
488 if (transition_id) {
489 *transition_id = local_transition_id;
490 }
491 if (action_id) {
492 *action_id = local_action_id;
493 }
494 if (target_rc) {
495 *target_rc = local_target_rc;
496 }
497 return TRUE;
498 }
499
500 int
501 rsc_op_expected_rc(const lrmd_event_data_t *op)
502 {
503 int rc = 0;
504
505 if (op && op->user_data) {
506 decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
507 }
508 return rc;
509 }
510
511 gboolean
512 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
513 {
514 switch (op->op_status) {
515 case PCMK_EXEC_CANCELLED:
516 case PCMK_EXEC_PENDING:
517 return FALSE;
518
519 case PCMK_EXEC_NOT_SUPPORTED:
520 case PCMK_EXEC_TIMEOUT:
521 case PCMK_EXEC_ERROR:
522 case PCMK_EXEC_NOT_CONNECTED:
523 case PCMK_EXEC_NO_FENCE_DEVICE:
524 case PCMK_EXEC_NO_SECRETS:
525 case PCMK_EXEC_INVALID:
526 return TRUE;
527
528 default:
529 if (target_rc != op->rc) {
530 return TRUE;
531 }
532 }
533
534 return FALSE;
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548 xmlNode *
549 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
550 const char *interval_spec, const char *timeout)
551 {
552 xmlNode *xml_op;
553
554 CRM_CHECK(prefix && task && interval_spec, return NULL);
555
556 xml_op = pcmk__xe_create(parent, PCMK_XE_OP);
557 pcmk__xe_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
558 crm_xml_add(xml_op, PCMK_META_INTERVAL, interval_spec);
559 crm_xml_add(xml_op, PCMK_XA_NAME, task);
560 if (timeout) {
561 crm_xml_add(xml_op, PCMK_META_TIMEOUT, timeout);
562 }
563 return xml_op;
564 }
565
566
567
568
569
570
571
572
573
574
575 bool
576 crm_op_needs_metadata(const char *rsc_class, const char *op)
577 {
578
579
580
581
582 CRM_CHECK((rsc_class != NULL) || (op != NULL), return false);
583
584 if ((rsc_class != NULL)
585 && !pcmk_is_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
586
587 return false;
588 }
589 if (op == NULL) {
590 return true;
591 }
592
593
594 return pcmk__str_any_of(op, PCMK_ACTION_START, PCMK_ACTION_MONITOR,
595 PCMK_ACTION_PROMOTE, PCMK_ACTION_DEMOTE,
596 PCMK_ACTION_RELOAD, PCMK_ACTION_RELOAD_AGENT,
597 PCMK_ACTION_MIGRATE_TO, PCMK_ACTION_MIGRATE_FROM,
598 PCMK_ACTION_NOTIFY, NULL);
599 }
600
601
602
603
604
605
606
607
608
609
610 bool
611 pcmk__is_fencing_action(const char *action)
612 {
613 return pcmk__str_any_of(action, PCMK_ACTION_OFF, PCMK_ACTION_REBOOT, NULL);
614 }