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