pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pe_actions.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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>
18#include "pe_status_private.h"
19
20static void unpack_operation(pe_action_t *action, const xmlNode *xml_obj,
21 const pe_resource_t *container,
22 pe_working_set_t *data_set, guint interval_ms);
23
24static void
26{
27 if (data_set->singletons == NULL) {
29 }
30 g_hash_table_insert(data_set->singletons, action->uuid, action);
31}
32
33static pe_action_t *
34lookup_singleton(pe_working_set_t *data_set, const char *action_uuid)
35{
36 if (data_set->singletons == NULL) {
37 return NULL;
38 }
39 return g_hash_table_lookup(data_set->singletons, action_uuid);
40}
41
53static pe_action_t *
54find_existing_action(const char *key, const pe_resource_t *rsc,
55 const pe_node_t *node, const pe_working_set_t *data_set)
56{
57 GList *matches = NULL;
58 pe_action_t *action = NULL;
59
60 /* When rsc is NULL, it would be quicker to check data_set->singletons,
61 * but checking all data_set->actions takes the node into account.
62 */
63 matches = find_actions(((rsc == NULL)? data_set->actions : rsc->actions),
64 key, node);
65 if (matches == NULL) {
66 return NULL;
67 }
68 CRM_LOG_ASSERT(!pcmk__list_of_multiple(matches));
69
70 action = matches->data;
71 g_list_free(matches);
72 return action;
73}
74
75static xmlNode *
76find_rsc_op_entry_helper(const pe_resource_t *rsc, const char *key,
77 gboolean include_disabled)
78{
79 guint interval_ms = 0;
80 gboolean do_retry = TRUE;
81 char *local_key = NULL;
82 const char *name = NULL;
83 const char *interval_spec = NULL;
84 char *match_key = NULL;
85 xmlNode *op = NULL;
86 xmlNode *operation = NULL;
87
88 retry:
89 for (operation = pcmk__xe_first_child(rsc->ops_xml); operation != NULL;
90 operation = pcmk__xe_next(operation)) {
91
92 if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
93 bool enabled = false;
94
95 name = crm_element_value(operation, "name");
96 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
97 if (!include_disabled && pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok &&
98 !enabled) {
99 continue;
100 }
101
102 interval_ms = crm_parse_interval_spec(interval_spec);
103 match_key = pcmk__op_key(rsc->id, name, interval_ms);
104 if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
105 op = operation;
106 }
107 free(match_key);
108
109 if (rsc->clone_name) {
110 match_key = pcmk__op_key(rsc->clone_name, name, interval_ms);
111 if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
112 op = operation;
113 }
114 free(match_key);
115 }
116
117 if (op != NULL) {
118 free(local_key);
119 return op;
120 }
121 }
122 }
123
124 free(local_key);
125 if (do_retry == FALSE) {
126 return NULL;
127 }
128
129 do_retry = FALSE;
130 if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
131 local_key = pcmk__op_key(rsc->id, "migrate", 0);
132 key = local_key;
133 goto retry;
134
135 } else if (strstr(key, "_notify_")) {
136 local_key = pcmk__op_key(rsc->id, "notify", 0);
137 key = local_key;
138 goto retry;
139 }
140
141 return NULL;
142}
143
144xmlNode *
145find_rsc_op_entry(const pe_resource_t *rsc, const char *key)
146{
147 return find_rsc_op_entry_helper(rsc, key, FALSE);
148}
149
166static pe_action_t *
167new_action(char *key, const char *task, pe_resource_t *rsc,
168 const pe_node_t *node, bool optional, bool for_graph,
170{
171 pe_action_t *action = calloc(1, sizeof(pe_action_t));
172
173 CRM_ASSERT(action != NULL);
174
175 action->rsc = rsc;
176 action->task = strdup(task); CRM_ASSERT(action->task != NULL);
177 action->uuid = key;
178 action->extra = pcmk__strkey_table(free, free);
179 action->meta = pcmk__strkey_table(free, free);
180
181 if (node) {
182 action->node = pe__copy_node(node);
183 }
184
185 if (pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
186 // Resource history deletion for a node can be done on the DC
188 }
189
191 if (optional) {
193 } else {
195 }
196
197 if (rsc != NULL) {
198 guint interval_ms = 0;
199
200 action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
201 parse_op_key(key, NULL, NULL, &interval_ms);
202 unpack_operation(action, action->op_entry, rsc->container, data_set,
203 interval_ms);
204 }
205
206 if (for_graph) {
207 pe_rsc_trace(rsc, "Created %s action %d (%s): %s for %s on %s",
208 (optional? "optional" : "required"),
209 data_set->action_id, key, task,
210 ((rsc == NULL)? "no resource" : rsc->id),
211 pe__node_name(node));
212 action->id = data_set->action_id++;
213
214 data_set->actions = g_list_prepend(data_set->actions, action);
215 if (rsc == NULL) {
216 add_singleton(data_set, action);
217 } else {
218 rsc->actions = g_list_prepend(rsc->actions, action);
219 }
220 }
221 return action;
222}
223
231static void
232unpack_action_node_attributes(pe_action_t *action, pe_working_set_t *data_set)
233{
235 && (action->op_entry != NULL)) {
236
237 pe_rule_eval_data_t rule_data = {
238 .node_hash = action->node->details->attrs,
239 .role = RSC_ROLE_UNKNOWN,
240 .now = data_set->now,
241 .match_data = NULL,
242 .rsc_data = NULL,
243 .op_data = NULL
244 };
245
248 &rule_data, action->extra, NULL,
249 FALSE, data_set);
250 }
251}
252
260static void
261update_action_optional(pe_action_t *action, gboolean optional)
262{
263 // Force a non-recurring action to be optional if its resource is unmanaged
264 if ((action->rsc != NULL) && (action->node != NULL)
266 && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
267 && (g_hash_table_lookup(action->meta,
268 XML_LRM_ATTR_INTERVAL_MS) == NULL)) {
269 pe_rsc_debug(action->rsc, "%s on %s is optional (%s is unmanaged)",
270 action->uuid, pe__node_name(action->node),
271 action->rsc->id);
273 // We shouldn't clear runnable here because ... something
274
275 // Otherwise require the action if requested
276 } else if (!optional) {
278 }
279}
280
281static enum pe_quorum_policy
282effective_quorum_policy(pe_resource_t *rsc, pe_working_set_t *data_set)
283{
285
287 policy = no_quorum_ignore;
288
290 switch (rsc->role) {
293 if (rsc->next_role > RSC_ROLE_UNPROMOTED) {
295 "no-quorum-policy=demote");
296 }
297 policy = no_quorum_ignore;
298 break;
299 default:
300 policy = no_quorum_stop;
301 break;
302 }
303 }
304 return policy;
305}
306
317static void
318update_resource_action_runnable(pe_action_t *action, bool for_graph,
320{
321 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
322 return;
323 }
324
325 if (action->node == NULL) {
326 pe_rsc_trace(action->rsc, "%s is unrunnable (unallocated)",
327 action->uuid);
329
330 } else if (!pcmk_is_set(action->flags, pe_action_dc)
331 && !(action->node->details->online)
332 && (!pe__is_guest_node(action->node)
333 || action->node->details->remote_requires_reset)) {
335 do_crm_log((for_graph? LOG_WARNING: LOG_TRACE),
336 "%s on %s is unrunnable (node is offline)",
337 action->uuid, pe__node_name(action->node));
338 if (pcmk_is_set(action->rsc->flags, pe_rsc_managed)
339 && for_graph
340 && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
341 && !(action->node->details->unclean)) {
342 pe_fence_node(data_set, action->node, "stop is unrunnable", false);
343 }
344
345 } else if (!pcmk_is_set(action->flags, pe_action_dc)
346 && action->node->details->pending) {
348 do_crm_log((for_graph? LOG_WARNING: LOG_TRACE),
349 "Action %s on %s is unrunnable (node is pending)",
350 action->uuid, pe__node_name(action->node));
351
352 } else if (action->needs == rsc_req_nothing) {
353 pe_action_set_reason(action, NULL, TRUE);
354 if (pe__is_guest_node(action->node)
355 && !pe_can_fence(data_set, action->node)) {
356 /* An action that requires nothing usually does not require any
357 * fencing in order to be runnable. However, there is an exception:
358 * such an action cannot be completed if it is on a guest node whose
359 * host is unclean and cannot be fenced.
360 */
361 pe_rsc_debug(action->rsc, "%s on %s is unrunnable "
362 "(node's host cannot be fenced)",
363 action->uuid, pe__node_name(action->node));
365 } else {
366 pe_rsc_trace(action->rsc,
367 "%s on %s does not require fencing or quorum",
368 action->uuid, pe__node_name(action->node));
370 }
371
372 } else {
373 switch (effective_quorum_policy(action->rsc, data_set)) {
374 case no_quorum_stop:
375 pe_rsc_debug(action->rsc, "%s on %s is unrunnable (no quorum)",
376 action->uuid, pe__node_name(action->node));
378 pe_action_set_reason(action, "no quorum", true);
379 break;
380
381 case no_quorum_freeze:
382 if (!action->rsc->fns->active(action->rsc, TRUE)
383 || (action->rsc->next_role > action->rsc->role)) {
384 pe_rsc_debug(action->rsc,
385 "%s on %s is unrunnable (no quorum)",
386 action->uuid, pe__node_name(action->node));
388 pe_action_set_reason(action, "quorum freeze", true);
389 }
390 break;
391
392 default:
393 //pe_action_set_reason(action, NULL, TRUE);
395 break;
396 }
397 }
398}
399
407static void
408update_resource_flags_for_action(pe_resource_t *rsc, const pe_action_t *action)
409{
410 /* @COMPAT pe_rsc_starting and pe_rsc_stopping are not actually used
411 * within Pacemaker, and should be deprecated and eventually removed
412 */
413 if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
415
416 } else if (pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
419 } else {
421 }
422 }
423}
424
425static bool
426valid_stop_on_fail(const char *value)
427{
428 return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
429}
430
431static const char *
432unpack_operation_on_fail(pe_action_t * action)
433{
434 const char *name = NULL;
435 const char *role = NULL;
436 const char *on_fail = NULL;
437 const char *interval_spec = NULL;
438 const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
439
440 if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
441 && !valid_stop_on_fail(value)) {
442
443 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
444 "action to default value because '%s' is not "
445 "allowed for stop", action->rsc->id, value);
446 return NULL;
447
448 } else if (pcmk__str_eq(action->task, CRMD_ACTION_DEMOTE, pcmk__str_casei) && !value) {
449 // demote on_fail defaults to monitor value for promoted role if present
450 xmlNode *operation = NULL;
451
452 CRM_CHECK(action->rsc != NULL, return NULL);
453
454 for (operation = pcmk__xe_first_child(action->rsc->ops_xml);
455 (operation != NULL) && (value == NULL);
456 operation = pcmk__xe_next(operation)) {
457 bool enabled = false;
458
459 if (!pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
460 continue;
461 }
462 name = crm_element_value(operation, "name");
463 role = crm_element_value(operation, "role");
464 on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
465 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
466 if (!on_fail) {
467 continue;
468 } else if (pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok && !enabled) {
469 continue;
470 } else if (!pcmk__str_eq(name, "monitor", pcmk__str_casei)
473 NULL)) {
474 continue;
475 } else if (crm_parse_interval_spec(interval_spec) == 0) {
476 continue;
477 } else if (pcmk__str_eq(on_fail, "demote", pcmk__str_casei)) {
478 continue;
479 }
480
481 value = on_fail;
482 }
483 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
484 value = "ignore";
485
486 } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
487 name = crm_element_value(action->op_entry, "name");
488 role = crm_element_value(action->op_entry, "role");
489 interval_spec = crm_element_value(action->op_entry,
491
492 if (!pcmk__str_eq(name, CRMD_ACTION_PROMOTE, pcmk__str_casei)
493 && (!pcmk__str_eq(name, CRMD_ACTION_STATUS, pcmk__str_casei)
496 || (crm_parse_interval_spec(interval_spec) == 0))) {
497 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
498 "action to default value because 'demote' is not "
499 "allowed for it", action->rsc->id, name);
500 return NULL;
501 }
502 }
503
504 return value;
505}
506
507static int
508unpack_timeout(const char *value)
509{
510 int timeout_ms = crm_get_msec(value);
511
512 if (timeout_ms < 0) {
514 }
515 return timeout_ms;
516}
517
518// true if value contains valid, non-NULL interval origin for recurring op
519static bool
520unpack_interval_origin(const char *value, const xmlNode *xml_obj,
521 guint interval_ms, const crm_time_t *now,
522 long long *start_delay)
523{
524 long long result = 0;
525 guint interval_sec = interval_ms / 1000;
526 crm_time_t *origin = NULL;
527
528 // Ignore unspecified values and non-recurring operations
529 if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
530 return false;
531 }
532
533 // Parse interval origin from text
534 origin = crm_time_new(value);
535 if (origin == NULL) {
536 pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
537 "'%s' because '%s' is not valid",
538 (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
539 return false;
540 }
541
542 // Get seconds since origin (negative if origin is in the future)
544 crm_time_free(origin);
545
546 // Calculate seconds from closest interval to now
547 result = result % interval_sec;
548
549 // Calculate seconds remaining until next interval
550 result = ((result <= 0)? 0 : interval_sec) - result;
551 crm_info("Calculated a start delay of %llds for operation '%s'",
552 result,
553 (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
554
555 if (start_delay != NULL) {
556 *start_delay = result * 1000; // milliseconds
557 }
558 return true;
559}
560
561static int
562unpack_start_delay(const char *value, GHashTable *meta)
563{
564 int start_delay = 0;
565
566 if (value != NULL) {
567 start_delay = crm_get_msec(value);
568
569 if (start_delay < 0) {
570 start_delay = 0;
571 }
572
573 if (meta) {
574 g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
575 pcmk__itoa(start_delay));
576 }
577 }
578
579 return start_delay;
580}
581
582static xmlNode *
583find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
584{
585 guint interval_ms = 0;
586 guint min_interval_ms = G_MAXUINT;
587 const char *name = NULL;
588 const char *interval_spec = NULL;
589 xmlNode *op = NULL;
590 xmlNode *operation = NULL;
591
592 for (operation = pcmk__xe_first_child(rsc->ops_xml);
593 operation != NULL;
594 operation = pcmk__xe_next(operation)) {
595
596 if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
597 bool enabled = false;
598
599 name = crm_element_value(operation, "name");
600 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
601 if (!include_disabled && pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok &&
602 !enabled) {
603 continue;
604 }
605
606 if (!pcmk__str_eq(name, RSC_STATUS, pcmk__str_casei)) {
607 continue;
608 }
609
610 interval_ms = crm_parse_interval_spec(interval_spec);
611
612 if (interval_ms && (interval_ms < min_interval_ms)) {
613 min_interval_ms = interval_ms;
614 op = operation;
615 }
616 }
617 }
618
619 return op;
620}
621
635static void
636unpack_operation(pe_action_t *action, const xmlNode *xml_obj,
637 const pe_resource_t *container,
638 pe_working_set_t *data_set, guint interval_ms)
639{
640 int timeout_ms = 0;
641 const char *value = NULL;
642 bool is_probe = false;
643
644 pe_rsc_eval_data_t rsc_rule_data = {
646 .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER),
647 .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE)
648 };
649
650 pe_op_eval_data_t op_rule_data = {
651 .op_name = action->task,
652 .interval = interval_ms
653 };
654
655 pe_rule_eval_data_t rule_data = {
656 .node_hash = NULL,
657 .role = RSC_ROLE_UNKNOWN,
658 .now = data_set->now,
659 .match_data = NULL,
660 .rsc_data = &rsc_rule_data,
661 .op_data = &op_rule_data
662 };
663
664 CRM_CHECK(action && action->rsc, return);
665
666 is_probe = pcmk_is_probe(action->task, interval_ms);
667
668 // Cluster-wide <op_defaults> <meta_attributes>
670 action->meta, NULL, FALSE, data_set);
671
672 // Determine probe default timeout differently
673 if (is_probe) {
674 xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
675
676 if (min_interval_mon) {
677 value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
678 if (value) {
679 crm_trace("\t%s: Setting default timeout to minimum-interval "
680 "monitor's timeout '%s'", action->uuid, value);
681 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
682 strdup(value));
683 }
684 }
685 }
686
687 if (xml_obj) {
688 xmlAttrPtr xIter = NULL;
689
690 // <op> <meta_attributes> take precedence over defaults
692 action->meta, NULL, TRUE, data_set);
693
694 /* Anything set as an <op> XML property has highest precedence.
695 * This ensures we use the name and interval from the <op> tag.
696 */
697 for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
698 const char *prop_name = (const char *)xIter->name;
699 const char *prop_value = crm_element_value(xml_obj, prop_name);
700
701 g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
702 }
703 }
704
705 g_hash_table_remove(action->meta, "id");
706
707 // Normalize interval to milliseconds
708 if (interval_ms > 0) {
709 g_hash_table_replace(action->meta, strdup(XML_LRM_ATTR_INTERVAL),
710 crm_strdup_printf("%u", interval_ms));
711 } else {
712 g_hash_table_remove(action->meta, XML_LRM_ATTR_INTERVAL);
713 }
714
715 /*
716 * Timeout order of precedence:
717 * 1. pcmk_monitor_timeout (if rsc has pcmk_ra_cap_fence_params
718 * and task is start or a probe; pcmk_monitor_timeout works
719 * by default for a recurring monitor)
720 * 2. explicit op timeout on the primitive
721 * 3. default op timeout
722 * a. if probe, then min-interval monitor's timeout
723 * b. else, in XML_CIB_TAG_OPCONFIG
724 * 4. CRM_DEFAULT_OP_TIMEOUT_S
725 *
726 * #1 overrides general rule of <op> XML property having highest
727 * precedence.
728 */
729 if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
731 && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
732 || is_probe)) {
733
734 GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
735
736 value = g_hash_table_lookup(params, "pcmk_monitor_timeout");
737
738 if (value) {
739 crm_trace("\t%s: Setting timeout to pcmk_monitor_timeout '%s', "
740 "overriding default", action->uuid, value);
741 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
742 strdup(value));
743 }
744 }
745
746 // Normalize timeout to positive milliseconds
747 value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
748 timeout_ms = unpack_timeout(value);
749 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
750 pcmk__itoa(timeout_ms));
751
752 if (!pcmk__strcase_any_of(action->task, RSC_START, RSC_PROMOTE, NULL)) {
753 action->needs = rsc_req_nothing;
754 value = "nothing (not start or promote)";
755
756 } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
757 action->needs = rsc_req_stonith;
758 value = "fencing";
759
760 } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
761 action->needs = rsc_req_quorum;
762 value = "quorum";
763
764 } else {
765 action->needs = rsc_req_nothing;
766 value = "nothing";
767 }
768 pe_rsc_trace(action->rsc, "%s requires %s", action->uuid, value);
769
770 value = unpack_operation_on_fail(action);
771
772 if (value == NULL) {
773
774 } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
775 action->on_fail = action_fail_block;
776 g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
777 value = "block"; // The above could destroy the original string
778
779 } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
780 action->on_fail = action_fail_fence;
781 value = "node fencing";
782
784 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
785 "operation '%s' to 'stop' because 'fence' is not "
786 "valid when fencing is disabled", action->uuid);
787 action->on_fail = action_fail_stop;
788 action->fail_role = RSC_ROLE_STOPPED;
789 value = "stop resource";
790 }
791
792 } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
793 action->on_fail = action_fail_standby;
794 value = "node standby";
795
796 } else if (pcmk__strcase_any_of(value, "ignore", PCMK__VALUE_NOTHING,
797 NULL)) {
798 action->on_fail = action_fail_ignore;
799 value = "ignore";
800
801 } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
802 action->on_fail = action_fail_migrate;
803 value = "force migration";
804
805 } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
806 action->on_fail = action_fail_stop;
807 action->fail_role = RSC_ROLE_STOPPED;
808 value = "stop resource";
809
810 } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
811 action->on_fail = action_fail_recover;
812 value = "restart (and possibly migrate)";
813
814 } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
815 if (container) {
817 value = "restart container (and possibly migrate)";
818
819 } else {
820 value = NULL;
821 }
822
823 } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
824 action->on_fail = action_fail_demote;
825 value = "demote instance";
826
827 } else {
828 pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
829 value = NULL;
830 }
831
832 /* defaults */
833 if (value == NULL && container) {
835 value = "restart container (and possibly migrate) (default)";
836
837 /* For remote nodes, ensure that any failure that results in dropping an
838 * active connection to the node results in fencing of the node.
839 *
840 * There are only two action failures that don't result in fencing.
841 * 1. probes - probe failures are expected.
842 * 2. start - a start failure indicates that an active connection does not already
843 * exist. The user can set op on-fail=fence if they really want to fence start
844 * failures. */
845 } else if (((value == NULL) || !pcmk_is_set(action->rsc->flags, pe_rsc_managed))
847 && !(pcmk__str_eq(action->task, CRMD_ACTION_STATUS, pcmk__str_casei)
848 && (interval_ms == 0))
849 && !pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
850
851 if (!pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
852 action->on_fail = action_fail_stop;
853 action->fail_role = RSC_ROLE_STOPPED;
854 value = "stop unmanaged remote node (enforcing default)";
855
856 } else {
858 value = "fence remote node (default)";
859 } else {
860 value = "recover remote node connection (default)";
861 }
862
863 if (action->rsc->remote_reconnect_ms) {
864 action->fail_role = RSC_ROLE_STOPPED;
865 }
867 }
868
869 } else if (value == NULL && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
871 action->on_fail = action_fail_fence;
872 value = "resource fence (default)";
873
874 } else {
875 action->on_fail = action_fail_block;
876 value = "resource block (default)";
877 }
878
879 } else if (value == NULL) {
880 action->on_fail = action_fail_recover;
881 value = "restart (and possibly migrate) (default)";
882 }
883
884 pe_rsc_trace(action->rsc, "%s failure handling: %s",
885 action->uuid, value);
886
887 value = NULL;
888 if (xml_obj != NULL) {
889 value = g_hash_table_lookup(action->meta, "role_after_failure");
890 if (value) {
892 "Support for role_after_failure is deprecated and will be removed in a future release");
893 }
894 }
895 if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
896 action->fail_role = text2role(value);
897 }
898 /* defaults */
899 if (action->fail_role == RSC_ROLE_UNKNOWN) {
900 if (pcmk__str_eq(action->task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
901 action->fail_role = RSC_ROLE_UNPROMOTED;
902 } else {
903 action->fail_role = RSC_ROLE_STARTED;
904 }
905 }
906 pe_rsc_trace(action->rsc, "%s failure results in: %s",
907 action->uuid, role2text(action->fail_role));
908
909 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
910 if (value) {
911 unpack_start_delay(value, action->meta);
912 } else {
913 long long start_delay = 0;
914
915 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
916 if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
917 &start_delay)) {
918 g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
919 crm_strdup_printf("%lld", start_delay));
920 }
921 }
922}
923
942custom_action(pe_resource_t *rsc, char *key, const char *task,
943 const pe_node_t *on_node, gboolean optional, gboolean save_action,
945{
946 pe_action_t *action = NULL;
947
948 CRM_ASSERT((key != NULL) && (task != NULL) && (data_set != NULL));
949
950 if (save_action) {
951 action = find_existing_action(key, rsc, on_node, data_set);
952 }
953
954 if (action == NULL) {
955 action = new_action(key, task, rsc, on_node, optional, save_action,
956 data_set);
957 } else {
958 free(key);
959 }
960
961 update_action_optional(action, optional);
962
963 if (rsc != NULL) {
964 if (action->node != NULL) {
965 unpack_action_node_attributes(action, data_set);
966 }
967
968 update_resource_action_runnable(action, save_action, data_set);
969
970 if (save_action) {
971 update_resource_flags_for_action(rsc, action);
972 }
973 }
974
975 return action;
976}
977
980{
981 pe_action_t *op = lookup_singleton(data_set, name);
982
983 if (op == NULL) {
984 op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
986 }
987 return op;
988}
989
990static GList *
991find_unfencing_devices(GList *candidates, GList *matches)
992{
993 for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
994 pe_resource_t *candidate = gIter->data;
995
996 if (candidate->children != NULL) {
997 matches = find_unfencing_devices(candidate->children, matches);
998
999 } else if (!pcmk_is_set(candidate->flags, pe_rsc_fence_device)) {
1000 continue;
1001
1002 } else if (pcmk_is_set(candidate->flags, pe_rsc_needs_unfencing)) {
1003 matches = g_list_prepend(matches, candidate);
1004
1005 } else if (pcmk__str_eq(g_hash_table_lookup(candidate->meta,
1008 pcmk__str_casei)) {
1009 matches = g_list_prepend(matches, candidate);
1010 }
1011 }
1012 return matches;
1013}
1014
1015static int
1016node_priority_fencing_delay(const pe_node_t *node,
1018{
1019 int member_count = 0;
1020 int online_count = 0;
1021 int top_priority = 0;
1022 int lowest_priority = 0;
1023 GList *gIter = NULL;
1024
1025 // `priority-fencing-delay` is disabled
1026 if (data_set->priority_fencing_delay <= 0) {
1027 return 0;
1028 }
1029
1030 /* No need to request a delay if the fencing target is not a normal cluster
1031 * member, for example if it's a remote node or a guest node. */
1032 if (node->details->type != node_member) {
1033 return 0;
1034 }
1035
1036 // No need to request a delay if the fencing target is in our partition
1037 if (node->details->online) {
1038 return 0;
1039 }
1040
1041 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1042 pe_node_t *n = gIter->data;
1043
1044 if (n->details->type != node_member) {
1045 continue;
1046 }
1047
1048 member_count ++;
1049
1050 if (n->details->online) {
1051 online_count++;
1052 }
1053
1054 if (member_count == 1
1055 || n->details->priority > top_priority) {
1056 top_priority = n->details->priority;
1057 }
1058
1059 if (member_count == 1
1060 || n->details->priority < lowest_priority) {
1061 lowest_priority = n->details->priority;
1062 }
1063 }
1064
1065 // No need to delay if we have more than half of the cluster members
1066 if (online_count > member_count / 2) {
1067 return 0;
1068 }
1069
1070 /* All the nodes have equal priority.
1071 * Any configured corresponding `pcmk_delay_base/max` will be applied. */
1072 if (lowest_priority == top_priority) {
1073 return 0;
1074 }
1075
1076 if (node->details->priority < top_priority) {
1077 return 0;
1078 }
1079
1081}
1082
1084pe_fence_op(pe_node_t *node, const char *op, bool optional,
1085 const char *reason, bool priority_delay, pe_working_set_t *data_set)
1086{
1087 char *op_key = NULL;
1088 pe_action_t *stonith_op = NULL;
1089
1090 if(op == NULL) {
1092 }
1093
1094 op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
1095
1096 stonith_op = lookup_singleton(data_set, op_key);
1097 if(stonith_op == NULL) {
1098 stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
1099
1100 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1102 add_hash_param(stonith_op->meta, "stonith_action", op);
1103
1105 /* Extra work to detect device changes
1106 */
1107 GString *digests_all = g_string_sized_new(1024);
1108 GString *digests_secure = g_string_sized_new(1024);
1109
1110 GList *matches = find_unfencing_devices(data_set->resources, NULL);
1111
1112 char *key = NULL;
1113 char *value = NULL;
1114
1115 for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
1116 pe_resource_t *match = gIter->data;
1117 const char *agent = g_hash_table_lookup(match->meta,
1119 op_digest_cache_t *data = NULL;
1120
1121 data = pe__compare_fencing_digest(match, agent, node, data_set);
1122 if(data->rc == RSC_DIGEST_ALL) {
1123 optional = FALSE;
1124 crm_notice("Unfencing node %s because the definition of "
1125 "%s changed", pe__node_name(node), match->id);
1126 if (!pcmk__is_daemon && data_set->priv != NULL) {
1128
1129 out->info(out,
1130 "notice: Unfencing node %s because the "
1131 "definition of %s changed",
1132 pe__node_name(node), match->id);
1133 }
1134 }
1135
1136 pcmk__g_strcat(digests_all,
1137 match->id, ":", agent, ":",
1138 data->digest_all_calc, ",", NULL);
1139 pcmk__g_strcat(digests_secure,
1140 match->id, ":", agent, ":",
1141 data->digest_secure_calc, ",", NULL);
1142 }
1143 key = strdup(XML_OP_ATTR_DIGESTS_ALL);
1144 value = strdup((const char *) digests_all->str);
1145 CRM_ASSERT((key != NULL) && (value != NULL));
1146 g_hash_table_insert(stonith_op->meta, key, value);
1147 g_string_free(digests_all, TRUE);
1148
1149 key = strdup(XML_OP_ATTR_DIGESTS_SECURE);
1150 value = strdup((const char *) digests_secure->str);
1151 CRM_ASSERT((key != NULL) && (value != NULL));
1152 g_hash_table_insert(stonith_op->meta, key, value);
1153 g_string_free(digests_secure, TRUE);
1154 }
1155
1156 } else {
1157 free(op_key);
1158 }
1159
1161
1162 /* It's a suitable case where `priority-fencing-delay` applies.
1163 * At least add `priority-fencing-delay` field as an indicator. */
1164 && (priority_delay
1165
1166 /* The priority delay needs to be recalculated if this function has
1167 * been called by schedule_fencing_and_shutdowns() after node
1168 * priority has already been calculated by native_add_running().
1169 */
1170 || g_hash_table_lookup(stonith_op->meta,
1172
1173 /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
1174 * the targeting node. So that it takes precedence over any possible
1175 * `pcmk_delay_base/max`.
1176 */
1177 char *delay_s = pcmk__itoa(node_priority_fencing_delay(node, data_set));
1178
1179 g_hash_table_insert(stonith_op->meta,
1181 delay_s);
1182 }
1183
1184 if(optional == FALSE && pe_can_fence(data_set, node)) {
1186 pe_action_set_reason(stonith_op, reason, false);
1187
1188 } else if(reason && stonith_op->reason == NULL) {
1189 stonith_op->reason = strdup(reason);
1190 }
1191
1192 return stonith_op;
1193}
1194
1195void
1197{
1198 if (action == NULL) {
1199 return;
1200 }
1201 g_list_free_full(action->actions_before, free); /* pe_action_wrapper_t* */
1202 g_list_free_full(action->actions_after, free); /* pe_action_wrapper_t* */
1203 if (action->extra) {
1204 g_hash_table_destroy(action->extra);
1205 }
1206 if (action->meta) {
1207 g_hash_table_destroy(action->meta);
1208 }
1209 free(action->cancel_task);
1210 free(action->reason);
1211 free(action->task);
1212 free(action->uuid);
1213 free(action->node);
1214 free(action);
1215}
1216
1217int
1219{
1220 xmlNode *child = NULL;
1221 GHashTable *action_meta = NULL;
1222 const char *timeout_spec = NULL;
1223 int timeout_ms = 0;
1224
1225 pe_rule_eval_data_t rule_data = {
1226 .node_hash = NULL,
1227 .role = RSC_ROLE_UNKNOWN,
1228 .now = data_set->now,
1229 .match_data = NULL,
1230 .rsc_data = NULL,
1231 .op_data = NULL
1232 };
1233
1234 for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
1235 child != NULL; child = crm_next_same_xml(child)) {
1236 if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
1237 pcmk__str_casei)) {
1238 timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
1239 break;
1240 }
1241 }
1242
1243 if (timeout_spec == NULL && data_set->op_defaults) {
1244 action_meta = pcmk__strkey_table(free, free);
1246 &rule_data, action_meta, NULL, FALSE, data_set);
1247 timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
1248 }
1249
1250 // @TODO check meta-attributes
1251 // @TODO maybe use min-interval monitor timeout as default for monitors
1252
1253 timeout_ms = crm_get_msec(timeout_spec);
1254 if (timeout_ms < 0) {
1256 }
1257
1258 if (action_meta != NULL) {
1259 g_hash_table_destroy(action_meta);
1260 }
1261 return timeout_ms;
1262}
1263
1264enum action_tasks
1265get_complex_task(const pe_resource_t *rsc, const char *name)
1266{
1267 enum action_tasks task = text2task(name);
1268
1269 if ((rsc != NULL) && (rsc->variant == pe_native)) {
1270 switch (task) {
1271 case stopped_rsc:
1272 case started_rsc:
1273 case action_demoted:
1274 case action_promoted:
1275 crm_trace("Folding %s back into its atomic counterpart for %s",
1276 name, rsc->id);
1277 --task;
1278 break;
1279 default:
1280 break;
1281 }
1282 }
1283 return task;
1284}
1285
1298find_first_action(const GList *input, const char *uuid, const char *task,
1299 const pe_node_t *on_node)
1300{
1301 CRM_CHECK(uuid || task, return NULL);
1302
1303 for (const GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1304 pe_action_t *action = (pe_action_t *) gIter->data;
1305
1306 if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1307 continue;
1308
1309 } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1310 continue;
1311
1312 } else if (on_node == NULL) {
1313 return action;
1314
1315 } else if (action->node == NULL) {
1316 continue;
1317
1318 } else if (on_node->details == action->node->details) {
1319 return action;
1320 }
1321 }
1322
1323 return NULL;
1324}
1325
1326GList *
1327find_actions(GList *input, const char *key, const pe_node_t *on_node)
1328{
1329 GList *gIter = input;
1330 GList *result = NULL;
1331
1332 CRM_CHECK(key != NULL, return NULL);
1333
1334 for (; gIter != NULL; gIter = gIter->next) {
1335 pe_action_t *action = (pe_action_t *) gIter->data;
1336
1337 if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1338 continue;
1339
1340 } else if (on_node == NULL) {
1341 crm_trace("Action %s matches (ignoring node)", key);
1342 result = g_list_prepend(result, action);
1343
1344 } else if (action->node == NULL) {
1345 crm_trace("Action %s matches (unallocated, assigning to %s)",
1346 key, pe__node_name(on_node));
1347
1348 action->node = pe__copy_node(on_node);
1349 result = g_list_prepend(result, action);
1350
1351 } else if (on_node->details == action->node->details) {
1352 crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1353 result = g_list_prepend(result, action);
1354 }
1355 }
1356
1357 return result;
1358}
1359
1360GList *
1361find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1362{
1363 GList *result = NULL;
1364
1365 CRM_CHECK(key != NULL, return NULL);
1366
1367 if (on_node == NULL) {
1368 return NULL;
1369 }
1370
1371 for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1372 pe_action_t *action = (pe_action_t *) gIter->data;
1373
1374 if ((action->node != NULL)
1375 && pcmk__str_eq(key, action->uuid, pcmk__str_casei)
1376 && pcmk__str_eq(on_node->details->id, action->node->details->id,
1377 pcmk__str_casei)) {
1378
1379 crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1380 result = g_list_prepend(result, action);
1381 }
1382 }
1383
1384 return result;
1385}
1386
1399GList *
1401 const char *task, bool require_node)
1402{
1403 GList *result = NULL;
1404 char *key = pcmk__op_key(rsc->id, task, 0);
1405
1406 if (require_node) {
1407 result = find_actions_exact(rsc->actions, key, node);
1408 } else {
1409 result = find_actions(rsc->actions, key, node);
1410 }
1411 free(key);
1412 return result;
1413}
1414
1425char *
1427{
1428 const char *change = NULL;
1429
1430 switch (flag) {
1431 case pe_action_runnable:
1433 change = "unrunnable";
1434 break;
1435 case pe_action_optional:
1436 change = "required";
1437 break;
1438 default:
1439 // Bug: caller passed unsupported flag
1440 CRM_CHECK(change != NULL, change = "");
1441 break;
1442 }
1443 return crm_strdup_printf("%s%s%s %s", change,
1444 (action->rsc == NULL)? "" : " ",
1445 (action->rsc == NULL)? "" : action->rsc->id,
1446 action->task);
1447}
1448
1449void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
1450{
1451 if (action->reason != NULL && overwrite) {
1452 pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
1453 action->uuid, action->reason, pcmk__s(reason, "(none)"));
1454 } else if (action->reason == NULL) {
1455 pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
1456 action->uuid, pcmk__s(reason, "(none)"));
1457 } else {
1458 // crm_assert(action->reason != NULL && !overwrite);
1459 return;
1460 }
1461
1462 pcmk__str_update(&action->reason, reason);
1463}
1464
1478{
1479 char *key = NULL;
1480
1481 CRM_ASSERT(rsc && node);
1482 key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
1483 return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
1484 data_set);
1485}
1486
1487#define sort_return(an_int, why) do { \
1488 free(a_uuid); \
1489 free(b_uuid); \
1490 crm_trace("%s (%d) %c %s (%d) : %s", \
1491 a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1492 b_xml_id, b_call_id, why); \
1493 return an_int; \
1494 } while(0)
1495
1496int
1497pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b,
1498 bool same_node_default)
1499{
1500 int a_call_id = -1;
1501 int b_call_id = -1;
1502
1503 char *a_uuid = NULL;
1504 char *b_uuid = NULL;
1505
1506 const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1507 const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1508
1509 const char *a_node = crm_element_value(xml_a, XML_LRM_ATTR_TARGET);
1510 const char *b_node = crm_element_value(xml_b, XML_LRM_ATTR_TARGET);
1511 bool same_node = true;
1512
1513 /* @COMPAT The on_node attribute was added to last_failure as of 1.1.13 (via
1514 * 8b3ca1c) and the other entries as of 1.1.12 (via 0b07b5c).
1515 *
1516 * In case that any of the lrm_rsc_op entries doesn't have on_node
1517 * attribute, we need to explicitly tell whether the two operations are on
1518 * the same node.
1519 */
1520 if (a_node == NULL || b_node == NULL) {
1521 same_node = same_node_default;
1522
1523 } else {
1524 same_node = pcmk__str_eq(a_node, b_node, pcmk__str_casei);
1525 }
1526
1527 if (same_node && pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_none)) {
1528 /* We have duplicate lrm_rsc_op entries in the status
1529 * section which is unlikely to be a good thing
1530 * - we can handle it easily enough, but we need to get
1531 * to the bottom of why it's happening.
1532 */
1533 pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1534 sort_return(0, "duplicate");
1535 }
1536
1537 crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1538 crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1539
1540 if (a_call_id == -1 && b_call_id == -1) {
1541 /* both are pending ops so it doesn't matter since
1542 * stops are never pending
1543 */
1544 sort_return(0, "pending");
1545
1546 } else if (same_node && a_call_id >= 0 && a_call_id < b_call_id) {
1547 sort_return(-1, "call id");
1548
1549 } else if (same_node && b_call_id >= 0 && a_call_id > b_call_id) {
1550 sort_return(1, "call id");
1551
1552 } else if (a_call_id >= 0 && b_call_id >= 0
1553 && (!same_node || a_call_id == b_call_id)) {
1554 /*
1555 * The op and last_failed_op are the same
1556 * Order on last-rc-change
1557 */
1558 time_t last_a = -1;
1559 time_t last_b = -1;
1560
1563
1564 crm_trace("rc-change: %lld vs %lld",
1565 (long long) last_a, (long long) last_b);
1566 if (last_a >= 0 && last_a < last_b) {
1567 sort_return(-1, "rc-change");
1568
1569 } else if (last_b >= 0 && last_a > last_b) {
1570 sort_return(1, "rc-change");
1571 }
1572 sort_return(0, "rc-change");
1573
1574 } else {
1575 /* One of the inputs is a pending operation
1576 * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1577 */
1578
1579 int a_id = -1;
1580 int b_id = -1;
1581
1582 const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1583 const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1584
1585 CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1586 if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1587 NULL)) {
1588 sort_return(0, "bad magic a");
1589 }
1590 if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1591 NULL)) {
1592 sort_return(0, "bad magic b");
1593 }
1594 /* try to determine the relative age of the operation...
1595 * some pending operations (e.g. a start) may have been superseded
1596 * by a subsequent stop
1597 *
1598 * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1599 */
1600 if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1601 /*
1602 * some of the logic in here may be redundant...
1603 *
1604 * if the UUID from the TE doesn't match then one better
1605 * be a pending operation.
1606 * pending operations don't survive between elections and joins
1607 * because we query the LRM directly
1608 */
1609
1610 if (b_call_id == -1) {
1611 sort_return(-1, "transition + call");
1612
1613 } else if (a_call_id == -1) {
1614 sort_return(1, "transition + call");
1615 }
1616
1617 } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1618 sort_return(-1, "transition");
1619
1620 } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1621 sort_return(1, "transition");
1622 }
1623 }
1624
1625 /* we should never end up here */
1626 CRM_CHECK(FALSE, sort_return(0, "default"));
1627}
1628
1629gint
1630sort_op_by_callid(gconstpointer a, gconstpointer b)
1631{
1632 const xmlNode *xml_a = a;
1633 const xmlNode *xml_b = b;
1634
1635 return pe__is_newer_op(xml_a, xml_b, true);
1636}
1637
1650pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional,
1651 bool runnable)
1652{
1653 pe_action_t *action = NULL;
1654
1655 CRM_ASSERT((rsc != NULL) && (task != NULL));
1656
1657 action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0), task, NULL,
1658 optional, TRUE, rsc->cluster);
1660 if (runnable) {
1662 }
1663 return action;
1664}
1665
1675void
1677{
1678 char *name = NULL;
1679
1680 CRM_ASSERT((action != NULL) && (action->meta != NULL));
1681
1682 name = strdup(XML_ATTR_TE_TARGET_RC);
1683 CRM_ASSERT (name != NULL);
1684
1685 g_hash_table_insert(action->meta, name, pcmk__itoa(expected_result));
1686}
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:31
@ pcmk_ra_cap_fence_params
Definition agents.h:65
#define PCMK_STONITH_PROVIDES
Definition agents.h:48
const char * name
Definition cib.c:24
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition nvpair.c:927
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition operations.c:42
bool pcmk__is_daemon
Definition logging.c:47
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition operations.c:96
bool pcmk_is_probe(const char *task, guint interval)
Definition operations.c:495
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition utils.c:271
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition strings.c:364
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition util.h:76
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Parse a transition magic string into its constituent parts.
Definition operations.c:209
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:121
@ rsc_req_quorum
Definition common.h:87
@ rsc_req_stonith
Definition common.h:88
@ rsc_req_nothing
Definition common.h:86
enum action_tasks text2task(const char *task)
Definition common.c:349
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition common.h:116
@ action_fail_block
Definition common.h:40
@ action_fail_reset_remote
Definition common.h:55
@ action_fail_migrate
Definition common.h:39
@ action_fail_ignore
Definition common.h:34
@ action_fail_restart_container
Definition common.h:47
@ action_fail_fence
Definition common.h:43
@ action_fail_standby
Definition common.h:42
@ action_fail_demote
Definition common.h:57
@ action_fail_stop
Definition common.h:41
@ action_fail_recover
Definition common.h:36
const char * role2text(enum rsc_role_e role)
Definition common.c:450
action_tasks
Definition common.h:61
@ started_rsc
Definition common.h:67
@ action_demoted
Definition common.h:73
@ action_promoted
Definition common.h:71
@ stopped_rsc
Definition common.h:65
@ RSC_ROLE_STARTED
Definition common.h:95
@ RSC_ROLE_STOPPED
Definition common.h:94
@ RSC_ROLE_PROMOTED
Definition common.h:97
@ RSC_ROLE_UNKNOWN
Definition common.h:93
@ RSC_ROLE_UNPROMOTED
Definition common.h:96
#define RSC_ROLE_PROMOTED_S
Definition common.h:114
enum rsc_role_e text2role(const char *role)
Definition common.c:479
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition complex.c:436
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
A dumping ground.
#define CRMD_ACTION_STOP
Definition crm.h:177
#define RSC_PROMOTE
Definition crm.h:205
#define CRMD_ACTION_MIGRATED
Definition crm.h:172
#define CRMD_ACTION_STATUS
Definition crm.h:188
#define RSC_START
Definition crm.h:199
#define CRMD_ACTION_DEMOTE
Definition crm.h:182
#define CRMD_ACTION_MIGRATE
Definition crm.h:171
#define CRMD_ACTION_START
Definition crm.h:174
#define RSC_STATUS
Definition crm.h:213
#define CRM_OP_LRM_DELETE
Definition crm.h:149
#define CRMD_ACTION_PROMOTE
Definition crm.h:180
#define CRM_OP_FENCE
Definition crm.h:144
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:150
long long crm_time_get_seconds(const crm_time_t *dt)
Definition iso8601.c:316
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:109
struct crm_time_s crm_time_t
Definition iso8601.h:32
#define crm_info(fmt, args...)
Definition logging.h:378
#define do_crm_log(level, fmt, args...)
Log a message.
Definition logging.h:172
#define CRM_LOG_ASSERT(expr)
Definition logging.h:219
#define crm_notice(fmt, args...)
Definition logging.h:377
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define crm_trace(fmt, args...)
Definition logging.h:381
#define LOG_TRACE
Definition logging.h:37
#define pcmk__config_err(fmt...)
#define ID(x)
Definition msg_xml.h:480
#define XML_EXPR_ATTR_TYPE
Definition msg_xml.h:360
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition msg_xml.h:415
#define XML_LRM_ATTR_TARGET_UUID
Definition msg_xml.h:318
#define XML_TAG_ATTR_SETS
Definition msg_xml.h:222
#define XML_ATTR_ID
Definition msg_xml.h:147
#define XML_LRM_ATTR_INTERVAL
Definition msg_xml.h:309
#define XML_ATTR_TRANSITION_MAGIC
Definition msg_xml.h:424
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:283
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:282
#define XML_TAG_META_SETS
Definition msg_xml.h:223
#define XML_OP_ATTR_DIGESTS_ALL
Definition msg_xml.h:275
#define XML_ATTR_TYPE
Definition msg_xml.h:151
#define XML_NVPAIR_ATTR_NAME
Definition msg_xml.h:403
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:317
#define XML_ATTR_TIMEOUT
Definition msg_xml.h:141
#define XML_OP_ATTR_ON_FAIL
Definition msg_xml.h:270
#define XML_RSC_OP_LAST_CHANGE
Definition msg_xml.h:335
#define XML_OP_ATTR_DIGESTS_SECURE
Definition msg_xml.h:276
#define XML_OP_ATTR_ORIGIN
Definition msg_xml.h:273
#define XML_LRM_ATTR_CALLID
Definition msg_xml.h:327
#define XML_ATTR_OP
Definition msg_xml.h:153
#define XML_OP_ATTR_START_DELAY
Definition msg_xml.h:271
#define XML_ATTR_TE_TARGET_RC
Definition msg_xml.h:428
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:313
pe_working_set_t * data_set
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:532
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition nvpair.c:617
#define PCMK__VALUE_UNFENCING
#define PCMK__VALUE_NOTHING
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
enum action_tasks get_complex_task(const pe_resource_t *rsc, const char *name)
GList * find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, const pe_node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set)
Create or update an action object.
Definition pe_actions.c:942
char * pe__action2reason(const pe_action_t *action, enum pe_action_flags flag)
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition pe_actions.c:979
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
void pe_free_action(pe_action_t *action)
pe_action_t * pe_fence_op(pe_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pe_working_set_t *data_set)
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
#define sort_return(an_int, why)
void pe__add_action_expected_result(pe_action_t *action, int expected_result)
xmlNode * find_rsc_op_entry(const pe_resource_t *rsc, const char *key)
Definition pe_actions.c:145
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
int pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
op_digest_cache_t * pe__compare_fencing_digest(pe_resource_t *rsc, const char *agent, pe_node_t *node, pe_working_set_t *data_set)
Definition pe_digest.c:533
pe_quorum_policy
Definition pe_types.h:79
@ no_quorum_demote
Definition pe_types.h:84
@ no_quorum_freeze
Definition pe_types.h:80
@ no_quorum_ignore
Definition pe_types.h:82
@ no_quorum_stop
Definition pe_types.h:81
#define pe_rsc_stopping
Definition pe_types.h:301
#define pe_rsc_starting
Definition pe_types.h:298
#define pe_rsc_needs_quorum
Definition pe_types.h:311
#define pe_rsc_fence_device
Definition pe_types.h:279
#define pe_rsc_needs_unfencing
Definition pe_types.h:313
#define pe_flag_have_quorum
Definition pe_types.h:111
#define pe_rsc_managed
Definition pe_types.h:273
#define pe_flag_enable_unfencing
Definition pe_types.h:117
@ node_member
Definition pe_types.h:89
pe_action_flags
Definition pe_types.h:316
@ pe_action_optional
Definition pe_types.h:319
@ pe_action_runnable
Definition pe_types.h:318
@ pe_action_pseudo
Definition pe_types.h:317
@ pe_action_have_node_attrs
Definition pe_types.h:322
@ pe_action_dc
Internal state tracking when creating graph.
Definition pe_types.h:342
@ pe_action_migrate_runnable
Definition pe_types.h:324
@ pe_native
Definition pe_types.h:38
#define pe_flag_stonith_enabled
Definition pe_types.h:115
#define pe_rsc_needs_fencing
Definition pe_types.h:312
#define pe_warn_once(pe_wo_bit, fmt...)
Definition internal.h:177
void pe_fence_node(pe_working_set_t *data_set, pe_node_t *node, const char *reason, bool priority_delay)
Schedule a fence action for a node.
Definition unpack.c:113
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1166
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:83
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:49
@ pe_wo_role_after
Definition internal.h:160
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:50
@ RSC_DIGEST_ALL
Definition internal.h:501
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:77
void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition utils.c:737
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:98
bool pe_can_fence(const pe_working_set_t *data_set, const pe_node_t *node)
Definition utils.c:36
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition utils.c:89
#define pe_err(fmt...)
Definition internal.h:52
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:89
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:500
bool pe__is_guest_node(const pe_node_t *node)
Definition remote.c:33
bool pe__resource_is_remote_conn(const pe_resource_t *rsc, const pe_working_set_t *data_set)
Definition remote.c:17
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:151
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:611
void pcmk__str_update(char **str, const char *value)
Definition strings.c:1193
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ pcmk__str_none
@ pcmk__str_casei
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1217
This structure contains everything that makes up a single output formatter.
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
char * reason
Definition pe_types.h:440
GHashTable * meta
Definition pe_types.h:447
struct pe_node_shared_s * details
Definition pe_types.h:268
const char * id
Definition pe_types.h:231
gboolean online
Definition pe_types.h:236
const char * uname
Definition pe_types.h:232
enum node_type type
Definition pe_types.h:233
const char * op_name
Definition common.h:188
GList * actions
Definition pe_types.h:391
enum pe_obj_types variant
Definition pe_types.h:356
GHashTable * meta
Definition pe_types.h:405
GList * children
Definition pe_types.h:409
pe_working_set_t * cluster
Definition pe_types.h:353
pe_resource_t * container
Definition pe_types.h:412
char * clone_name
Definition pe_types.h:348
unsigned long long flags
Definition pe_types.h:373
enum rsc_role_e next_role
Definition pe_types.h:403
enum rsc_role_e role
Definition pe_types.h:402
xmlNode * ops_xml
Definition pe_types.h:351
const char * standard
Definition common.h:182
GHashTable * node_hash
Definition common.h:193
GHashTable * singletons
Definition pe_types.h:178
const char * stonith_action
Definition pe_types.h:166
GList * actions
Definition pe_types.h:187
GList * resources
Definition pe_types.h:181
unsigned long long flags
Definition pe_types.h:169
xmlNode * op_defaults
Definition pe_types.h:189
enum pe_quorum_policy no_quorum_policy
Definition pe_types.h:172
int priority_fencing_delay
Definition pe_types.h:213
crm_time_t * now
Definition pe_types.h:161
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2521
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition xml.c:2547