This source file includes following definitions.
- add_singleton
- lookup_singleton
- find_existing_action
- find_exact_action_config
- pcmk__find_action_config
- new_action
- pcmk__unpack_action_rsc_params
- update_action_optional
- effective_quorum_policy
- update_resource_action_runnable
- update_resource_flags_for_action
- valid_stop_on_fail
- validate_on_fail
- unpack_timeout
- unpack_interval_origin
- unpack_start_delay
- most_frequent_monitor
- pcmk__unpack_action_meta
- pcmk__action_requires
- pcmk__parse_on_fail
- pcmk__role_after_failure
- unpack_operation
- custom_action
- get_pseudo_op
- find_unfencing_devices
- node_priority_fencing_delay
- pe_fence_op
- pe_free_action
- pe_get_configured_timeout
- get_complex_task
- find_first_action
- find_actions
- find_actions_exact
- pe__resource_actions
- pe__action2reason
- pe_action_set_reason
- pe__clear_resource_history
- pe__is_newer_op
- sort_op_by_callid
- pe__new_rsc_pseudo_action
- pe__add_action_expected_result
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <stdbool.h>
14
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/common/scheduler_internal.h>
18 #include <crm/pengine/internal.h>
19 #include <crm/common/xml_internal.h>
20 #include "pe_status_private.h"
21
22 static void unpack_operation(pcmk_action_t *action, const xmlNode *xml_obj,
23 guint interval_ms);
24
25 static void
26 add_singleton(pcmk_scheduler_t *scheduler, pcmk_action_t *action)
27 {
28 if (scheduler->singletons == NULL) {
29 scheduler->singletons = pcmk__strkey_table(NULL, NULL);
30 }
31 g_hash_table_insert(scheduler->singletons, action->uuid, action);
32 }
33
34 static pcmk_action_t *
35 lookup_singleton(pcmk_scheduler_t *scheduler, const char *action_uuid)
36 {
37 if (scheduler->singletons == NULL) {
38 return NULL;
39 }
40 return g_hash_table_lookup(scheduler->singletons, action_uuid);
41 }
42
43
44
45
46
47
48
49
50
51
52
53
54 static pcmk_action_t *
55 find_existing_action(const char *key, const pcmk_resource_t *rsc,
56 const pcmk_node_t *node, const pcmk_scheduler_t *scheduler)
57 {
58 GList *matches = NULL;
59 pcmk_action_t *action = NULL;
60
61
62
63
64 matches = find_actions(((rsc == NULL)? scheduler->actions : rsc->actions),
65 key, node);
66 if (matches == NULL) {
67 return NULL;
68 }
69 CRM_LOG_ASSERT(!pcmk__list_of_multiple(matches));
70
71 action = matches->data;
72 g_list_free(matches);
73 return action;
74 }
75
76
77
78
79
80
81
82
83
84
85
86 static xmlNode *
87 find_exact_action_config(const pcmk_resource_t *rsc, const char *action_name,
88 guint interval_ms, bool include_disabled)
89 {
90 for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
91 operation != NULL; operation = crm_next_same_xml(operation)) {
92
93 bool enabled = false;
94 const char *config_name = NULL;
95 const char *interval_spec = NULL;
96
97
98 if (!include_disabled
99 && (pcmk__xe_get_bool_attr(operation, "enabled",
100 &enabled) == pcmk_rc_ok) && !enabled) {
101 continue;
102 }
103
104 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
105 if (crm_parse_interval_spec(interval_spec) != interval_ms) {
106 continue;
107 }
108
109 config_name = crm_element_value(operation, "name");
110 if (pcmk__str_eq(action_name, config_name, pcmk__str_none)) {
111 return operation;
112 }
113 }
114 return NULL;
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128 xmlNode *
129 pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name,
130 guint interval_ms, bool include_disabled)
131 {
132 xmlNode *action_config = NULL;
133
134
135 action_config = find_exact_action_config(rsc, action_name, interval_ms,
136 include_disabled);
137
138
139
140 if ((action_config == NULL)
141 && pcmk__str_any_of(action_name, PCMK_ACTION_MIGRATE_TO,
142 PCMK_ACTION_MIGRATE_FROM, NULL)) {
143 action_config = find_exact_action_config(rsc, "migrate", 0,
144 include_disabled);
145 }
146
147 return action_config;
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 static pcmk_action_t *
166 new_action(char *key, const char *task, pcmk_resource_t *rsc,
167 const pcmk_node_t *node, bool optional, pcmk_scheduler_t *scheduler)
168 {
169 pcmk_action_t *action = calloc(1, sizeof(pcmk_action_t));
170
171 CRM_ASSERT(action != NULL);
172
173 action->rsc = rsc;
174 action->task = strdup(task); CRM_ASSERT(action->task != NULL);
175 action->uuid = key;
176
177 if (node) {
178 action->node = pe__copy_node(node);
179 }
180
181 if (pcmk__str_eq(task, PCMK_ACTION_LRM_DELETE, pcmk__str_casei)) {
182
183 pe__set_action_flags(action, pcmk_action_on_dc);
184 }
185
186 pe__set_action_flags(action, pcmk_action_runnable);
187 if (optional) {
188 pe__set_action_flags(action, pcmk_action_optional);
189 } else {
190 pe__clear_action_flags(action, pcmk_action_optional);
191 }
192
193 if (rsc == NULL) {
194 action->meta = pcmk__strkey_table(free, free);
195 } else {
196 guint interval_ms = 0;
197
198 parse_op_key(key, NULL, NULL, &interval_ms);
199 action->op_entry = pcmk__find_action_config(rsc, task, interval_ms,
200 true);
201
202
203
204
205 if ((action->op_entry == NULL) && (strstr(key, "_notify_") != NULL)) {
206 action->op_entry = find_exact_action_config(rsc, PCMK_ACTION_NOTIFY,
207 0, true);
208 }
209
210 unpack_operation(action, action->op_entry, interval_ms);
211 }
212
213 pe_rsc_trace(rsc, "Created %s action %d (%s): %s for %s on %s",
214 (optional? "optional" : "required"),
215 scheduler->action_id, key, task,
216 ((rsc == NULL)? "no resource" : rsc->id),
217 pe__node_name(node));
218 action->id = scheduler->action_id++;
219
220 scheduler->actions = g_list_prepend(scheduler->actions, action);
221 if (rsc == NULL) {
222 add_singleton(scheduler, action);
223 } else {
224 rsc->actions = g_list_prepend(rsc->actions, action);
225 }
226 return action;
227 }
228
229
230
231
232
233
234
235
236
237
238
239 GHashTable *
240 pcmk__unpack_action_rsc_params(const xmlNode *action_xml,
241 GHashTable *node_attrs,
242 pcmk_scheduler_t *scheduler)
243 {
244 GHashTable *params = pcmk__strkey_table(free, free);
245
246 pe_rule_eval_data_t rule_data = {
247 .node_hash = node_attrs,
248 .role = pcmk_role_unknown,
249 .now = scheduler->now,
250 .match_data = NULL,
251 .rsc_data = NULL,
252 .op_data = NULL
253 };
254
255 pe__unpack_dataset_nvpairs(action_xml, XML_TAG_ATTR_SETS,
256 &rule_data, params, NULL,
257 FALSE, scheduler);
258 return params;
259 }
260
261
262
263
264
265
266
267
268 static void
269 update_action_optional(pcmk_action_t *action, gboolean optional)
270 {
271
272 if ((action->rsc != NULL) && (action->node != NULL)
273 && !pcmk_is_set(action->flags, pcmk_action_pseudo)
274 && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
275 && (g_hash_table_lookup(action->meta,
276 XML_LRM_ATTR_INTERVAL_MS) == NULL)) {
277 pe_rsc_debug(action->rsc, "%s on %s is optional (%s is unmanaged)",
278 action->uuid, pe__node_name(action->node),
279 action->rsc->id);
280 pe__set_action_flags(action, pcmk_action_optional);
281
282
283
284 } else if (!optional) {
285 pe__clear_action_flags(action, pcmk_action_optional);
286 }
287 }
288
289 static enum pe_quorum_policy
290 effective_quorum_policy(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
291 {
292 enum pe_quorum_policy policy = scheduler->no_quorum_policy;
293
294 if (pcmk_is_set(scheduler->flags, pcmk_sched_quorate)) {
295 policy = pcmk_no_quorum_ignore;
296
297 } else if (scheduler->no_quorum_policy == pcmk_no_quorum_demote) {
298 switch (rsc->role) {
299 case pcmk_role_promoted:
300 case pcmk_role_unpromoted:
301 if (rsc->next_role > pcmk_role_unpromoted) {
302 pe__set_next_role(rsc, pcmk_role_unpromoted,
303 "no-quorum-policy=demote");
304 }
305 policy = pcmk_no_quorum_ignore;
306 break;
307 default:
308 policy = pcmk_no_quorum_stop;
309 break;
310 }
311 }
312 return policy;
313 }
314
315
316
317
318
319
320
321
322
323
324 static void
325 update_resource_action_runnable(pcmk_action_t *action,
326 pcmk_scheduler_t *scheduler)
327 {
328 if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
329 return;
330 }
331
332 if (action->node == NULL) {
333 pe_rsc_trace(action->rsc, "%s is unrunnable (unallocated)",
334 action->uuid);
335 pe__clear_action_flags(action, pcmk_action_runnable);
336
337 } else if (!pcmk_is_set(action->flags, pcmk_action_on_dc)
338 && !(action->node->details->online)
339 && (!pe__is_guest_node(action->node)
340 || action->node->details->remote_requires_reset)) {
341 pe__clear_action_flags(action, pcmk_action_runnable);
342 do_crm_log(LOG_WARNING, "%s on %s is unrunnable (node is offline)",
343 action->uuid, pe__node_name(action->node));
344 if (pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
345 && pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_casei)
346 && !(action->node->details->unclean)) {
347 pe_fence_node(scheduler, action->node, "stop is unrunnable", false);
348 }
349
350 } else if (!pcmk_is_set(action->flags, pcmk_action_on_dc)
351 && action->node->details->pending) {
352 pe__clear_action_flags(action, pcmk_action_runnable);
353 do_crm_log(LOG_WARNING,
354 "Action %s on %s is unrunnable (node is pending)",
355 action->uuid, pe__node_name(action->node));
356
357 } else if (action->needs == pcmk_requires_nothing) {
358 pe_action_set_reason(action, NULL, TRUE);
359 if (pe__is_guest_node(action->node)
360 && !pe_can_fence(scheduler, action->node)) {
361
362
363
364
365
366 pe_rsc_debug(action->rsc, "%s on %s is unrunnable "
367 "(node's host cannot be fenced)",
368 action->uuid, pe__node_name(action->node));
369 pe__clear_action_flags(action, pcmk_action_runnable);
370 } else {
371 pe_rsc_trace(action->rsc,
372 "%s on %s does not require fencing or quorum",
373 action->uuid, pe__node_name(action->node));
374 pe__set_action_flags(action, pcmk_action_runnable);
375 }
376
377 } else {
378 switch (effective_quorum_policy(action->rsc, scheduler)) {
379 case pcmk_no_quorum_stop:
380 pe_rsc_debug(action->rsc, "%s on %s is unrunnable (no quorum)",
381 action->uuid, pe__node_name(action->node));
382 pe__clear_action_flags(action, pcmk_action_runnable);
383 pe_action_set_reason(action, "no quorum", true);
384 break;
385
386 case pcmk_no_quorum_freeze:
387 if (!action->rsc->fns->active(action->rsc, TRUE)
388 || (action->rsc->next_role > action->rsc->role)) {
389 pe_rsc_debug(action->rsc,
390 "%s on %s is unrunnable (no quorum)",
391 action->uuid, pe__node_name(action->node));
392 pe__clear_action_flags(action, pcmk_action_runnable);
393 pe_action_set_reason(action, "quorum freeze", true);
394 }
395 break;
396
397 default:
398
399 pe__set_action_flags(action, pcmk_action_runnable);
400 break;
401 }
402 }
403 }
404
405
406
407
408
409
410
411
412 static void
413 update_resource_flags_for_action(pcmk_resource_t *rsc,
414 const pcmk_action_t *action)
415 {
416
417
418
419 if (pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_casei)) {
420 pe__set_resource_flags(rsc, pcmk_rsc_stopping);
421
422 } else if (pcmk__str_eq(action->task, PCMK_ACTION_START, pcmk__str_casei)) {
423 if (pcmk_is_set(action->flags, pcmk_action_runnable)) {
424 pe__set_resource_flags(rsc, pcmk_rsc_starting);
425 } else {
426 pe__clear_resource_flags(rsc, pcmk_rsc_starting);
427 }
428 }
429 }
430
431 static bool
432 valid_stop_on_fail(const char *value)
433 {
434 return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
435 }
436
437
438
439
440
441
442
443
444
445
446 static void
447 validate_on_fail(const pcmk_resource_t *rsc, const char *action_name,
448 const xmlNode *action_config, GHashTable *meta)
449 {
450 const char *name = NULL;
451 const char *role = NULL;
452 const char *interval_spec = NULL;
453 const char *value = g_hash_table_lookup(meta, XML_OP_ATTR_ON_FAIL);
454 char *key = NULL;
455 char *new_value = NULL;
456
457
458 if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)
459 && !valid_stop_on_fail(value)) {
460
461 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
462 "action to default value because '%s' is not "
463 "allowed for stop", rsc->id, value);
464 g_hash_table_remove(meta, XML_OP_ATTR_ON_FAIL);
465 return;
466 }
467
468
469
470
471 if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTE, pcmk__str_none)
472 && (value == NULL)) {
473
474
475
476
477
478 for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
479 operation != NULL; operation = crm_next_same_xml(operation)) {
480 bool enabled = false;
481 const char *promote_on_fail = NULL;
482
483
484
485
486 promote_on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
487 if (promote_on_fail == NULL) {
488 continue;
489 }
490
491
492 name = crm_element_value(operation, "name");
493 role = crm_element_value(operation, "role");
494 if (!pcmk__str_eq(name, PCMK_ACTION_MONITOR, pcmk__str_none)
495 || !pcmk__strcase_any_of(role, PCMK__ROLE_PROMOTED,
496 PCMK__ROLE_PROMOTED_LEGACY, NULL)) {
497 continue;
498 }
499 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
500 if (crm_parse_interval_spec(interval_spec) == 0) {
501 continue;
502 }
503
504
505 if ((pcmk__xe_get_bool_attr(operation, "enabled",
506 &enabled) == pcmk_rc_ok) && !enabled) {
507 continue;
508 }
509
510
511 if (pcmk__str_eq(promote_on_fail, "demote", pcmk__str_casei)) {
512 continue;
513 }
514
515
516 key = strdup(XML_OP_ATTR_ON_FAIL);
517 new_value = strdup(promote_on_fail);
518 CRM_ASSERT((key != NULL) && (new_value != NULL));
519 g_hash_table_insert(meta, key, new_value);
520 }
521 return;
522 }
523
524 if (pcmk__str_eq(action_name, PCMK_ACTION_LRM_DELETE, pcmk__str_none)
525 && !pcmk__str_eq(value, "ignore", pcmk__str_casei)) {
526 key = strdup(XML_OP_ATTR_ON_FAIL);
527 new_value = strdup("ignore");
528 CRM_ASSERT((key != NULL) && (new_value != NULL));
529 g_hash_table_insert(meta, key, new_value);
530 return;
531 }
532
533
534 if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
535 name = crm_element_value(action_config, "name");
536 role = crm_element_value(action_config, "role");
537 interval_spec = crm_element_value(action_config,
538 XML_LRM_ATTR_INTERVAL);
539
540 if (!pcmk__str_eq(name, PCMK_ACTION_PROMOTE, pcmk__str_none)
541 && (!pcmk__str_eq(name, PCMK_ACTION_MONITOR, pcmk__str_none)
542 || !pcmk__strcase_any_of(role, PCMK__ROLE_PROMOTED,
543 PCMK__ROLE_PROMOTED_LEGACY, NULL)
544 || (crm_parse_interval_spec(interval_spec) == 0))) {
545 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
546 "action to default value because 'demote' is not "
547 "allowed for it", rsc->id, name);
548 g_hash_table_remove(meta, XML_OP_ATTR_ON_FAIL);
549 return;
550 }
551 }
552 }
553
554 static int
555 unpack_timeout(const char *value)
556 {
557 int timeout_ms = crm_get_msec(value);
558
559 if (timeout_ms < 0) {
560 timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
561 }
562 return timeout_ms;
563 }
564
565
566 static bool
567 unpack_interval_origin(const char *value, const xmlNode *xml_obj,
568 guint interval_ms, const crm_time_t *now,
569 long long *start_delay)
570 {
571 long long result = 0;
572 guint interval_sec = interval_ms / 1000;
573 crm_time_t *origin = NULL;
574
575
576 if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
577 return false;
578 }
579
580
581 origin = crm_time_new(value);
582 if (origin == NULL) {
583 pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
584 "'%s' because '%s' is not valid",
585 (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
586 return false;
587 }
588
589
590 result = crm_time_get_seconds(now) - crm_time_get_seconds(origin);
591 crm_time_free(origin);
592
593
594 result = result % interval_sec;
595
596
597 result = ((result <= 0)? 0 : interval_sec) - result;
598 crm_info("Calculated a start delay of %llds for operation '%s'",
599 result,
600 (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
601
602 if (start_delay != NULL) {
603 *start_delay = result * 1000;
604 }
605 return true;
606 }
607
608 static int
609 unpack_start_delay(const char *value, GHashTable *meta)
610 {
611 int start_delay = 0;
612
613 if (value != NULL) {
614 start_delay = crm_get_msec(value);
615
616 if (start_delay < 0) {
617 start_delay = 0;
618 }
619
620 if (meta) {
621 g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
622 pcmk__itoa(start_delay));
623 }
624 }
625
626 return start_delay;
627 }
628
629
630
631
632
633
634
635
636
637
638 static xmlNode *
639 most_frequent_monitor(const pcmk_resource_t *rsc)
640 {
641 guint min_interval_ms = G_MAXUINT;
642 xmlNode *op = NULL;
643
644 for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
645 operation != NULL; operation = crm_next_same_xml(operation)) {
646 bool enabled = false;
647 guint interval_ms = 0;
648 const char *interval_spec = crm_element_value(operation,
649 XML_LRM_ATTR_INTERVAL);
650
651
652 if (!pcmk__str_eq(crm_element_value(operation, "name"),
653 PCMK_ACTION_MONITOR, pcmk__str_none)) {
654 continue;
655 }
656 interval_ms = crm_parse_interval_spec(interval_spec);
657 if (interval_ms == 0) {
658 continue;
659 }
660
661
662 if ((pcmk__xe_get_bool_attr(operation, "enabled",
663 &enabled) == pcmk_rc_ok) && !enabled) {
664 continue;
665 }
666
667 if (interval_ms < min_interval_ms) {
668 min_interval_ms = interval_ms;
669 op = operation;
670 }
671 }
672 return op;
673 }
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691 GHashTable *
692 pcmk__unpack_action_meta(pcmk_resource_t *rsc, const pcmk_node_t *node,
693 const char *action_name, guint interval_ms,
694 const xmlNode *action_config)
695 {
696 GHashTable *meta = NULL;
697 char *name = NULL;
698 char *value = NULL;
699 const char *timeout_spec = NULL;
700 const char *str = NULL;
701
702 pe_rsc_eval_data_t rsc_rule_data = {
703 .standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS),
704 .provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER),
705 .agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE),
706 };
707
708 pe_op_eval_data_t op_rule_data = {
709 .op_name = action_name,
710 .interval = interval_ms,
711 };
712
713 pe_rule_eval_data_t rule_data = {
714 .node_hash = (node == NULL)? NULL : node->details->attrs,
715 .role = pcmk_role_unknown,
716 .now = rsc->cluster->now,
717 .match_data = NULL,
718 .rsc_data = &rsc_rule_data,
719 .op_data = &op_rule_data,
720 };
721
722 meta = pcmk__strkey_table(free, free);
723
724
725 pe__unpack_dataset_nvpairs(rsc->cluster->op_defaults, XML_TAG_META_SETS,
726 &rule_data, meta, NULL, FALSE, rsc->cluster);
727
728
729 if (pcmk_is_probe(action_name, interval_ms)) {
730 xmlNode *min_interval_mon = most_frequent_monitor(rsc);
731
732 if (min_interval_mon != NULL) {
733
734
735
736 timeout_spec = crm_element_value(min_interval_mon,
737 XML_ATTR_TIMEOUT);
738 if (timeout_spec != NULL) {
739 pe_rsc_trace(rsc,
740 "Setting default timeout for %s probe to "
741 "most frequent monitor's timeout '%s'",
742 rsc->id, timeout_spec);
743 name = strdup(XML_ATTR_TIMEOUT);
744 value = strdup(timeout_spec);
745 CRM_ASSERT((name != NULL) && (value != NULL));
746 g_hash_table_insert(meta, name, value);
747 }
748 }
749 }
750
751 if (action_config != NULL) {
752
753 pe__unpack_dataset_nvpairs(action_config, XML_TAG_META_SETS, &rule_data,
754 meta, NULL, TRUE, rsc->cluster);
755
756
757
758
759
760 for (xmlAttrPtr attr = action_config->properties;
761 attr != NULL; attr = attr->next) {
762 name = strdup((const char *) attr->name);
763 value = strdup(pcmk__xml_attr_value(attr));
764
765 CRM_ASSERT((name != NULL) && (value != NULL));
766 g_hash_table_insert(meta, name, value);
767 }
768 }
769
770 g_hash_table_remove(meta, XML_ATTR_ID);
771
772
773 if (interval_ms > 0) {
774 name = strdup(XML_LRM_ATTR_INTERVAL);
775 CRM_ASSERT(name != NULL);
776 value = crm_strdup_printf("%u", interval_ms);
777 g_hash_table_insert(meta, name, value);
778 } else {
779 g_hash_table_remove(meta, XML_LRM_ATTR_INTERVAL);
780 }
781
782
783
784
785
786
787
788
789
790
791
792
793 if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
794 pcmk_ra_cap_fence_params)
795 && (pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)
796 || pcmk_is_probe(action_name, interval_ms))) {
797
798 GHashTable *params = pe_rsc_params(rsc, node, rsc->cluster);
799
800 timeout_spec = g_hash_table_lookup(params, "pcmk_monitor_timeout");
801 if (timeout_spec != NULL) {
802 pe_rsc_trace(rsc,
803 "Setting timeout for %s %s to "
804 "pcmk_monitor_timeout (%s)",
805 rsc->id, action_name, timeout_spec);
806 name = strdup(XML_ATTR_TIMEOUT);
807 value = strdup(timeout_spec);
808 CRM_ASSERT((name != NULL) && (value != NULL));
809 g_hash_table_insert(meta, name, value);
810 }
811 }
812
813
814 name = strdup(XML_ATTR_TIMEOUT);
815 CRM_ASSERT(name != NULL);
816 timeout_spec = g_hash_table_lookup(meta, XML_ATTR_TIMEOUT);
817 g_hash_table_insert(meta, name, pcmk__itoa(unpack_timeout(timeout_spec)));
818
819
820 validate_on_fail(rsc, action_name, action_config, meta);
821
822
823 str = g_hash_table_lookup(meta, XML_OP_ATTR_START_DELAY);
824 if (str != NULL) {
825 unpack_start_delay(str, meta);
826 } else {
827 long long start_delay = 0;
828
829 str = g_hash_table_lookup(meta, XML_OP_ATTR_ORIGIN);
830 if (unpack_interval_origin(str, action_config, interval_ms,
831 rsc->cluster->now, &start_delay)) {
832 name = strdup(XML_OP_ATTR_START_DELAY);
833 CRM_ASSERT(name != NULL);
834 g_hash_table_insert(meta, name,
835 crm_strdup_printf("%lld", start_delay));
836 }
837 }
838 return meta;
839 }
840
841
842
843
844
845
846
847
848
849
850 enum rsc_start_requirement
851 pcmk__action_requires(const pcmk_resource_t *rsc, const char *action_name)
852 {
853 const char *value = NULL;
854 enum rsc_start_requirement requires = pcmk_requires_nothing;
855
856 CRM_CHECK((rsc != NULL) && (action_name != NULL), return requires);
857
858 if (!pcmk__strcase_any_of(action_name, PCMK_ACTION_START,
859 PCMK_ACTION_PROMOTE, NULL)) {
860 value = "nothing (not start or promote)";
861
862 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_fencing)) {
863 requires = pcmk_requires_fencing;
864 value = "fencing";
865
866 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_quorum)) {
867 requires = pcmk_requires_quorum;
868 value = "quorum";
869
870 } else {
871 value = "nothing";
872 }
873 pe_rsc_trace(rsc, "%s of %s requires %s", action_name, rsc->id, value);
874 return requires;
875 }
876
877
878
879
880
881
882
883
884
885
886
887
888 enum action_fail_response
889 pcmk__parse_on_fail(const pcmk_resource_t *rsc, const char *action_name,
890 guint interval_ms, const char *value)
891 {
892 const char *desc = NULL;
893 bool needs_remote_reset = false;
894 enum action_fail_response on_fail = pcmk_on_fail_ignore;
895
896 if (value == NULL) {
897
898
899 } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
900 on_fail = pcmk_on_fail_block;
901 desc = "block";
902
903 } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
904 if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_fencing_enabled)) {
905 on_fail = pcmk_on_fail_fence_node;
906 desc = "node fencing";
907 } else {
908 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
909 "%s of %s to 'stop' because 'fence' is not "
910 "valid when fencing is disabled",
911 action_name, rsc->id);
912 on_fail = pcmk_on_fail_stop;
913 desc = "stop resource";
914 }
915
916 } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
917 on_fail = pcmk_on_fail_standby_node;
918 desc = "node standby";
919
920 } else if (pcmk__strcase_any_of(value, "ignore", PCMK__VALUE_NOTHING,
921 NULL)) {
922 desc = "ignore";
923
924 } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
925 on_fail = pcmk_on_fail_ban;
926 desc = "force migration";
927
928 } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
929 on_fail = pcmk_on_fail_stop;
930 desc = "stop resource";
931
932 } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
933 on_fail = pcmk_on_fail_restart;
934 desc = "restart (and possibly migrate)";
935
936 } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
937 if (rsc->container == NULL) {
938 pe_rsc_debug(rsc,
939 "Using default " XML_OP_ATTR_ON_FAIL
940 " for %s of %s because it does not have a container",
941 action_name, rsc->id);
942 } else {
943 on_fail = pcmk_on_fail_restart_container;
944 desc = "restart container (and possibly migrate)";
945 }
946
947 } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
948 on_fail = pcmk_on_fail_demote;
949 desc = "demote instance";
950
951 } else {
952 pcmk__config_err("Using default '" XML_OP_ATTR_ON_FAIL "' for "
953 "%s of %s because '%s' is not valid",
954 action_name, rsc->id, value);
955 }
956
957
958
959
960
961
962 if (pe__resource_is_remote_conn(rsc)
963 && !pcmk_is_probe(action_name, interval_ms)
964 && !pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)) {
965 needs_remote_reset = true;
966 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
967 desc = NULL;
968 }
969 }
970
971 if (desc != NULL) {
972
973
974 } else if (rsc->container != NULL) {
975 on_fail = pcmk_on_fail_restart_container;
976 desc = "restart container (and possibly migrate) (default)";
977
978 } else if (needs_remote_reset) {
979 if (pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
980 if (pcmk_is_set(rsc->cluster->flags,
981 pcmk_sched_fencing_enabled)) {
982 desc = "fence remote node (default)";
983 } else {
984 desc = "recover remote node connection (default)";
985 }
986 on_fail = pcmk_on_fail_reset_remote;
987 } else {
988 on_fail = pcmk_on_fail_stop;
989 desc = "stop unmanaged remote node (enforcing default)";
990 }
991
992 } else if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)) {
993 if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_fencing_enabled)) {
994 on_fail = pcmk_on_fail_fence_node;
995 desc = "resource fence (default)";
996 } else {
997 on_fail = pcmk_on_fail_block;
998 desc = "resource block (default)";
999 }
1000
1001 } else {
1002 on_fail = pcmk_on_fail_restart;
1003 desc = "restart (and possibly migrate) (default)";
1004 }
1005
1006 pe_rsc_trace(rsc, "Failure handling for %s-interval %s of %s: %s",
1007 pcmk__readable_interval(interval_ms), action_name,
1008 rsc->id, desc);
1009 return on_fail;
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 enum rsc_role_e
1024 pcmk__role_after_failure(const pcmk_resource_t *rsc, const char *action_name,
1025 enum action_fail_response on_fail, GHashTable *meta)
1026 {
1027 const char *value = NULL;
1028 enum rsc_role_e role = pcmk_role_unknown;
1029
1030
1031 switch (on_fail) {
1032 case pcmk_on_fail_stop:
1033 role = pcmk_role_stopped;
1034 break;
1035
1036 case pcmk_on_fail_reset_remote:
1037 if (rsc->remote_reconnect_ms != 0) {
1038 role = pcmk_role_stopped;
1039 }
1040 break;
1041
1042 default:
1043 break;
1044 }
1045
1046
1047 value = g_hash_table_lookup(meta, "role_after_failure");
1048 if (value != NULL) {
1049 pe_warn_once(pcmk__wo_role_after,
1050 "Support for role_after_failure is deprecated "
1051 "and will be removed in a future release");
1052 if (role == pcmk_role_unknown) {
1053 role = text2role(value);
1054 }
1055 }
1056
1057 if (role == pcmk_role_unknown) {
1058
1059 if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
1060 role = pcmk_role_unpromoted;
1061 } else {
1062 role = pcmk_role_started;
1063 }
1064 }
1065 pe_rsc_trace(rsc, "Role after %s %s failure is: %s",
1066 rsc->id, action_name, role2text(role));
1067 return role;
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 static void
1083 unpack_operation(pcmk_action_t *action, const xmlNode *xml_obj,
1084 guint interval_ms)
1085 {
1086 const char *value = NULL;
1087
1088 action->meta = pcmk__unpack_action_meta(action->rsc, action->node,
1089 action->task, interval_ms, xml_obj);
1090 action->needs = pcmk__action_requires(action->rsc, action->task);
1091
1092 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
1093 action->on_fail = pcmk__parse_on_fail(action->rsc, action->task,
1094 interval_ms, value);
1095
1096 action->fail_role = pcmk__role_after_failure(action->rsc, action->task,
1097 action->on_fail, action->meta);
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 pcmk_action_t *
1117 custom_action(pcmk_resource_t *rsc, char *key, const char *task,
1118 const pcmk_node_t *on_node, gboolean optional,
1119 pcmk_scheduler_t *scheduler)
1120 {
1121 pcmk_action_t *action = NULL;
1122
1123 CRM_ASSERT((key != NULL) && (task != NULL) && (scheduler != NULL));
1124
1125 action = find_existing_action(key, rsc, on_node, scheduler);
1126 if (action == NULL) {
1127 action = new_action(key, task, rsc, on_node, optional, scheduler);
1128 } else {
1129 free(key);
1130 }
1131
1132 update_action_optional(action, optional);
1133
1134 if (rsc != NULL) {
1135 if ((action->node != NULL) && (action->op_entry != NULL)
1136 && !pcmk_is_set(action->flags, pcmk_action_attrs_evaluated)) {
1137
1138 GHashTable *attrs = action->node->details->attrs;
1139
1140 if (action->extra != NULL) {
1141 g_hash_table_destroy(action->extra);
1142 }
1143 action->extra = pcmk__unpack_action_rsc_params(action->op_entry,
1144 attrs, scheduler);
1145 pe__set_action_flags(action, pcmk_action_attrs_evaluated);
1146 }
1147
1148 update_resource_action_runnable(action, scheduler);
1149 update_resource_flags_for_action(rsc, action);
1150 }
1151
1152 if (action->extra == NULL) {
1153 action->extra = pcmk__strkey_table(free, free);
1154 }
1155
1156 return action;
1157 }
1158
1159 pcmk_action_t *
1160 get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler)
1161 {
1162 pcmk_action_t *op = lookup_singleton(scheduler, name);
1163
1164 if (op == NULL) {
1165 op = custom_action(NULL, strdup(name), name, NULL, TRUE, scheduler);
1166 pe__set_action_flags(op, pcmk_action_pseudo|pcmk_action_runnable);
1167 }
1168 return op;
1169 }
1170
1171 static GList *
1172 find_unfencing_devices(GList *candidates, GList *matches)
1173 {
1174 for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
1175 pcmk_resource_t *candidate = gIter->data;
1176
1177 if (candidate->children != NULL) {
1178 matches = find_unfencing_devices(candidate->children, matches);
1179
1180 } else if (!pcmk_is_set(candidate->flags, pcmk_rsc_fence_device)) {
1181 continue;
1182
1183 } else if (pcmk_is_set(candidate->flags, pcmk_rsc_needs_unfencing)) {
1184 matches = g_list_prepend(matches, candidate);
1185
1186 } else if (pcmk__str_eq(g_hash_table_lookup(candidate->meta,
1187 PCMK_STONITH_PROVIDES),
1188 PCMK__VALUE_UNFENCING,
1189 pcmk__str_casei)) {
1190 matches = g_list_prepend(matches, candidate);
1191 }
1192 }
1193 return matches;
1194 }
1195
1196 static int
1197 node_priority_fencing_delay(const pcmk_node_t *node,
1198 const pcmk_scheduler_t *scheduler)
1199 {
1200 int member_count = 0;
1201 int online_count = 0;
1202 int top_priority = 0;
1203 int lowest_priority = 0;
1204 GList *gIter = NULL;
1205
1206
1207 if (scheduler->priority_fencing_delay <= 0) {
1208 return 0;
1209 }
1210
1211
1212
1213 if (node->details->type != pcmk_node_variant_cluster) {
1214 return 0;
1215 }
1216
1217
1218 if (node->details->online) {
1219 return 0;
1220 }
1221
1222 for (gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
1223 pcmk_node_t *n = gIter->data;
1224
1225 if (n->details->type != pcmk_node_variant_cluster) {
1226 continue;
1227 }
1228
1229 member_count ++;
1230
1231 if (n->details->online) {
1232 online_count++;
1233 }
1234
1235 if (member_count == 1
1236 || n->details->priority > top_priority) {
1237 top_priority = n->details->priority;
1238 }
1239
1240 if (member_count == 1
1241 || n->details->priority < lowest_priority) {
1242 lowest_priority = n->details->priority;
1243 }
1244 }
1245
1246
1247 if (online_count > member_count / 2) {
1248 return 0;
1249 }
1250
1251
1252
1253 if (lowest_priority == top_priority) {
1254 return 0;
1255 }
1256
1257 if (node->details->priority < top_priority) {
1258 return 0;
1259 }
1260
1261 return scheduler->priority_fencing_delay;
1262 }
1263
1264 pcmk_action_t *
1265 pe_fence_op(pcmk_node_t *node, const char *op, bool optional,
1266 const char *reason, bool priority_delay,
1267 pcmk_scheduler_t *scheduler)
1268 {
1269 char *op_key = NULL;
1270 pcmk_action_t *stonith_op = NULL;
1271
1272 if(op == NULL) {
1273 op = scheduler->stonith_action;
1274 }
1275
1276 op_key = crm_strdup_printf("%s-%s-%s",
1277 PCMK_ACTION_STONITH, node->details->uname, op);
1278
1279 stonith_op = lookup_singleton(scheduler, op_key);
1280 if(stonith_op == NULL) {
1281 stonith_op = custom_action(NULL, op_key, PCMK_ACTION_STONITH, node,
1282 TRUE, scheduler);
1283
1284 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1285 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
1286 add_hash_param(stonith_op->meta, "stonith_action", op);
1287
1288 if (pcmk_is_set(scheduler->flags, pcmk_sched_enable_unfencing)) {
1289
1290
1291 GString *digests_all = g_string_sized_new(1024);
1292 GString *digests_secure = g_string_sized_new(1024);
1293
1294 GList *matches = find_unfencing_devices(scheduler->resources, NULL);
1295
1296 char *key = NULL;
1297 char *value = NULL;
1298
1299 for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
1300 pcmk_resource_t *match = gIter->data;
1301 const char *agent = g_hash_table_lookup(match->meta,
1302 XML_ATTR_TYPE);
1303 op_digest_cache_t *data = NULL;
1304
1305 data = pe__compare_fencing_digest(match, agent, node,
1306 scheduler);
1307 if (data->rc == pcmk__digest_mismatch) {
1308 optional = FALSE;
1309 crm_notice("Unfencing node %s because the definition of "
1310 "%s changed", pe__node_name(node), match->id);
1311 if (!pcmk__is_daemon && scheduler->priv != NULL) {
1312 pcmk__output_t *out = scheduler->priv;
1313
1314 out->info(out,
1315 "notice: Unfencing node %s because the "
1316 "definition of %s changed",
1317 pe__node_name(node), match->id);
1318 }
1319 }
1320
1321 pcmk__g_strcat(digests_all,
1322 match->id, ":", agent, ":",
1323 data->digest_all_calc, ",", NULL);
1324 pcmk__g_strcat(digests_secure,
1325 match->id, ":", agent, ":",
1326 data->digest_secure_calc, ",", NULL);
1327 }
1328 key = strdup(XML_OP_ATTR_DIGESTS_ALL);
1329 value = strdup((const char *) digests_all->str);
1330 CRM_ASSERT((key != NULL) && (value != NULL));
1331 g_hash_table_insert(stonith_op->meta, key, value);
1332 g_string_free(digests_all, TRUE);
1333
1334 key = strdup(XML_OP_ATTR_DIGESTS_SECURE);
1335 value = strdup((const char *) digests_secure->str);
1336 CRM_ASSERT((key != NULL) && (value != NULL));
1337 g_hash_table_insert(stonith_op->meta, key, value);
1338 g_string_free(digests_secure, TRUE);
1339 }
1340
1341 } else {
1342 free(op_key);
1343 }
1344
1345 if (scheduler->priority_fencing_delay > 0
1346
1347
1348
1349 && (priority_delay
1350
1351
1352
1353
1354
1355 || g_hash_table_lookup(stonith_op->meta,
1356 XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY) != NULL)) {
1357
1358
1359
1360
1361
1362 char *delay_s = pcmk__itoa(node_priority_fencing_delay(node,
1363 scheduler));
1364
1365 g_hash_table_insert(stonith_op->meta,
1366 strdup(XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY),
1367 delay_s);
1368 }
1369
1370 if(optional == FALSE && pe_can_fence(scheduler, node)) {
1371 pe__clear_action_flags(stonith_op, pcmk_action_optional);
1372 pe_action_set_reason(stonith_op, reason, false);
1373
1374 } else if(reason && stonith_op->reason == NULL) {
1375 stonith_op->reason = strdup(reason);
1376 }
1377
1378 return stonith_op;
1379 }
1380
1381 void
1382 pe_free_action(pcmk_action_t *action)
1383 {
1384 if (action == NULL) {
1385 return;
1386 }
1387 g_list_free_full(action->actions_before, free);
1388 g_list_free_full(action->actions_after, free);
1389 if (action->extra) {
1390 g_hash_table_destroy(action->extra);
1391 }
1392 if (action->meta) {
1393 g_hash_table_destroy(action->meta);
1394 }
1395 free(action->cancel_task);
1396 free(action->reason);
1397 free(action->task);
1398 free(action->uuid);
1399 free(action->node);
1400 free(action);
1401 }
1402
1403 int
1404 pe_get_configured_timeout(pcmk_resource_t *rsc, const char *action,
1405 pcmk_scheduler_t *scheduler)
1406 {
1407 xmlNode *child = NULL;
1408 GHashTable *action_meta = NULL;
1409 const char *timeout_spec = NULL;
1410 int timeout_ms = 0;
1411
1412 pe_rule_eval_data_t rule_data = {
1413 .node_hash = NULL,
1414 .role = pcmk_role_unknown,
1415 .now = scheduler->now,
1416 .match_data = NULL,
1417 .rsc_data = NULL,
1418 .op_data = NULL
1419 };
1420
1421 for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
1422 child != NULL; child = crm_next_same_xml(child)) {
1423 if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
1424 pcmk__str_casei)) {
1425 timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
1426 break;
1427 }
1428 }
1429
1430 if (timeout_spec == NULL && scheduler->op_defaults) {
1431 action_meta = pcmk__strkey_table(free, free);
1432 pe__unpack_dataset_nvpairs(scheduler->op_defaults, XML_TAG_META_SETS,
1433 &rule_data, action_meta, NULL, FALSE,
1434 scheduler);
1435 timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
1436 }
1437
1438
1439
1440
1441 timeout_ms = crm_get_msec(timeout_spec);
1442 if (timeout_ms < 0) {
1443 timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
1444 }
1445
1446 if (action_meta != NULL) {
1447 g_hash_table_destroy(action_meta);
1448 }
1449 return timeout_ms;
1450 }
1451
1452 enum action_tasks
1453 get_complex_task(const pcmk_resource_t *rsc, const char *name)
1454 {
1455 enum action_tasks task = text2task(name);
1456
1457 if ((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_primitive)) {
1458 switch (task) {
1459 case pcmk_action_stopped:
1460 case pcmk_action_started:
1461 case pcmk_action_demoted:
1462 case pcmk_action_promoted:
1463 crm_trace("Folding %s back into its atomic counterpart for %s",
1464 name, rsc->id);
1465 --task;
1466 break;
1467 default:
1468 break;
1469 }
1470 }
1471 return task;
1472 }
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 pcmk_action_t *
1486 find_first_action(const GList *input, const char *uuid, const char *task,
1487 const pcmk_node_t *on_node)
1488 {
1489 CRM_CHECK(uuid || task, return NULL);
1490
1491 for (const GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1492 pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1493
1494 if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1495 continue;
1496
1497 } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1498 continue;
1499
1500 } else if (on_node == NULL) {
1501 return action;
1502
1503 } else if (action->node == NULL) {
1504 continue;
1505
1506 } else if (on_node->details == action->node->details) {
1507 return action;
1508 }
1509 }
1510
1511 return NULL;
1512 }
1513
1514 GList *
1515 find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
1516 {
1517 GList *gIter = input;
1518 GList *result = NULL;
1519
1520 CRM_CHECK(key != NULL, return NULL);
1521
1522 for (; gIter != NULL; gIter = gIter->next) {
1523 pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1524
1525 if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1526 continue;
1527
1528 } else if (on_node == NULL) {
1529 crm_trace("Action %s matches (ignoring node)", key);
1530 result = g_list_prepend(result, action);
1531
1532 } else if (action->node == NULL) {
1533 crm_trace("Action %s matches (unallocated, assigning to %s)",
1534 key, pe__node_name(on_node));
1535
1536 action->node = pe__copy_node(on_node);
1537 result = g_list_prepend(result, action);
1538
1539 } else if (on_node->details == action->node->details) {
1540 crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1541 result = g_list_prepend(result, action);
1542 }
1543 }
1544
1545 return result;
1546 }
1547
1548 GList *
1549 find_actions_exact(GList *input, const char *key, const pcmk_node_t *on_node)
1550 {
1551 GList *result = NULL;
1552
1553 CRM_CHECK(key != NULL, return NULL);
1554
1555 if (on_node == NULL) {
1556 return NULL;
1557 }
1558
1559 for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1560 pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1561
1562 if ((action->node != NULL)
1563 && pcmk__str_eq(key, action->uuid, pcmk__str_casei)
1564 && pcmk__str_eq(on_node->details->id, action->node->details->id,
1565 pcmk__str_casei)) {
1566
1567 crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1568 result = g_list_prepend(result, action);
1569 }
1570 }
1571
1572 return result;
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587 GList *
1588 pe__resource_actions(const pcmk_resource_t *rsc, const pcmk_node_t *node,
1589 const char *task, bool require_node)
1590 {
1591 GList *result = NULL;
1592 char *key = pcmk__op_key(rsc->id, task, 0);
1593
1594 if (require_node) {
1595 result = find_actions_exact(rsc->actions, key, node);
1596 } else {
1597 result = find_actions(rsc->actions, key, node);
1598 }
1599 free(key);
1600 return result;
1601 }
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613 char *
1614 pe__action2reason(const pcmk_action_t *action, enum pe_action_flags flag)
1615 {
1616 const char *change = NULL;
1617
1618 switch (flag) {
1619 case pcmk_action_runnable:
1620 change = "unrunnable";
1621 break;
1622 case pcmk_action_migratable:
1623 change = "unmigrateable";
1624 break;
1625 case pcmk_action_optional:
1626 change = "required";
1627 break;
1628 default:
1629
1630 CRM_CHECK(change != NULL, change = "");
1631 break;
1632 }
1633 return crm_strdup_printf("%s%s%s %s", change,
1634 (action->rsc == NULL)? "" : " ",
1635 (action->rsc == NULL)? "" : action->rsc->id,
1636 action->task);
1637 }
1638
1639 void pe_action_set_reason(pcmk_action_t *action, const char *reason,
1640 bool overwrite)
1641 {
1642 if (action->reason != NULL && overwrite) {
1643 pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
1644 action->uuid, action->reason, pcmk__s(reason, "(none)"));
1645 } else if (action->reason == NULL) {
1646 pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
1647 action->uuid, pcmk__s(reason, "(none)"));
1648 } else {
1649
1650 return;
1651 }
1652
1653 pcmk__str_update(&action->reason, reason);
1654 }
1655
1656
1657
1658
1659
1660
1661
1662
1663 void
1664 pe__clear_resource_history(pcmk_resource_t *rsc, const pcmk_node_t *node)
1665 {
1666 CRM_ASSERT((rsc != NULL) && (node != NULL));
1667
1668 custom_action(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_LRM_DELETE, 0),
1669 PCMK_ACTION_LRM_DELETE, node, FALSE, rsc->cluster);
1670 }
1671
1672 #define sort_return(an_int, why) do { \
1673 free(a_uuid); \
1674 free(b_uuid); \
1675 crm_trace("%s (%d) %c %s (%d) : %s", \
1676 a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1677 b_xml_id, b_call_id, why); \
1678 return an_int; \
1679 } while(0)
1680
1681 int
1682 pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b,
1683 bool same_node_default)
1684 {
1685 int a_call_id = -1;
1686 int b_call_id = -1;
1687
1688 char *a_uuid = NULL;
1689 char *b_uuid = NULL;
1690
1691 const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1692 const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1693
1694 const char *a_node = crm_element_value(xml_a, XML_LRM_ATTR_TARGET);
1695 const char *b_node = crm_element_value(xml_b, XML_LRM_ATTR_TARGET);
1696 bool same_node = true;
1697
1698
1699
1700
1701
1702
1703
1704
1705 if (a_node == NULL || b_node == NULL) {
1706 same_node = same_node_default;
1707
1708 } else {
1709 same_node = pcmk__str_eq(a_node, b_node, pcmk__str_casei);
1710 }
1711
1712 if (same_node && pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_none)) {
1713
1714
1715
1716
1717
1718 pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1719 sort_return(0, "duplicate");
1720 }
1721
1722 crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1723 crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1724
1725 if (a_call_id == -1 && b_call_id == -1) {
1726
1727
1728
1729 sort_return(0, "pending");
1730
1731 } else if (same_node && a_call_id >= 0 && a_call_id < b_call_id) {
1732 sort_return(-1, "call id");
1733
1734 } else if (same_node && b_call_id >= 0 && a_call_id > b_call_id) {
1735 sort_return(1, "call id");
1736
1737 } else if (a_call_id >= 0 && b_call_id >= 0
1738 && (!same_node || a_call_id == b_call_id)) {
1739
1740
1741
1742
1743 time_t last_a = -1;
1744 time_t last_b = -1;
1745
1746 crm_element_value_epoch(xml_a, XML_RSC_OP_LAST_CHANGE, &last_a);
1747 crm_element_value_epoch(xml_b, XML_RSC_OP_LAST_CHANGE, &last_b);
1748
1749 crm_trace("rc-change: %lld vs %lld",
1750 (long long) last_a, (long long) last_b);
1751 if (last_a >= 0 && last_a < last_b) {
1752 sort_return(-1, "rc-change");
1753
1754 } else if (last_b >= 0 && last_a > last_b) {
1755 sort_return(1, "rc-change");
1756 }
1757 sort_return(0, "rc-change");
1758
1759 } else {
1760
1761
1762
1763
1764 int a_id = -1;
1765 int b_id = -1;
1766
1767 const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1768 const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1769
1770 CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1771 if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1772 NULL)) {
1773 sort_return(0, "bad magic a");
1774 }
1775 if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1776 NULL)) {
1777 sort_return(0, "bad magic b");
1778 }
1779
1780
1781
1782
1783
1784
1785 if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795 if (b_call_id == -1) {
1796 sort_return(-1, "transition + call");
1797
1798 } else if (a_call_id == -1) {
1799 sort_return(1, "transition + call");
1800 }
1801
1802 } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1803 sort_return(-1, "transition");
1804
1805 } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1806 sort_return(1, "transition");
1807 }
1808 }
1809
1810
1811 CRM_CHECK(FALSE, sort_return(0, "default"));
1812 }
1813
1814 gint
1815 sort_op_by_callid(gconstpointer a, gconstpointer b)
1816 {
1817 const xmlNode *xml_a = a;
1818 const xmlNode *xml_b = b;
1819
1820 return pe__is_newer_op(xml_a, xml_b, true);
1821 }
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834 pcmk_action_t *
1835 pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional,
1836 bool runnable)
1837 {
1838 pcmk_action_t *action = NULL;
1839
1840 CRM_ASSERT((rsc != NULL) && (task != NULL));
1841
1842 action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0), task, NULL,
1843 optional, rsc->cluster);
1844 pe__set_action_flags(action, pcmk_action_pseudo);
1845 if (runnable) {
1846 pe__set_action_flags(action, pcmk_action_runnable);
1847 }
1848 return action;
1849 }
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860 void
1861 pe__add_action_expected_result(pcmk_action_t *action, int expected_result)
1862 {
1863 char *name = NULL;
1864
1865 CRM_ASSERT((action != NULL) && (action->meta != NULL));
1866
1867 name = strdup(XML_ATTR_TE_TARGET_RC);
1868 CRM_ASSERT (name != NULL);
1869
1870 g_hash_table_insert(action->meta, name, pcmk__itoa(expected_result));
1871 }