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 pcmk__assert((rsc_id != NULL) && (op_type != NULL));
199 return crm_strdup_printf(PCMK__OP_FMT, rsc_id, op_type, interval_ms);
200 }
201
202 static inline gboolean
203 convert_interval(const char *s, guint *interval_ms)
204 {
205 unsigned long l;
206
207 errno = 0;
208 l = strtoul(s, NULL, 10);
209
210 if (errno != 0) {
211 return FALSE;
212 }
213
214 *interval_ms = (guint) l;
215 return TRUE;
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229 static size_t
230 match_before(const char *key, size_t position, const char **matches)
231 {
232 for (int i = 0; matches[i] != NULL; ++i) {
233 const size_t match_len = strlen(matches[i]);
234
235
236 if (position > (match_len + 1)) {
237 const size_t possible = position - match_len - 1;
238
239 if ((key[possible] == '_')
240 && (strncmp(key + possible + 1, matches[i], match_len) == 0)) {
241 return possible;
242 }
243 }
244 }
245 return 0;
246 }
247
248 gboolean
249 parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
250 {
251 guint local_interval_ms = 0;
252 const size_t key_len = (key == NULL)? 0 : strlen(key);
253
254
255 size_t action_underbar = 0;
256 size_t interval_underbar = 0;
257 size_t possible = 0;
258
259
260
261
262 const char *actions_with_underbars[] = {
263 PCMK_ACTION_MIGRATE_FROM,
264 PCMK_ACTION_MIGRATE_TO,
265 NULL
266 };
267 const char *action_prefixes_with_underbars[] = {
268 "pre_" PCMK_ACTION_NOTIFY,
269 "post_" PCMK_ACTION_NOTIFY,
270 "confirmed-pre_" PCMK_ACTION_NOTIFY,
271 "confirmed-post_" PCMK_ACTION_NOTIFY,
272 NULL,
273 };
274
275
276 if (rsc_id) {
277 *rsc_id = NULL;
278 }
279 if (op_type) {
280 *op_type = NULL;
281 }
282 if (interval_ms) {
283 *interval_ms = 0;
284 }
285
286
287 if (key_len < 5) {
288 return FALSE;
289 }
290
291
292 interval_underbar = key_len - 2;
293 while ((interval_underbar > 2) && (key[interval_underbar] != '_')) {
294 --interval_underbar;
295 }
296 if ((interval_underbar == 2)
297 || !convert_interval(key + interval_underbar + 1, &local_interval_ms)) {
298 return FALSE;
299 }
300
301
302 action_underbar = match_before(key, interval_underbar,
303 actions_with_underbars);
304 if (action_underbar == 0) {
305 action_underbar = interval_underbar - 2;
306 while ((action_underbar > 0) && (key[action_underbar] != '_')) {
307 --action_underbar;
308 }
309 if (action_underbar == 0) {
310 return FALSE;
311 }
312 }
313 possible = match_before(key, action_underbar,
314 action_prefixes_with_underbars);
315 if (possible != 0) {
316 action_underbar = possible;
317 }
318
319
320 if (rsc_id != NULL) {
321 *rsc_id = strndup(key, action_underbar);
322 pcmk__mem_assert(*rsc_id);
323 }
324 if (op_type != NULL) {
325 *op_type = strndup(key + action_underbar + 1,
326 interval_underbar - action_underbar - 1);
327 pcmk__mem_assert(*op_type);
328 }
329 if (interval_ms != NULL) {
330 *interval_ms = local_interval_ms;
331 }
332 return TRUE;
333 }
334
335 char *
336 pcmk__notify_key(const char *rsc_id, const char *notify_type,
337 const char *op_type)
338 {
339 CRM_CHECK(rsc_id != NULL, return NULL);
340 CRM_CHECK(op_type != NULL, return NULL);
341 CRM_CHECK(notify_type != NULL, return NULL);
342 return crm_strdup_printf("%s_%s_notify_%s_0",
343 rsc_id, notify_type, op_type);
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 gboolean
362 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
363 int *op_status, int *op_rc, int *target_rc)
364 {
365 int res = 0;
366 char *key = NULL;
367 gboolean result = TRUE;
368 int local_op_status = -1;
369 int local_op_rc = -1;
370
371 CRM_CHECK(magic != NULL, return FALSE);
372
373 #ifdef HAVE_SSCANF_M
374 res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
375 #else
376
377 key = pcmk__assert_alloc(1, strlen(magic) - 3);
378 res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
379 #endif
380 if (res == EOF) {
381 crm_err("Could not decode transition information '%s': %s",
382 magic, pcmk_rc_str(errno));
383 result = FALSE;
384 } else if (res < 3) {
385 crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
386 magic, res);
387 result = FALSE;
388 } else {
389 if (op_status) {
390 *op_status = local_op_status;
391 }
392 if (op_rc) {
393 *op_rc = local_op_rc;
394 }
395 result = decode_transition_key(key, uuid, transition_id, action_id,
396 target_rc);
397 }
398 free(key);
399 return result;
400 }
401
402 char *
403 pcmk__transition_key(int transition_id, int action_id, int target_rc,
404 const char *node)
405 {
406 CRM_CHECK(node != NULL, return NULL);
407 return crm_strdup_printf("%d:%d:%d:%-*s",
408 action_id, transition_id, target_rc, 36, node);
409 }
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 gboolean
425 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
426 int *target_rc)
427 {
428 int local_transition_id = -1;
429 int local_action_id = -1;
430 int local_target_rc = -1;
431 char local_uuid[37] = { '\0' };
432
433
434 if (uuid) {
435 *uuid = NULL;
436 }
437 if (transition_id) {
438 *transition_id = -1;
439 }
440 if (action_id) {
441 *action_id = -1;
442 }
443 if (target_rc) {
444 *target_rc = -1;
445 }
446
447 CRM_CHECK(key != NULL, return FALSE);
448 if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
449 &local_target_rc, local_uuid) != 4) {
450 crm_err("Invalid transition key '%s'", key);
451 return FALSE;
452 }
453 if (strlen(local_uuid) != 36) {
454 crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
455 }
456 if (uuid) {
457 *uuid = pcmk__str_copy(local_uuid);
458 }
459 if (transition_id) {
460 *transition_id = local_transition_id;
461 }
462 if (action_id) {
463 *action_id = local_action_id;
464 }
465 if (target_rc) {
466 *target_rc = local_target_rc;
467 }
468 return TRUE;
469 }
470
471 int
472 rsc_op_expected_rc(const lrmd_event_data_t *op)
473 {
474 int rc = 0;
475
476 if (op && op->user_data) {
477 decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
478 }
479 return rc;
480 }
481
482 gboolean
483 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
484 {
485 switch (op->op_status) {
486 case PCMK_EXEC_CANCELLED:
487 case PCMK_EXEC_PENDING:
488 return FALSE;
489
490 case PCMK_EXEC_NOT_SUPPORTED:
491 case PCMK_EXEC_TIMEOUT:
492 case PCMK_EXEC_ERROR:
493 case PCMK_EXEC_NOT_CONNECTED:
494 case PCMK_EXEC_NO_FENCE_DEVICE:
495 case PCMK_EXEC_NO_SECRETS:
496 case PCMK_EXEC_INVALID:
497 return TRUE;
498
499 default:
500 if (target_rc != op->rc) {
501 return TRUE;
502 }
503 }
504
505 return FALSE;
506 }
507
508
509
510
511
512
513
514
515
516
517
518
519 xmlNode *
520 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
521 const char *interval_spec, const char *timeout)
522 {
523 xmlNode *xml_op;
524
525 CRM_CHECK(prefix && task && interval_spec, return NULL);
526
527 xml_op = pcmk__xe_create(parent, PCMK_XE_OP);
528 crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
529 crm_xml_add(xml_op, PCMK_META_INTERVAL, interval_spec);
530 crm_xml_add(xml_op, PCMK_XA_NAME, task);
531 if (timeout) {
532 crm_xml_add(xml_op, PCMK_META_TIMEOUT, timeout);
533 }
534 return xml_op;
535 }
536
537
538
539
540
541
542
543
544
545
546 bool
547 crm_op_needs_metadata(const char *rsc_class, const char *op)
548 {
549
550
551
552
553 CRM_CHECK((rsc_class != NULL) || (op != NULL), return false);
554
555 if ((rsc_class != NULL)
556 && !pcmk_is_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
557
558 return false;
559 }
560 if (op == NULL) {
561 return true;
562 }
563
564
565 return pcmk__str_any_of(op, PCMK_ACTION_START, PCMK_ACTION_MONITOR,
566 PCMK_ACTION_PROMOTE, PCMK_ACTION_DEMOTE,
567 PCMK_ACTION_RELOAD, PCMK_ACTION_RELOAD_AGENT,
568 PCMK_ACTION_MIGRATE_TO, PCMK_ACTION_MIGRATE_FROM,
569 PCMK_ACTION_NOTIFY, NULL);
570 }
571
572
573
574
575
576
577
578
579
580
581 bool
582 pcmk__is_fencing_action(const char *action)
583 {
584 return pcmk__str_any_of(action, PCMK_ACTION_OFF, PCMK_ACTION_REBOOT,
585 PCMK__ACTION_POWEROFF, NULL);
586 }