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