pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
utils.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 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#include <crm/crm.h>
12#include <crm/msg_xml.h>
13#include <crm/common/xml.h>
15#include <crm/common/util.h>
16
17#include <glib.h>
18#include <stdbool.h>
19
20#include <crm/pengine/rules.h>
22#include "pe_status_private.h"
23
24extern bool pcmk__is_daemon;
25
26extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
27void print_str_str(gpointer key, gpointer value, gpointer user_data);
28gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
29static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
30 pe_working_set_t * data_set, guint interval_ms);
31static xmlNode *find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key,
32 gboolean include_disabled);
33
34#if ENABLE_VERSIONED_ATTRS
35pe_rsc_action_details_t *
36pe_rsc_action_details(pe_action_t *action)
37{
38 pe_rsc_action_details_t *details;
39
40 CRM_CHECK(action != NULL, return NULL);
41
42 if (action->action_details == NULL) {
43 action->action_details = calloc(1, sizeof(pe_rsc_action_details_t));
44 CRM_CHECK(action->action_details != NULL, return NULL);
45 }
46
47 details = (pe_rsc_action_details_t *) action->action_details;
48 if (details->versioned_parameters == NULL) {
49 details->versioned_parameters = create_xml_node(NULL,
51 }
52 if (details->versioned_meta == NULL) {
53 details->versioned_meta = create_xml_node(NULL, XML_TAG_OP_VER_META);
54 }
55 return details;
56}
57
58static void
59pe_free_rsc_action_details(pe_action_t *action)
60{
61 pe_rsc_action_details_t *details;
62
63 if ((action == NULL) || (action->action_details == NULL)) {
64 return;
65 }
66
67 details = (pe_rsc_action_details_t *) action->action_details;
68
69 if (details->versioned_parameters) {
70 free_xml(details->versioned_parameters);
71 }
72 if (details->versioned_meta) {
73 free_xml(details->versioned_meta);
74 }
75
76 action->action_details = NULL;
77}
78#endif
79
89bool
91{
92 if (pe__is_guest_node(node)) {
93 /* Guest nodes are fenced by stopping their container resource. We can
94 * do that if the container's host is either online or fenceable.
95 */
97
98 for (GList *n = rsc->running_on; n != NULL; n = n->next) {
99 pe_node_t *container_node = n->data;
100
101 if (!container_node->details->online
102 && !pe_can_fence(data_set, container_node)) {
103 return false;
104 }
105 }
106 return true;
107
108 } else if (!pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
109 return false; /* Turned off */
110
111 } else if (!pcmk_is_set(data_set->flags, pe_flag_have_stonith_resource)) {
112 return false; /* No devices */
113
114 } else if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)) {
115 return true;
116
117 } else if (data_set->no_quorum_policy == no_quorum_ignore) {
118 return true;
119
120 } else if(node == NULL) {
121 return false;
122
123 } else if(node->details->online) {
124 crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
125 return true;
126 }
127
128 crm_trace("Cannot fence %s", node->details->uname);
129 return false;
130}
131
141pe_node_t *
142pe__copy_node(const pe_node_t *this_node)
143{
144 pe_node_t *new_node = NULL;
145
146 CRM_ASSERT(this_node != NULL);
147
148 new_node = calloc(1, sizeof(pe_node_t));
149 CRM_ASSERT(new_node != NULL);
150
151 new_node->rsc_discover_mode = this_node->rsc_discover_mode;
152 new_node->weight = this_node->weight;
153 new_node->fixed = this_node->fixed;
154 new_node->details = this_node->details;
155
156 return new_node;
157}
158
159/* any node in list1 or list2 and not in the other gets a score of -INFINITY */
160void
161node_list_exclude(GHashTable * hash, GList *list, gboolean merge_scores)
162{
163 GHashTable *result = hash;
164 pe_node_t *other_node = NULL;
165 GList *gIter = list;
166
167 GHashTableIter iter;
168 pe_node_t *node = NULL;
169
170 g_hash_table_iter_init(&iter, hash);
171 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
172
173 other_node = pe_find_node_id(list, node->details->id);
174 if (other_node == NULL) {
175 node->weight = -INFINITY;
176 } else if (merge_scores) {
177 node->weight = pe__add_scores(node->weight, other_node->weight);
178 }
179 }
180
181 for (; gIter != NULL; gIter = gIter->next) {
182 pe_node_t *node = (pe_node_t *) gIter->data;
183
184 other_node = pe_hash_table_lookup(result, node->details->id);
185
186 if (other_node == NULL) {
187 pe_node_t *new_node = pe__copy_node(node);
188
189 new_node->weight = -INFINITY;
190 g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
191 }
192 }
193}
194
203GHashTable *
205{
206 GHashTable *result = NULL;
207
208 result = pcmk__strkey_table(NULL, free);
209 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
210 pe_node_t *new_node = pe__copy_node((pe_node_t *) gIter->data);
211
212 g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
213 }
214 return result;
215}
216
217gint
218sort_node_uname(gconstpointer a, gconstpointer b)
219{
220 return pcmk__numeric_strcasecmp(((const pe_node_t *) a)->details->uname,
221 ((const pe_node_t *) b)->details->uname);
222}
223
232static void
233pe__output_node_weights(pe_resource_t *rsc, const char *comment,
234 GHashTable *nodes, pe_working_set_t *data_set)
235{
236 pcmk__output_t *out = data_set->priv;
237 char score[128]; // Stack-allocated since this is called frequently
238
239 // Sort the nodes so the output is consistent for regression tests
240 GList *list = g_list_sort(g_hash_table_get_values(nodes), sort_node_uname);
241
242 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
243 pe_node_t *node = (pe_node_t *) gIter->data;
244
245 score2char_stack(node->weight, score, sizeof(score));
246 out->message(out, "node-weight", rsc, comment, node->details->uname, score);
247 }
248 g_list_free(list);
249}
250
262static void
263pe__log_node_weights(const char *file, const char *function, int line,
264 pe_resource_t *rsc, const char *comment, GHashTable *nodes)
265{
266 GHashTableIter iter;
267 pe_node_t *node = NULL;
268 char score[128]; // Stack-allocated since this is called frequently
269
270 // Don't waste time if we're not tracing at this point
271 pcmk__log_else(LOG_TRACE, return);
272
273 g_hash_table_iter_init(&iter, nodes);
274 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
275 score2char_stack(node->weight, score, sizeof(score));
276 if (rsc) {
277 qb_log_from_external_source(function, file,
278 "%s: %s allocation score on %s: %s",
279 LOG_TRACE, line, 0,
280 comment, rsc->id,
281 node->details->uname, score);
282 } else {
283 qb_log_from_external_source(function, file, "%s: %s = %s",
284 LOG_TRACE, line, 0,
285 comment, node->details->uname,
286 score);
287 }
288 }
289}
290
303void
304pe__show_node_weights_as(const char *file, const char *function, int line,
305 bool to_log, pe_resource_t *rsc, const char *comment,
306 GHashTable *nodes, pe_working_set_t *data_set)
307{
308 if (rsc != NULL && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
309 // Don't show allocation scores for orphans
310 return;
311 }
312 if (nodes == NULL) {
313 // Nothing to show
314 return;
315 }
316
317 if (to_log) {
318 pe__log_node_weights(file, function, line, rsc, comment, nodes);
319 } else {
320 pe__output_node_weights(rsc, comment, nodes, data_set);
321 }
322
323 // If this resource has children, repeat recursively for each
324 if (rsc && rsc->children) {
325 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
326 pe_resource_t *child = (pe_resource_t *) gIter->data;
327
328 pe__show_node_weights_as(file, function, line, to_log, child,
329 comment, child->allowed_nodes, data_set);
330 }
331 }
332}
333
334gint
335sort_rsc_index(gconstpointer a, gconstpointer b)
336{
337 const pe_resource_t *resource1 = (const pe_resource_t *)a;
338 const pe_resource_t *resource2 = (const pe_resource_t *)b;
339
340 if (a == NULL && b == NULL) {
341 return 0;
342 }
343 if (a == NULL) {
344 return 1;
345 }
346 if (b == NULL) {
347 return -1;
348 }
349
350 if (resource1->sort_index > resource2->sort_index) {
351 return -1;
352 }
353
354 if (resource1->sort_index < resource2->sort_index) {
355 return 1;
356 }
357
358 return 0;
359}
360
361gint
362sort_rsc_priority(gconstpointer a, gconstpointer b)
363{
364 const pe_resource_t *resource1 = (const pe_resource_t *)a;
365 const pe_resource_t *resource2 = (const pe_resource_t *)b;
366
367 if (a == NULL && b == NULL) {
368 return 0;
369 }
370 if (a == NULL) {
371 return 1;
372 }
373 if (b == NULL) {
374 return -1;
375 }
376
377 if (resource1->priority > resource2->priority) {
378 return -1;
379 }
380
381 if (resource1->priority < resource2->priority) {
382 return 1;
383 }
384
385 return 0;
386}
387
388static enum pe_quorum_policy
389effective_quorum_policy(pe_resource_t *rsc, pe_working_set_t *data_set)
390{
391 enum pe_quorum_policy policy = data_set->no_quorum_policy;
392
393 if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)) {
394 policy = no_quorum_ignore;
395
396 } else if (data_set->no_quorum_policy == no_quorum_demote) {
397 switch (rsc->role) {
400 if (rsc->next_role > RSC_ROLE_UNPROMOTED) {
402 "no-quorum-policy=demote");
403 }
404 policy = no_quorum_ignore;
405 break;
406 default:
407 policy = no_quorum_stop;
408 break;
409 }
410 }
411 return policy;
412}
413
415custom_action(pe_resource_t * rsc, char *key, const char *task,
416 pe_node_t * on_node, gboolean optional, gboolean save_action,
417 pe_working_set_t * data_set)
418{
419 pe_action_t *action = NULL;
420 GList *possible_matches = NULL;
421
422 CRM_CHECK(key != NULL, return NULL);
423 CRM_CHECK(task != NULL, free(key); return NULL);
424
425 if (save_action && rsc != NULL) {
426 possible_matches = find_actions(rsc->actions, key, on_node);
427 } else if(save_action) {
428#if 0
429 action = g_hash_table_lookup(data_set->singletons, key);
430#else
431 /* More expensive but takes 'node' into account */
432 possible_matches = find_actions(data_set->actions, key, on_node);
433#endif
434 }
435
436 if(data_set->singletons == NULL) {
437 data_set->singletons = pcmk__strkey_table(NULL, NULL);
438 }
439
440 if (possible_matches != NULL) {
441 if (pcmk__list_of_multiple(possible_matches)) {
442 pe_warn("Action %s for %s on %s exists %d times",
443 task, rsc ? rsc->id : "<NULL>",
444 on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
445 }
446
447 action = g_list_nth_data(possible_matches, 0);
448 pe_rsc_trace(rsc, "Found action %d: %s for %s (%s) on %s",
449 action->id, task, (rsc? rsc->id : "no resource"),
450 action->uuid,
451 (on_node? on_node->details->uname : "no node"));
452 g_list_free(possible_matches);
453 }
454
455 if (action == NULL) {
456 if (save_action) {
457 pe_rsc_trace(rsc, "Creating action %d (%s): %s for %s (%s) on %s",
458 data_set->action_id,
459 (optional? "optional" : "required"),
460 task, (rsc? rsc->id : "no resource"), key,
461 (on_node? on_node->details->uname : "no node"));
462 }
463
464 action = calloc(1, sizeof(pe_action_t));
465 if (save_action) {
466 action->id = data_set->action_id++;
467 } else {
468 action->id = 0;
469 }
470 action->rsc = rsc;
471 action->task = strdup(task);
472 if (on_node) {
473 action->node = pe__copy_node(on_node);
474 }
475 action->uuid = strdup(key);
476
477 if (pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
478 // Resource history deletion for a node can be done on the DC
480 }
481
483 if (optional) {
485 } else {
487 }
488
489 action->extra = pcmk__strkey_table(free, free);
490 action->meta = pcmk__strkey_table(free, free);
491
492 if (save_action) {
493 data_set->actions = g_list_prepend(data_set->actions, action);
494 if(rsc == NULL) {
495 g_hash_table_insert(data_set->singletons, action->uuid, action);
496 }
497 }
498
499 if (rsc != NULL) {
500 guint interval_ms = 0;
501
502 action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
503 parse_op_key(key, NULL, NULL, &interval_ms);
504
505 unpack_operation(action, action->op_entry, rsc->container, data_set,
506 interval_ms);
507
508 if (save_action) {
509 rsc->actions = g_list_prepend(rsc->actions, action);
510 }
511 }
512 }
513
514 if (!optional && pcmk_is_set(action->flags, pe_action_optional)) {
516 }
517
518 if (rsc != NULL) {
519 enum action_tasks a_task = text2task(action->task);
520 enum pe_quorum_policy quorum_policy = effective_quorum_policy(rsc, data_set);
521 int warn_level = LOG_TRACE;
522
523 if (save_action) {
524 warn_level = LOG_WARNING;
525 }
526
528 && action->node != NULL && action->op_entry != NULL) {
529 pe_rule_eval_data_t rule_data = {
530 .node_hash = action->node->details->attrs,
531 .role = RSC_ROLE_UNKNOWN,
532 .now = data_set->now,
533 .match_data = NULL,
534 .rsc_data = NULL,
535 .op_data = NULL
536 };
537
540 &rule_data, action->extra, NULL,
541 FALSE, data_set);
542 }
543
544 // Make the action optional if its resource is unmanaged
546 && (action->node != NULL)
547 && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
548 && (g_hash_table_lookup(action->meta,
549 XML_LRM_ATTR_INTERVAL_MS) == NULL)) {
550 pe_rsc_debug(rsc, "%s on %s is optional (%s is unmanaged)",
551 action->uuid, action->node->details->uname,
552 action->rsc->id);
554 // We shouldn't clear runnable here because ... something
555 }
556
557 // Make the action runnable or unrunnable as appropriate
558 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
559 /* leave untouched */
560
561 } else if (action->node == NULL) {
562 pe_rsc_trace(rsc, "%s is unrunnable (unallocated)",
563 action->uuid);
565
566 } else if (!pcmk_is_set(action->flags, pe_action_dc)
567 && !(action->node->details->online)
568 && (!pe__is_guest_node(action->node)
569 || action->node->details->remote_requires_reset)) {
571 do_crm_log(warn_level,
572 "%s on %s is unrunnable (node is offline)",
573 action->uuid, action->node->details->uname);
574 if (pcmk_is_set(action->rsc->flags, pe_rsc_managed)
575 && save_action && a_task == stop_rsc
576 && action->node->details->unclean == FALSE) {
577 pe_fence_node(data_set, action->node, "resource actions are unrunnable", FALSE);
578 }
579
580 } else if (!pcmk_is_set(action->flags, pe_action_dc)
581 && action->node->details->pending) {
583 do_crm_log(warn_level,
584 "Action %s on %s is unrunnable (node is pending)",
585 action->uuid, action->node->details->uname);
586
587 } else if (action->needs == rsc_req_nothing) {
588 pe_action_set_reason(action, NULL, TRUE);
589 if (pe__is_guest_node(action->node)
590 && !pe_can_fence(data_set, action->node)) {
591 /* An action that requires nothing usually does not require any
592 * fencing in order to be runnable. However, there is an
593 * exception: an action cannot be completed if it is on a guest
594 * node whose host is unclean and cannot be fenced.
595 */
596 pe_rsc_debug(rsc, "%s on %s is unrunnable "
597 "(node's host cannot be fenced)",
598 action->uuid, action->node->details->uname);
600 } else {
601 pe_rsc_trace(rsc, "%s on %s does not require fencing or quorum",
602 action->uuid, action->node->details->uname);
604 }
605#if 0
606 /*
607 * No point checking this
608 * - if we don't have quorum we can't stonith anyway
609 */
610 } else if (action->needs == rsc_req_stonith) {
611 crm_trace("Action %s requires only stonith", action->uuid);
612 action->runnable = TRUE;
613#endif
614 } else if (quorum_policy == no_quorum_stop) {
615 pe_rsc_debug(rsc, "%s on %s is unrunnable (no quorum)",
616 action->uuid, action->node->details->uname);
617 pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
618 "no quorum", pe_action_runnable, TRUE);
619
620 } else if (quorum_policy == no_quorum_freeze) {
621 if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
622 pe_rsc_debug(rsc, "%s on %s is unrunnable (no quorum)",
623 action->uuid, action->node->details->uname);
624 pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
625 "quorum freeze", pe_action_runnable,
626 TRUE);
627 }
628
629 } else {
630 //pe_action_set_reason(action, NULL, TRUE);
632 }
633
634 if (save_action) {
635 switch (a_task) {
636 case stop_rsc:
638 break;
639 case start_rsc:
643 }
644 break;
645 default:
646 break;
647 }
648 }
649 }
650
651 free(key);
652 return action;
653}
654
655static bool
656valid_stop_on_fail(const char *value)
657{
658 return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
659}
660
661static const char *
662unpack_operation_on_fail(pe_action_t * action)
663{
664
665 const char *name = NULL;
666 const char *role = NULL;
667 const char *on_fail = NULL;
668 const char *interval_spec = NULL;
669 const char *enabled = NULL;
670 const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
671
672 if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
673 && !valid_stop_on_fail(value)) {
674
675 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
676 "action to default value because '%s' is not "
677 "allowed for stop", action->rsc->id, value);
678 return NULL;
679
680 } else if (pcmk__str_eq(action->task, CRMD_ACTION_DEMOTE, pcmk__str_casei) && !value) {
681 // demote on_fail defaults to monitor value for promoted role if present
682 xmlNode *operation = NULL;
683
684 CRM_CHECK(action->rsc != NULL, return NULL);
685
686 for (operation = pcmk__xe_first_child(action->rsc->ops_xml);
687 (operation != NULL) && (value == NULL);
688 operation = pcmk__xe_next(operation)) {
689
690 if (!pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
691 continue;
692 }
693 name = crm_element_value(operation, "name");
694 role = crm_element_value(operation, "role");
695 on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
696 enabled = crm_element_value(operation, "enabled");
697 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
698 if (!on_fail) {
699 continue;
700 } else if (enabled && !crm_is_true(enabled)) {
701 continue;
702 } else if (!pcmk__str_eq(name, "monitor", pcmk__str_casei)
705 NULL)) {
706 continue;
707 } else if (crm_parse_interval_spec(interval_spec) == 0) {
708 continue;
709 } else if (pcmk__str_eq(on_fail, "demote", pcmk__str_casei)) {
710 continue;
711 }
712
713 value = on_fail;
714 }
715 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
716 value = "ignore";
717
718 } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
719 name = crm_element_value(action->op_entry, "name");
720 role = crm_element_value(action->op_entry, "role");
721 interval_spec = crm_element_value(action->op_entry,
723
724 if (!pcmk__str_eq(name, CRMD_ACTION_PROMOTE, pcmk__str_casei)
725 && (!pcmk__str_eq(name, CRMD_ACTION_STATUS, pcmk__str_casei)
728 || (crm_parse_interval_spec(interval_spec) == 0))) {
729 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
730 "action to default value because 'demote' is not "
731 "allowed for it", action->rsc->id, name);
732 return NULL;
733 }
734 }
735
736 return value;
737}
738
739static xmlNode *
740find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
741{
742 guint interval_ms = 0;
743 guint min_interval_ms = G_MAXUINT;
744 const char *name = NULL;
745 const char *value = NULL;
746 const char *interval_spec = NULL;
747 xmlNode *op = NULL;
748 xmlNode *operation = NULL;
749
750 for (operation = pcmk__xe_first_child(rsc->ops_xml);
751 operation != NULL;
752 operation = pcmk__xe_next(operation)) {
753
754 if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
755 name = crm_element_value(operation, "name");
756 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
757 value = crm_element_value(operation, "enabled");
758 if (!include_disabled && value && crm_is_true(value) == FALSE) {
759 continue;
760 }
761
762 if (!pcmk__str_eq(name, RSC_STATUS, pcmk__str_casei)) {
763 continue;
764 }
765
766 interval_ms = crm_parse_interval_spec(interval_spec);
767
768 if (interval_ms && (interval_ms < min_interval_ms)) {
769 min_interval_ms = interval_ms;
770 op = operation;
771 }
772 }
773 }
774
775 return op;
776}
777
778static int
779unpack_start_delay(const char *value, GHashTable *meta)
780{
781 int start_delay = 0;
782
783 if (value != NULL) {
784 start_delay = crm_get_msec(value);
785
786 if (start_delay < 0) {
787 start_delay = 0;
788 }
789
790 if (meta) {
791 g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
792 pcmk__itoa(start_delay));
793 }
794 }
795
796 return start_delay;
797}
798
799// true if value contains valid, non-NULL interval origin for recurring op
800static bool
801unpack_interval_origin(const char *value, xmlNode *xml_obj, guint interval_ms,
802 crm_time_t *now, long long *start_delay)
803{
804 long long result = 0;
805 guint interval_sec = interval_ms / 1000;
806 crm_time_t *origin = NULL;
807
808 // Ignore unspecified values and non-recurring operations
809 if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
810 return false;
811 }
812
813 // Parse interval origin from text
814 origin = crm_time_new(value);
815 if (origin == NULL) {
816 pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
817 "'%s' because '%s' is not valid",
818 (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
819 return false;
820 }
821
822 // Get seconds since origin (negative if origin is in the future)
823 result = crm_time_get_seconds(now) - crm_time_get_seconds(origin);
824 crm_time_free(origin);
825
826 // Calculate seconds from closest interval to now
827 result = result % interval_sec;
828
829 // Calculate seconds remaining until next interval
830 result = ((result <= 0)? 0 : interval_sec) - result;
831 crm_info("Calculated a start delay of %llds for operation '%s'",
832 result,
833 (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
834
835 if (start_delay != NULL) {
836 *start_delay = result * 1000; // milliseconds
837 }
838 return true;
839}
840
841static int
842unpack_timeout(const char *value)
843{
844 int timeout_ms = crm_get_msec(value);
845
846 if (timeout_ms < 0) {
848 }
849 return timeout_ms;
850}
851
852int
854{
855 xmlNode *child = NULL;
856 GHashTable *action_meta = NULL;
857 const char *timeout_spec = NULL;
858 int timeout_ms = 0;
859
860 pe_rule_eval_data_t rule_data = {
861 .node_hash = NULL,
862 .role = RSC_ROLE_UNKNOWN,
863 .now = data_set->now,
864 .match_data = NULL,
865 .rsc_data = NULL,
866 .op_data = NULL
867 };
868
869 for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
870 child != NULL; child = crm_next_same_xml(child)) {
871 if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
873 timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
874 break;
875 }
876 }
877
878 if (timeout_spec == NULL && data_set->op_defaults) {
879 action_meta = pcmk__strkey_table(free, free);
881 &rule_data, action_meta, NULL, FALSE, data_set);
882 timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
883 }
884
885 // @TODO check meta-attributes (including versioned meta-attributes)
886 // @TODO maybe use min-interval monitor timeout as default for monitors
887
888 timeout_ms = crm_get_msec(timeout_spec);
889 if (timeout_ms < 0) {
891 }
892
893 if (action_meta != NULL) {
894 g_hash_table_destroy(action_meta);
895 }
896 return timeout_ms;
897}
898
899#if ENABLE_VERSIONED_ATTRS
900static void
901unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj,
902 guint interval_ms, crm_time_t *now)
903{
904 xmlNode *attrs = NULL;
905 xmlNode *attr = NULL;
906
907 for (attrs = pcmk__xe_first_child(versioned_meta); attrs != NULL;
908 attrs = pcmk__xe_next(attrs)) {
909
910 for (attr = pcmk__xe_first_child(attrs); attr != NULL;
911 attr = pcmk__xe_next(attr)) {
912
913 const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
914 const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
915
916 if (pcmk__str_eq(name, XML_OP_ATTR_START_DELAY, pcmk__str_casei)) {
917 int start_delay = unpack_start_delay(value, NULL);
918
919 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
920 } else if (pcmk__str_eq(name, XML_OP_ATTR_ORIGIN, pcmk__str_casei)) {
921 long long start_delay = 0;
922
923 if (unpack_interval_origin(value, xml_obj, interval_ms, now,
924 &start_delay)) {
927 crm_xml_add_ll(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
928 }
929 } else if (pcmk__str_eq(name, XML_ATTR_TIMEOUT, pcmk__str_casei)) {
930 int timeout_ms = unpack_timeout(value);
931
932 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout_ms);
933 }
934 }
935 }
936}
937#endif
938
952static void
953unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
954 pe_working_set_t * data_set, guint interval_ms)
955{
956 int timeout_ms = 0;
957 const char *value = NULL;
958 bool is_probe = pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)
959 && (interval_ms == 0);
960#if ENABLE_VERSIONED_ATTRS
961 pe_rsc_action_details_t *rsc_details = NULL;
962#endif
963
964 pe_rsc_eval_data_t rsc_rule_data = {
966 .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER),
967 .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE)
968 };
969
970 pe_op_eval_data_t op_rule_data = {
971 .op_name = action->task,
972 .interval = interval_ms
973 };
974
975 pe_rule_eval_data_t rule_data = {
976 .node_hash = NULL,
977 .role = RSC_ROLE_UNKNOWN,
978 .now = data_set->now,
979 .match_data = NULL,
980 .rsc_data = &rsc_rule_data,
981 .op_data = &op_rule_data
982 };
983
984 CRM_CHECK(action && action->rsc, return);
985
986 // Cluster-wide <op_defaults> <meta_attributes>
988 action->meta, NULL, FALSE, data_set);
989
990 // Determine probe default timeout differently
991 if (is_probe) {
992 xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
993
994 if (min_interval_mon) {
995 value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
996 if (value) {
997 crm_trace("\t%s: Setting default timeout to minimum-interval "
998 "monitor's timeout '%s'", action->uuid, value);
999 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
1000 strdup(value));
1001 }
1002 }
1003 }
1004
1005 if (xml_obj) {
1006 xmlAttrPtr xIter = NULL;
1007
1008 // <op> <meta_attributes> take precedence over defaults
1009 pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, &rule_data,
1010 action->meta, NULL, TRUE, data_set);
1011
1012#if ENABLE_VERSIONED_ATTRS
1013 rsc_details = pe_rsc_action_details(action);
1014
1015 pe_eval_versioned_attributes(data_set->input, xml_obj,
1016 XML_TAG_ATTR_SETS, &rule_data,
1017 rsc_details->versioned_parameters,
1018 NULL);
1019 pe_eval_versioned_attributes(data_set->input, xml_obj,
1020 XML_TAG_META_SETS, &rule_data,
1021 rsc_details->versioned_meta,
1022 NULL);
1023#endif
1024
1025 /* Anything set as an <op> XML property has highest precedence.
1026 * This ensures we use the name and interval from the <op> tag.
1027 */
1028 for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
1029 const char *prop_name = (const char *)xIter->name;
1030 const char *prop_value = crm_element_value(xml_obj, prop_name);
1031
1032 g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
1033 }
1034 }
1035
1036 g_hash_table_remove(action->meta, "id");
1037
1038 // Normalize interval to milliseconds
1039 if (interval_ms > 0) {
1040 g_hash_table_replace(action->meta, strdup(XML_LRM_ATTR_INTERVAL),
1041 crm_strdup_printf("%u", interval_ms));
1042 } else {
1043 g_hash_table_remove(action->meta, XML_LRM_ATTR_INTERVAL);
1044 }
1045
1046 /*
1047 * Timeout order of precedence:
1048 * 1. pcmk_monitor_timeout (if rsc has pcmk_ra_cap_fence_params
1049 * and task is start or a probe; pcmk_monitor_timeout works
1050 * by default for a recurring monitor)
1051 * 2. explicit op timeout on the primitive
1052 * 3. default op timeout
1053 * a. if probe, then min-interval monitor's timeout
1054 * b. else, in XML_CIB_TAG_OPCONFIG
1055 * 4. CRM_DEFAULT_OP_TIMEOUT_S
1056 *
1057 * #1 overrides general rule of <op> XML property having highest
1058 * precedence.
1059 */
1060 if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
1062 && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
1063 || is_probe)) {
1064
1065 GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
1066
1067 value = g_hash_table_lookup(params, "pcmk_monitor_timeout");
1068
1069 if (value) {
1070 crm_trace("\t%s: Setting timeout to pcmk_monitor_timeout '%s', "
1071 "overriding default", action->uuid, value);
1072 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
1073 strdup(value));
1074 }
1075 }
1076
1077 // Normalize timeout to positive milliseconds
1078 value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
1079 timeout_ms = unpack_timeout(value);
1080 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
1081 pcmk__itoa(timeout_ms));
1082
1083 if (!pcmk__strcase_any_of(action->task, RSC_START, RSC_PROMOTE, NULL)) {
1084 action->needs = rsc_req_nothing;
1085 value = "nothing (not start or promote)";
1086
1087 } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1088 action->needs = rsc_req_stonith;
1089 value = "fencing";
1090
1091 } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1092 action->needs = rsc_req_quorum;
1093 value = "quorum";
1094
1095 } else {
1096 action->needs = rsc_req_nothing;
1097 value = "nothing";
1098 }
1099 pe_rsc_trace(action->rsc, "%s requires %s", action->uuid, value);
1100
1101 value = unpack_operation_on_fail(action);
1102
1103 if (value == NULL) {
1104
1105 } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
1106 action->on_fail = action_fail_block;
1107 g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1108 value = "block"; // The above could destroy the original string
1109
1110 } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
1111 action->on_fail = action_fail_fence;
1112 value = "node fencing";
1113
1114 if (!pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1115 pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
1116 "operation '%s' to 'stop' because 'fence' is not "
1117 "valid when fencing is disabled", action->uuid);
1118 action->on_fail = action_fail_stop;
1119 action->fail_role = RSC_ROLE_STOPPED;
1120 value = "stop resource";
1121 }
1122
1123 } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
1124 action->on_fail = action_fail_standby;
1125 value = "node standby";
1126
1127 } else if (pcmk__strcase_any_of(value, "ignore", "nothing", NULL)) {
1128 action->on_fail = action_fail_ignore;
1129 value = "ignore";
1130
1131 } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
1132 action->on_fail = action_fail_migrate;
1133 value = "force migration";
1134
1135 } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
1136 action->on_fail = action_fail_stop;
1137 action->fail_role = RSC_ROLE_STOPPED;
1138 value = "stop resource";
1139
1140 } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
1141 action->on_fail = action_fail_recover;
1142 value = "restart (and possibly migrate)";
1143
1144 } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
1145 if (container) {
1147 value = "restart container (and possibly migrate)";
1148
1149 } else {
1150 value = NULL;
1151 }
1152
1153 } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
1154 action->on_fail = action_fail_demote;
1155 value = "demote instance";
1156
1157 } else {
1158 pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1159 value = NULL;
1160 }
1161
1162 /* defaults */
1163 if (value == NULL && container) {
1165 value = "restart container (and possibly migrate) (default)";
1166
1167 /* For remote nodes, ensure that any failure that results in dropping an
1168 * active connection to the node results in fencing of the node.
1169 *
1170 * There are only two action failures that don't result in fencing.
1171 * 1. probes - probe failures are expected.
1172 * 2. start - a start failure indicates that an active connection does not already
1173 * exist. The user can set op on-fail=fence if they really want to fence start
1174 * failures. */
1175 } else if (((value == NULL) || !pcmk_is_set(action->rsc->flags, pe_rsc_managed))
1176 && pe__resource_is_remote_conn(action->rsc, data_set)
1177 && !(pcmk__str_eq(action->task, CRMD_ACTION_STATUS, pcmk__str_casei)
1178 && (interval_ms == 0))
1179 && !pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
1180
1181 if (!pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
1182 action->on_fail = action_fail_stop;
1183 action->fail_role = RSC_ROLE_STOPPED;
1184 value = "stop unmanaged remote node (enforcing default)";
1185
1186 } else {
1187 if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1188 value = "fence remote node (default)";
1189 } else {
1190 value = "recover remote node connection (default)";
1191 }
1192
1193 if (action->rsc->remote_reconnect_ms) {
1194 action->fail_role = RSC_ROLE_STOPPED;
1195 }
1197 }
1198
1199 } else if (value == NULL && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
1200 if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1201 action->on_fail = action_fail_fence;
1202 value = "resource fence (default)";
1203
1204 } else {
1205 action->on_fail = action_fail_block;
1206 value = "resource block (default)";
1207 }
1208
1209 } else if (value == NULL) {
1210 action->on_fail = action_fail_recover;
1211 value = "restart (and possibly migrate) (default)";
1212 }
1213
1214 pe_rsc_trace(action->rsc, "%s failure handling: %s",
1215 action->uuid, value);
1216
1217 value = NULL;
1218 if (xml_obj != NULL) {
1219 value = g_hash_table_lookup(action->meta, "role_after_failure");
1220 if (value) {
1222 "Support for role_after_failure is deprecated and will be removed in a future release");
1223 }
1224 }
1225 if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1226 action->fail_role = text2role(value);
1227 }
1228 /* defaults */
1229 if (action->fail_role == RSC_ROLE_UNKNOWN) {
1230 if (pcmk__str_eq(action->task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
1231 action->fail_role = RSC_ROLE_UNPROMOTED;
1232 } else {
1233 action->fail_role = RSC_ROLE_STARTED;
1234 }
1235 }
1236 pe_rsc_trace(action->rsc, "%s failure results in: %s",
1237 action->uuid, role2text(action->fail_role));
1238
1239 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1240 if (value) {
1241 unpack_start_delay(value, action->meta);
1242 } else {
1243 long long start_delay = 0;
1244
1245 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1246 if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
1247 &start_delay)) {
1248 g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
1249 crm_strdup_printf("%lld", start_delay));
1250 }
1251 }
1252
1253#if ENABLE_VERSIONED_ATTRS
1254 unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval_ms,
1255 data_set->now);
1256#endif
1257}
1258
1259static xmlNode *
1260find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key, gboolean include_disabled)
1261{
1262 guint interval_ms = 0;
1263 gboolean do_retry = TRUE;
1264 char *local_key = NULL;
1265 const char *name = NULL;
1266 const char *value = NULL;
1267 const char *interval_spec = NULL;
1268 char *match_key = NULL;
1269 xmlNode *op = NULL;
1270 xmlNode *operation = NULL;
1271
1272 retry:
1273 for (operation = pcmk__xe_first_child(rsc->ops_xml); operation != NULL;
1274 operation = pcmk__xe_next(operation)) {
1275
1276 if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
1277 name = crm_element_value(operation, "name");
1278 interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1279 value = crm_element_value(operation, "enabled");
1280 if (!include_disabled && value && crm_is_true(value) == FALSE) {
1281 continue;
1282 }
1283
1284 interval_ms = crm_parse_interval_spec(interval_spec);
1285 match_key = pcmk__op_key(rsc->id, name, interval_ms);
1286 if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
1287 op = operation;
1288 }
1289 free(match_key);
1290
1291 if (rsc->clone_name) {
1292 match_key = pcmk__op_key(rsc->clone_name, name, interval_ms);
1293 if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
1294 op = operation;
1295 }
1296 free(match_key);
1297 }
1298
1299 if (op != NULL) {
1300 free(local_key);
1301 return op;
1302 }
1303 }
1304 }
1305
1306 free(local_key);
1307 if (do_retry == FALSE) {
1308 return NULL;
1309 }
1310
1311 do_retry = FALSE;
1312 if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1313 local_key = pcmk__op_key(rsc->id, "migrate", 0);
1314 key = local_key;
1315 goto retry;
1316
1317 } else if (strstr(key, "_notify_")) {
1318 local_key = pcmk__op_key(rsc->id, "notify", 0);
1319 key = local_key;
1320 goto retry;
1321 }
1322
1323 return NULL;
1324}
1325
1326xmlNode *
1327find_rsc_op_entry(pe_resource_t * rsc, const char *key)
1328{
1329 return find_rsc_op_entry_helper(rsc, key, FALSE);
1330}
1331
1332/*
1333 * Used by the HashTable for-loop
1334 */
1335void
1336print_str_str(gpointer key, gpointer value, gpointer user_data)
1337{
1338 crm_trace("%s%s %s ==> %s",
1339 user_data == NULL ? "" : (char *)user_data,
1340 user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1341}
1342
1343void
1345{
1346 if (action == NULL) {
1347 return;
1348 }
1349 g_list_free_full(action->actions_before, free); /* pe_action_wrapper_t* */
1350 g_list_free_full(action->actions_after, free); /* pe_action_wrapper_t* */
1351 if (action->extra) {
1352 g_hash_table_destroy(action->extra);
1353 }
1354 if (action->meta) {
1355 g_hash_table_destroy(action->meta);
1356 }
1357#if ENABLE_VERSIONED_ATTRS
1358 if (action->rsc) {
1359 pe_free_rsc_action_details(action);
1360 }
1361#endif
1362 free(action->cancel_task);
1363 free(action->reason);
1364 free(action->task);
1365 free(action->uuid);
1366 free(action->node);
1367 free(action);
1368}
1369
1370GList *
1371find_recurring_actions(GList *input, pe_node_t * not_on_node)
1372{
1373 const char *value = NULL;
1374 GList *result = NULL;
1375 GList *gIter = input;
1376
1377 CRM_CHECK(input != NULL, return NULL);
1378
1379 for (; gIter != NULL; gIter = gIter->next) {
1380 pe_action_t *action = (pe_action_t *) gIter->data;
1381
1382 value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL_MS);
1383 if (value == NULL) {
1384 /* skip */
1385 } else if (pcmk__str_eq(value, "0", pcmk__str_casei)) {
1386 /* skip */
1387 } else if (pcmk__str_eq(CRMD_ACTION_CANCEL, action->task, pcmk__str_casei)) {
1388 /* skip */
1389 } else if (not_on_node == NULL) {
1390 crm_trace("(null) Found: %s", action->uuid);
1391 result = g_list_prepend(result, action);
1392
1393 } else if (action->node == NULL) {
1394 /* skip */
1395 } else if (action->node->details != not_on_node->details) {
1396 crm_trace("Found: %s", action->uuid);
1397 result = g_list_prepend(result, action);
1398 }
1399 }
1400
1401 return result;
1402}
1403
1404enum action_tasks
1405get_complex_task(pe_resource_t * rsc, const char *name, gboolean allow_non_atomic)
1406{
1407 enum action_tasks task = text2task(name);
1408
1409 if (rsc == NULL) {
1410 return task;
1411
1412 } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1413 switch (task) {
1414 case stopped_rsc:
1415 case started_rsc:
1416 case action_demoted:
1417 case action_promoted:
1418 crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1419 return task - 1;
1420 default:
1421 break;
1422 }
1423 }
1424 return task;
1425}
1426
1428find_first_action(GList *input, const char *uuid, const char *task, pe_node_t * on_node)
1429{
1430 GList *gIter = NULL;
1431
1432 CRM_CHECK(uuid || task, return NULL);
1433
1434 for (gIter = input; gIter != NULL; gIter = gIter->next) {
1435 pe_action_t *action = (pe_action_t *) gIter->data;
1436
1437 if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1438 continue;
1439
1440 } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1441 continue;
1442
1443 } else if (on_node == NULL) {
1444 return action;
1445
1446 } else if (action->node == NULL) {
1447 continue;
1448
1449 } else if (on_node->details == action->node->details) {
1450 return action;
1451 }
1452 }
1453
1454 return NULL;
1455}
1456
1457GList *
1458find_actions(GList *input, const char *key, const pe_node_t *on_node)
1459{
1460 GList *gIter = input;
1461 GList *result = NULL;
1462
1463 CRM_CHECK(key != NULL, return NULL);
1464
1465 for (; gIter != NULL; gIter = gIter->next) {
1466 pe_action_t *action = (pe_action_t *) gIter->data;
1467
1468 if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1469 crm_trace("%s does not match action %s", key, action->uuid);
1470 continue;
1471
1472 } else if (on_node == NULL) {
1473 crm_trace("Action %s matches (ignoring node)", key);
1474 result = g_list_prepend(result, action);
1475
1476 } else if (action->node == NULL) {
1477 crm_trace("Action %s matches (unallocated, assigning to %s)",
1478 key, on_node->details->uname);
1479
1480 action->node = pe__copy_node(on_node);
1481 result = g_list_prepend(result, action);
1482
1483 } else if (on_node->details == action->node->details) {
1484 crm_trace("Action %s on %s matches", key, on_node->details->uname);
1485 result = g_list_prepend(result, action);
1486
1487 } else {
1488 crm_trace("Action %s on node %s does not match requested node %s",
1489 key, action->node->details->uname,
1490 on_node->details->uname);
1491 }
1492 }
1493
1494 return result;
1495}
1496
1497GList *
1498find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1499{
1500 GList *result = NULL;
1501
1502 CRM_CHECK(key != NULL, return NULL);
1503
1504 if (on_node == NULL) {
1505 crm_trace("Not searching for action %s because node not specified",
1506 key);
1507 return NULL;
1508 }
1509
1510 for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1511 pe_action_t *action = (pe_action_t *) gIter->data;
1512
1513 if (action->node == NULL) {
1514 crm_trace("Skipping comparison of %s vs action %s without node",
1515 key, action->uuid);
1516
1517 } else if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1518 crm_trace("Desired action %s doesn't match %s", key, action->uuid);
1519
1520 } else if (!pcmk__str_eq(on_node->details->id, action->node->details->id, pcmk__str_casei)) {
1521 crm_trace("Action %s desired node ID %s doesn't match %s",
1522 key, on_node->details->id, action->node->details->id);
1523
1524 } else {
1525 crm_trace("Action %s matches", key);
1526 result = g_list_prepend(result, action);
1527 }
1528 }
1529
1530 return result;
1531}
1532
1545GList *
1547 const char *task, bool require_node)
1548{
1549 GList *result = NULL;
1550 char *key = pcmk__op_key(rsc->id, task, 0);
1551
1552 if (require_node) {
1553 result = find_actions_exact(rsc->actions, key, node);
1554 } else {
1555 result = find_actions(rsc->actions, key, node);
1556 }
1557 free(key);
1558 return result;
1559}
1560
1561static void
1562resource_node_score(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag)
1563{
1564 pe_node_t *match = NULL;
1565
1567 && pcmk__str_eq(tag, "symmetric_default", pcmk__str_casei)) {
1568 /* This string comparision may be fragile, but exclusive resources and
1569 * exclusive nodes should not have the symmetric_default constraint
1570 * applied to them.
1571 */
1572 return;
1573
1574 } else if (rsc->children) {
1575 GList *gIter = rsc->children;
1576
1577 for (; gIter != NULL; gIter = gIter->next) {
1578 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1579
1580 resource_node_score(child_rsc, node, score, tag);
1581 }
1582 }
1583
1584 pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1585 match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1586 if (match == NULL) {
1587 match = pe__copy_node(node);
1588 g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1589 }
1590 match->weight = pe__add_scores(match->weight, score);
1591}
1592
1593void
1594resource_location(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag,
1595 pe_working_set_t * data_set)
1596{
1597 if (node != NULL) {
1598 resource_node_score(rsc, node, score, tag);
1599
1600 } else if (data_set != NULL) {
1601 GList *gIter = data_set->nodes;
1602
1603 for (; gIter != NULL; gIter = gIter->next) {
1604 pe_node_t *node_iter = (pe_node_t *) gIter->data;
1605
1606 resource_node_score(rsc, node_iter, score, tag);
1607 }
1608
1609 } else {
1610 GHashTableIter iter;
1611 pe_node_t *node_iter = NULL;
1612
1613 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1614 while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1615 resource_node_score(rsc, node_iter, score, tag);
1616 }
1617 }
1618
1619 if (node == NULL && score == -INFINITY) {
1620 if (rsc->allocated_to) {
1621 crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1622 free(rsc->allocated_to);
1623 rsc->allocated_to = NULL;
1624 }
1625 }
1626}
1627
1628#define sort_return(an_int, why) do { \
1629 free(a_uuid); \
1630 free(b_uuid); \
1631 crm_trace("%s (%d) %c %s (%d) : %s", \
1632 a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1633 b_xml_id, b_call_id, why); \
1634 return an_int; \
1635 } while(0)
1636
1637gint
1638sort_op_by_callid(gconstpointer a, gconstpointer b)
1639{
1640 int a_call_id = -1;
1641 int b_call_id = -1;
1642
1643 char *a_uuid = NULL;
1644 char *b_uuid = NULL;
1645
1646 const xmlNode *xml_a = a;
1647 const xmlNode *xml_b = b;
1648
1649 const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1650 const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1651
1652 if (pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_casei)) {
1653 /* We have duplicate lrm_rsc_op entries in the status
1654 * section which is unlikely to be a good thing
1655 * - we can handle it easily enough, but we need to get
1656 * to the bottom of why it's happening.
1657 */
1658 pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1659 sort_return(0, "duplicate");
1660 }
1661
1662 crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1663 crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1664
1665 if (a_call_id == -1 && b_call_id == -1) {
1666 /* both are pending ops so it doesn't matter since
1667 * stops are never pending
1668 */
1669 sort_return(0, "pending");
1670
1671 } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1672 sort_return(-1, "call id");
1673
1674 } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1675 sort_return(1, "call id");
1676
1677 } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1678 /*
1679 * The op and last_failed_op are the same
1680 * Order on last-rc-change
1681 */
1682 time_t last_a = -1;
1683 time_t last_b = -1;
1684
1687
1688 crm_trace("rc-change: %lld vs %lld",
1689 (long long) last_a, (long long) last_b);
1690 if (last_a >= 0 && last_a < last_b) {
1691 sort_return(-1, "rc-change");
1692
1693 } else if (last_b >= 0 && last_a > last_b) {
1694 sort_return(1, "rc-change");
1695 }
1696 sort_return(0, "rc-change");
1697
1698 } else {
1699 /* One of the inputs is a pending operation
1700 * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1701 */
1702
1703 int a_id = -1;
1704 int b_id = -1;
1705
1706 const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1707 const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1708
1709 CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1710 if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1711 NULL)) {
1712 sort_return(0, "bad magic a");
1713 }
1714 if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1715 NULL)) {
1716 sort_return(0, "bad magic b");
1717 }
1718 /* try to determine the relative age of the operation...
1719 * some pending operations (e.g. a start) may have been superseded
1720 * by a subsequent stop
1721 *
1722 * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1723 */
1724 if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1725 /*
1726 * some of the logic in here may be redundant...
1727 *
1728 * if the UUID from the TE doesn't match then one better
1729 * be a pending operation.
1730 * pending operations don't survive between elections and joins
1731 * because we query the LRM directly
1732 */
1733
1734 if (b_call_id == -1) {
1735 sort_return(-1, "transition + call");
1736
1737 } else if (a_call_id == -1) {
1738 sort_return(1, "transition + call");
1739 }
1740
1741 } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1742 sort_return(-1, "transition");
1743
1744 } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1745 sort_return(1, "transition");
1746 }
1747 }
1748
1749 /* we should never end up here */
1750 CRM_CHECK(FALSE, sort_return(0, "default"));
1751
1752}
1753
1754time_t
1756{
1757 if(data_set) {
1758 if (data_set->now == NULL) {
1759 crm_trace("Recording a new 'now'");
1760 data_set->now = crm_time_new(NULL);
1761 }
1762 return crm_time_get_seconds_since_epoch(data_set->now);
1763 }
1764
1765 crm_trace("Defaulting to 'now'");
1766 return time(NULL);
1767}
1768
1769gboolean
1771{
1772 enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1773 const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1774
1775 CRM_CHECK(role != NULL, return FALSE);
1776
1777 if (pcmk__str_eq(value, "started", pcmk__str_null_matches | pcmk__str_casei)
1778 || pcmk__str_eq("default", value, pcmk__str_casei)) {
1779 return FALSE;
1780 }
1781
1782 local_role = text2role(value);
1783 if (local_role == RSC_ROLE_UNKNOWN) {
1784 pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1785 "because '%s' is not valid", rsc->id, value);
1786 return FALSE;
1787
1788 } else if (local_role > RSC_ROLE_STARTED) {
1790 if (local_role > RSC_ROLE_UNPROMOTED) {
1791 /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1792 return FALSE;
1793 }
1794
1795 } else {
1796 pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1797 "because '%s' only makes sense for promotable "
1798 "clones", rsc->id, value);
1799 return FALSE;
1800 }
1801 }
1802
1803 *role = local_role;
1804 return TRUE;
1805}
1806
1807gboolean
1808order_actions(pe_action_t * lh_action, pe_action_t * rh_action, enum pe_ordering order)
1809{
1810 GList *gIter = NULL;
1811 pe_action_wrapper_t *wrapper = NULL;
1812 GList *list = NULL;
1813
1814 if (order == pe_order_none) {
1815 return FALSE;
1816 }
1817
1818 if (lh_action == NULL || rh_action == NULL) {
1819 return FALSE;
1820 }
1821
1822 crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1823
1824 /* Ensure we never create a dependency on ourselves... it's happened */
1825 CRM_ASSERT(lh_action != rh_action);
1826
1827 /* Filter dups, otherwise update_action_states() has too much work to do */
1828 gIter = lh_action->actions_after;
1829 for (; gIter != NULL; gIter = gIter->next) {
1830 pe_action_wrapper_t *after = (pe_action_wrapper_t *) gIter->data;
1831
1832 if (after->action == rh_action && (after->type & order)) {
1833 return FALSE;
1834 }
1835 }
1836
1837 wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1838 wrapper->action = rh_action;
1839 wrapper->type = order;
1840 list = lh_action->actions_after;
1841 list = g_list_prepend(list, wrapper);
1842 lh_action->actions_after = list;
1843
1844 wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1845 wrapper->action = lh_action;
1846 wrapper->type = order;
1847 list = rh_action->actions_before;
1848 list = g_list_prepend(list, wrapper);
1849 rh_action->actions_before = list;
1850 return TRUE;
1851}
1852
1854get_pseudo_op(const char *name, pe_working_set_t * data_set)
1855{
1856 pe_action_t *op = NULL;
1857
1858 if(data_set->singletons) {
1859 op = g_hash_table_lookup(data_set->singletons, name);
1860 }
1861 if (op == NULL) {
1862 op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1864 }
1865
1866 return op;
1867}
1868
1869void
1871{
1872 pe_ticket_t *ticket = data;
1873
1874 if (ticket->state) {
1875 g_hash_table_destroy(ticket->state);
1876 }
1877 free(ticket->id);
1878 free(ticket);
1879}
1880
1882ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1883{
1884 pe_ticket_t *ticket = NULL;
1885
1886 if (pcmk__str_empty(ticket_id)) {
1887 return NULL;
1888 }
1889
1890 if (data_set->tickets == NULL) {
1891 data_set->tickets = pcmk__strkey_table(free, destroy_ticket);
1892 }
1893
1894 ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1895 if (ticket == NULL) {
1896
1897 ticket = calloc(1, sizeof(pe_ticket_t));
1898 if (ticket == NULL) {
1899 crm_err("Cannot allocate ticket '%s'", ticket_id);
1900 return NULL;
1901 }
1902
1903 crm_trace("Creaing ticket entry for %s", ticket_id);
1904
1905 ticket->id = strdup(ticket_id);
1906 ticket->granted = FALSE;
1907 ticket->last_granted = -1;
1908 ticket->standby = FALSE;
1909 ticket->state = pcmk__strkey_table(free, free);
1910
1911 g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1912 }
1913
1914 return ticket;
1915}
1916
1918{
1919 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1920 return ID(rsc->xml);
1921 }
1922 return rsc->id;
1923}
1924
1925void
1927{
1929 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1931 }
1932}
1933
1934void
1936{
1937 for (GList *lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
1938 pe_resource_t *r = (pe_resource_t *) lpc->data;
1940 }
1941}
1942
1943void
1945{
1947 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1949 }
1950}
1951
1952static GList *
1953find_unfencing_devices(GList *candidates, GList *matches)
1954{
1955 for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
1956 pe_resource_t *candidate = gIter->data;
1957 const char *provides = g_hash_table_lookup(candidate->meta,
1959 const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
1960
1961 if(candidate->children) {
1962 matches = find_unfencing_devices(candidate->children, matches);
1963 } else if (!pcmk_is_set(candidate->flags, pe_rsc_fence_device)) {
1964 continue;
1965
1966 } else if (pcmk__str_eq(provides, "unfencing", pcmk__str_casei) || pcmk__str_eq(requires, "unfencing", pcmk__str_casei)) {
1967 matches = g_list_prepend(matches, candidate);
1968 }
1969 }
1970 return matches;
1971}
1972
1973static int
1974node_priority_fencing_delay(pe_node_t * node, pe_working_set_t * data_set)
1975{
1976 int member_count = 0;
1977 int online_count = 0;
1978 int top_priority = 0;
1979 int lowest_priority = 0;
1980 GList *gIter = NULL;
1981
1982 // `priority-fencing-delay` is disabled
1983 if (data_set->priority_fencing_delay <= 0) {
1984 return 0;
1985 }
1986
1987 /* No need to request a delay if the fencing target is not a normal cluster
1988 * member, for example if it's a remote node or a guest node. */
1989 if (node->details->type != node_member) {
1990 return 0;
1991 }
1992
1993 // No need to request a delay if the fencing target is in our partition
1994 if (node->details->online) {
1995 return 0;
1996 }
1997
1998 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1999 pe_node_t *n = gIter->data;
2000
2001 if (n->details->type != node_member) {
2002 continue;
2003 }
2004
2005 member_count ++;
2006
2007 if (n->details->online) {
2008 online_count++;
2009 }
2010
2011 if (member_count == 1
2012 || n->details->priority > top_priority) {
2013 top_priority = n->details->priority;
2014 }
2015
2016 if (member_count == 1
2017 || n->details->priority < lowest_priority) {
2018 lowest_priority = n->details->priority;
2019 }
2020 }
2021
2022 // No need to delay if we have more than half of the cluster members
2023 if (online_count > member_count / 2) {
2024 return 0;
2025 }
2026
2027 /* All the nodes have equal priority.
2028 * Any configured corresponding `pcmk_delay_base/max` will be applied. */
2029 if (lowest_priority == top_priority) {
2030 return 0;
2031 }
2032
2033 if (node->details->priority < top_priority) {
2034 return 0;
2035 }
2036
2037 return data_set->priority_fencing_delay;
2038}
2039
2041pe_fence_op(pe_node_t * node, const char *op, bool optional, const char *reason,
2042 bool priority_delay, pe_working_set_t * data_set)
2043{
2044 char *op_key = NULL;
2045 pe_action_t *stonith_op = NULL;
2046
2047 if(op == NULL) {
2048 op = data_set->stonith_action;
2049 }
2050
2051 op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2052
2053 if(data_set->singletons) {
2054 stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2055 }
2056
2057 if(stonith_op == NULL) {
2058 stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2059
2060 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2062 add_hash_param(stonith_op->meta, "stonith_action", op);
2063
2066 /* Extra work to detect device changes on remotes
2067 *
2068 * We may do this for all nodes in the future, but for now
2069 * the check_action_definition() based stuff works fine.
2070 */
2071 long max = 1024;
2072 long digests_all_offset = 0;
2073 long digests_secure_offset = 0;
2074
2075 char *digests_all = calloc(max, sizeof(char));
2076 char *digests_secure = calloc(max, sizeof(char));
2077 GList *matches = find_unfencing_devices(data_set->resources, NULL);
2078
2079 for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
2080 pe_resource_t *match = gIter->data;
2081 const char *agent = g_hash_table_lookup(match->meta,
2083 op_digest_cache_t *data = NULL;
2084
2085 data = pe__compare_fencing_digest(match, agent, node, data_set);
2086 if(data->rc == RSC_DIGEST_ALL) {
2087 optional = FALSE;
2088 crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2089 if (!pcmk__is_daemon && data_set->priv != NULL) {
2090 pcmk__output_t *out = data_set->priv;
2091 out->info(out, "notice: Unfencing %s (remote): because the definition of %s changed",
2092 node->details->uname, match->id);
2093 }
2094 }
2095
2096 digests_all_offset += snprintf(
2097 digests_all+digests_all_offset, max-digests_all_offset,
2098 "%s:%s:%s,", match->id, agent, data->digest_all_calc);
2099
2100 digests_secure_offset += snprintf(
2101 digests_secure+digests_secure_offset, max-digests_secure_offset,
2102 "%s:%s:%s,", match->id, agent, data->digest_secure_calc);
2103 }
2104 g_hash_table_insert(stonith_op->meta,
2106 digests_all);
2107 g_hash_table_insert(stonith_op->meta,
2109 digests_secure);
2110 }
2111
2112 } else {
2113 free(op_key);
2114 }
2115
2116 if (data_set->priority_fencing_delay > 0
2117
2118 /* It's a suitable case where `priority-fencing-delay` applies.
2119 * At least add `priority-fencing-delay` field as an indicator. */
2120 && (priority_delay
2121
2122 /* Re-calculate priority delay for the suitable case when
2123 * pe_fence_op() is called again by stage6() after node priority has
2124 * been actually calculated with native_add_running() */
2125 || g_hash_table_lookup(stonith_op->meta,
2127
2128 /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
2129 * the targeting node. So that it takes precedence over any possible
2130 * `pcmk_delay_base/max`.
2131 */
2132 char *delay_s = pcmk__itoa(node_priority_fencing_delay(node, data_set));
2133
2134 g_hash_table_insert(stonith_op->meta,
2136 delay_s);
2137 }
2138
2139 if(optional == FALSE && pe_can_fence(data_set, node)) {
2140 pe_action_required(stonith_op, NULL, reason);
2141 } else if(reason && stonith_op->reason == NULL) {
2142 stonith_op->reason = strdup(reason);
2143 }
2144
2145 return stonith_op;
2146}
2147
2148void
2150 pe_resource_t * rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t * data_set)
2151{
2152 if (!pcmk_is_set(data_set->flags, pe_flag_enable_unfencing)) {
2153 /* No resources require it */
2154 return;
2155
2156 } else if ((rsc != NULL)
2158 /* Wasn't a stonith device */
2159 return;
2160
2161 } else if(node
2162 && node->details->online
2163 && node->details->unclean == FALSE
2164 && node->details->shutdown == FALSE) {
2165 pe_action_t *unfence = pe_fence_op(node, "on", FALSE, reason, FALSE, data_set);
2166
2167 if(dependency) {
2168 order_actions(unfence, dependency, pe_order_optional);
2169 }
2170
2171 } else if(rsc) {
2172 GHashTableIter iter;
2173
2174 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2175 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2176 if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2177 trigger_unfencing(rsc, node, reason, dependency, data_set);
2178 }
2179 }
2180 }
2181}
2182
2183gboolean
2184add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2185{
2186 pe_tag_t *tag = NULL;
2187 GList *gIter = NULL;
2188 gboolean is_existing = FALSE;
2189
2190 CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2191
2192 tag = g_hash_table_lookup(tags, tag_name);
2193 if (tag == NULL) {
2194 tag = calloc(1, sizeof(pe_tag_t));
2195 if (tag == NULL) {
2196 return FALSE;
2197 }
2198 tag->id = strdup(tag_name);
2199 tag->refs = NULL;
2200 g_hash_table_insert(tags, strdup(tag_name), tag);
2201 }
2202
2203 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2204 const char *existing_ref = (const char *) gIter->data;
2205
2206 if (pcmk__str_eq(existing_ref, obj_ref, pcmk__str_none)){
2207 is_existing = TRUE;
2208 break;
2209 }
2210 }
2211
2212 if (is_existing == FALSE) {
2213 tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2214 crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2215 }
2216
2217 return TRUE;
2218}
2219
2220void pe_action_set_flag_reason(const char *function, long line,
2221 pe_action_t *action, pe_action_t *reason, const char *text,
2222 enum pe_action_flags flags, bool overwrite)
2223{
2224 bool unset = FALSE;
2225 bool update = FALSE;
2226 const char *change = NULL;
2227
2229 unset = TRUE;
2230 change = "unrunnable";
2231 } else if (pcmk_is_set(flags, pe_action_optional)) {
2232 unset = TRUE;
2233 change = "required";
2235 unset = TRUE;
2236 overwrite = TRUE;
2237 change = "unrunnable";
2238 } else if (pcmk_is_set(flags, pe_action_dangle)) {
2239 change = "dangling";
2241 change = "required";
2242 } else {
2243 crm_err("Unknown flag change to %x by %s: 0x%s",
2244 flags, action->uuid, (reason? reason->uuid : "0"));
2245 }
2246
2247 if(unset) {
2248 if (pcmk_is_set(action->flags, flags)) {
2249 pe__clear_action_flags_as(function, line, action, flags);
2250 update = TRUE;
2251 }
2252
2253 } else {
2254 if (!pcmk_is_set(action->flags, flags)) {
2255 pe__set_action_flags_as(function, line, action, flags);
2256 update = TRUE;
2257 }
2258 }
2259
2260 if((change && update) || text) {
2261 char *reason_text = NULL;
2262 if(reason == NULL) {
2263 pe_action_set_reason(action, text, overwrite);
2264
2265 } else if(reason->rsc == NULL) {
2266 reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2267 } else {
2268 reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2269 }
2270
2271 if(reason_text && action->rsc != reason->rsc) {
2272 pe_action_set_reason(action, reason_text, overwrite);
2273 }
2274 free(reason_text);
2275 }
2276 }
2277
2278void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
2279{
2280 if (action->reason != NULL && overwrite) {
2281 pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
2282 action->uuid, action->reason, crm_str(reason));
2283 free(action->reason);
2284 } else if (action->reason == NULL) {
2285 pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
2286 action->uuid, crm_str(reason));
2287 } else {
2288 // crm_assert(action->reason != NULL && !overwrite);
2289 return;
2290 }
2291
2292 if (reason != NULL) {
2293 action->reason = strdup(reason);
2294 } else {
2295 action->reason = NULL;
2296 }
2297}
2298
2311bool
2313{
2314 const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
2315
2316 return !pcmk__str_eq(shutdown, "0", pcmk__str_null_matches);
2317}
2318
2326void
2328{
2329 if ((recheck > get_effective_time(data_set))
2330 && ((data_set->recheck_by == 0)
2331 || (data_set->recheck_by > recheck))) {
2332 data_set->recheck_by = recheck;
2333 }
2334}
2335
2340void
2341pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name,
2342 pe_rule_eval_data_t *rule_data, GHashTable *hash,
2343 const char *always_first, gboolean overwrite,
2344 pe_working_set_t *data_set)
2345{
2346 crm_time_t *next_change = crm_time_new_undefined();
2347
2348 pe_eval_nvpairs(data_set->input, xml_obj, set_name, rule_data, hash,
2349 always_first, overwrite, next_change);
2350 if (crm_time_is_defined(next_change)) {
2351 time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
2352
2353 pe__update_recheck_time(recheck, data_set);
2354 }
2355 crm_time_free(next_change);
2356}
2357
2358bool
2360{
2361 const char *target_role = NULL;
2362
2363 CRM_CHECK(rsc != NULL, return false);
2364 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
2365 if (target_role) {
2366 enum rsc_role_e target_role_e = text2role(target_role);
2367
2368 if ((target_role_e == RSC_ROLE_STOPPED)
2369 || ((target_role_e == RSC_ROLE_UNPROMOTED)
2371 return true;
2372 }
2373 }
2374 return false;
2375}
2376
2388 pe_working_set_t *data_set)
2389{
2390 char *key = NULL;
2391
2392 CRM_ASSERT(rsc && node);
2393 key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
2394 return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
2395 data_set);
2396}
2397
2398bool
2400{
2401 for (GList *ele = rsc->running_on; ele; ele = ele->next) {
2402 pe_node_t *node = (pe_node_t *) ele->data;
2403 if (pcmk__str_in_list(node_list, node->details->uname, pcmk__str_casei)) {
2404 return true;
2405 }
2406 }
2407
2408 return false;
2409}
2410
2411bool
2413{
2414 return (rsc->fns->active(rsc, FALSE) && !pe__rsc_running_on_any(rsc, only_node));
2415}
2416
2417GList *
2418pe__filter_rsc_list(GList *rscs, GList *filter)
2419{
2420 GList *retval = NULL;
2421
2422 for (GList *gIter = rscs; gIter; gIter = gIter->next) {
2423 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2424
2425 /* I think the second condition is safe here for all callers of this
2426 * function. If not, it needs to move into pe__node_text.
2427 */
2430 retval = g_list_prepend(retval, rsc);
2431 }
2432 }
2433
2434 return retval;
2435}
2436
2437GList *
2439 GList *nodes = NULL;
2440
2441 if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
2442 /* Nothing was given so return a list of all node names. Or, '*' was
2443 * given. This would normally fall into the pe__unames_with_tag branch
2444 * where it will return an empty list. Catch it here instead.
2445 */
2446 nodes = g_list_prepend(nodes, strdup("*"));
2447 } else {
2448 pe_node_t *node = pe_find_node(data_set->nodes, s);
2449
2450 if (node) {
2451 /* The given string was a valid uname for a node. Return a
2452 * singleton list containing just that uname.
2453 */
2454 nodes = g_list_prepend(nodes, strdup(s));
2455 } else {
2456 /* The given string was not a valid uname. It's either a tag or
2457 * it's a typo or something. In the first case, we'll return a
2458 * list of all the unames of the nodes with the given tag. In the
2459 * second case, we'll return a NULL pointer and nothing will
2460 * get displayed.
2461 */
2462 nodes = pe__unames_with_tag(data_set, s);
2463 }
2464 }
2465
2466 return nodes;
2467}
2468
2469GList *
2470pe__build_rsc_list(pe_working_set_t *data_set, const char *s) {
2471 GList *resources = NULL;
2472
2473 if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
2474 resources = g_list_prepend(resources, strdup("*"));
2475 } else {
2478
2479 if (rsc) {
2480 /* A colon in the name we were given means we're being asked to filter
2481 * on a specific instance of a cloned resource. Put that exact string
2482 * into the filter list. Otherwise, use the printable ID of whatever
2483 * resource was found that matches what was asked for.
2484 */
2485 if (strstr(s, ":") != NULL) {
2486 resources = g_list_prepend(resources, strdup(rsc->id));
2487 } else {
2488 resources = g_list_prepend(resources, strdup(rsc_printable_id(rsc)));
2489 }
2490 } else {
2491 /* The given string was not a valid resource name. It's either
2492 * a tag or it's a typo or something. See build_uname_list for
2493 * more detail.
2494 */
2495 resources = pe__rscs_with_tag(data_set, s);
2496 }
2497 }
2498
2499 return resources;
2500}
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:53
#define PCMK_STONITH_PROVIDES
Definition agents.h:36
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:45
bool pcmk__is_daemon
Definition logging.c:47
uint64_t flags
Definition remote.c:3
Utility functions.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition operations.c:185
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition strings.c:363
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition util.h:73
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:415
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:255
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
char * score2char_stack(int score, char *buf, size_t len)
Definition utils.c:101
guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition utils.c:314
@ 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:354
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition common.h:116
@ action_fail_block
Definition common.h:41
@ action_fail_reset_remote
Definition common.h:56
@ action_fail_migrate
Definition common.h:40
@ action_fail_ignore
Definition common.h:35
@ action_fail_restart_container
Definition common.h:48
@ action_fail_fence
Definition common.h:44
@ action_fail_standby
Definition common.h:43
@ action_fail_demote
Definition common.h:58
@ action_fail_stop
Definition common.h:42
@ action_fail_recover
Definition common.h:37
const char * role2text(enum rsc_role_e role)
Definition common.c:459
action_tasks
Definition common.h:62
@ started_rsc
Definition common.h:68
@ start_rsc
Definition common.h:67
@ action_demoted
Definition common.h:74
@ stop_rsc
Definition common.h:65
@ action_promoted
Definition common.h:72
@ stopped_rsc
Definition common.h:66
rsc_role_e
Possible roles that a resource can be in.
Definition common.h:92
@ 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:488
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition complex.c:903
GHashTable * pe_rsc_params(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition complex.c:457
char data[0]
Definition cpg.c:10
A dumping ground.
#define CRMD_ACTION_STOP
Definition crm.h:179
#define RSC_PROMOTE
Definition crm.h:207
#define CRMD_ACTION_CANCEL
Definition crm.h:169
#define CRMD_ACTION_MIGRATED
Definition crm.h:174
#define CRMD_ACTION_STATUS
Definition crm.h:190
#define RSC_START
Definition crm.h:201
#define CRMD_ACTION_DEMOTE
Definition crm.h:184
#define INFINITY
Definition crm.h:99
#define CRMD_ACTION_MIGRATE
Definition crm.h:173
#define CRMD_ACTION_START
Definition crm.h:176
#define RSC_STATUS
Definition crm.h:215
#define CRM_OP_LRM_DELETE
Definition crm.h:151
#define CRMD_ACTION_PROMOTE
Definition crm.h:182
#define CRM_OP_FENCE
Definition crm.h:145
long long int crm_time_get_seconds_since_epoch(crm_time_t *dt)
Definition iso8601.c:351
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:141
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition iso8601.c:133
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:93
long long int crm_time_get_seconds(crm_time_t *dt)
Definition iso8601.c:308
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition iso8601.c:117
struct crm_time_s crm_time_t
Definition iso8601.h:32
#define crm_str(x)
Definition logging.h:376
#define crm_info(fmt, args...)
Definition logging.h:353
#define do_crm_log(level, fmt, args...)
Log a message.
Definition logging.h:159
#define crm_notice(fmt, args...)
Definition logging.h:352
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
#define LOG_TRACE
Definition logging.h:36
#define pcmk__config_err(fmt...)
#define pcmk__log_else(level, else_action)
#define ID(x)
Definition msg_xml.h:456
#define XML_EXPR_ATTR_TYPE
Definition msg_xml.h:342
#define XML_RSC_ATTR_TARGET_ROLE
Definition msg_xml.h:233
#define XML_NVPAIR_ATTR_VALUE
Definition msg_xml.h:378
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition msg_xml.h:389
#define XML_RSC_ATTR_REQUIRES
Definition msg_xml.h:240
#define XML_TAG_OP_VER_ATTRS
Definition msg_xml.h:207
#define XML_LRM_ATTR_TARGET_UUID
Definition msg_xml.h:300
#define XML_TAG_ATTR_SETS
Definition msg_xml.h:203
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_LRM_ATTR_INTERVAL
Definition msg_xml.h:291
#define XML_ATTR_TRANSITION_MAGIC
Definition msg_xml.h:398
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:267
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:266
#define XML_TAG_META_SETS
Definition msg_xml.h:204
#define XML_CIB_ATTR_SHUTDOWN
Definition msg_xml.h:283
#define XML_OP_ATTR_DIGESTS_ALL
Definition msg_xml.h:259
#define XML_ATTR_TYPE
Definition msg_xml.h:132
#define XML_NVPAIR_ATTR_NAME
Definition msg_xml.h:377
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:299
#define XML_ATTR_TIMEOUT
Definition msg_xml.h:123
#define XML_TAG_OP_VER_META
Definition msg_xml.h:208
#define XML_OP_ATTR_ON_FAIL
Definition msg_xml.h:254
#define XML_RSC_OP_LAST_CHANGE
Definition msg_xml.h:317
#define XML_OP_ATTR_DIGESTS_SECURE
Definition msg_xml.h:260
#define XML_OP_ATTR_ORIGIN
Definition msg_xml.h:257
#define XML_LRM_ATTR_CALLID
Definition msg_xml.h:309
#define XML_ATTR_OP
Definition msg_xml.h:134
#define XML_OP_ATTR_START_DELAY
Definition msg_xml.h:255
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:295
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:566
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:432
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition nvpair.c:482
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:651
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:324
char * name
Definition pcmk_fence.c:31
const char * action
Definition pcmk_fence.c:30
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:520
pe_quorum_policy
Definition pe_types.h:62
@ no_quorum_demote
Definition pe_types.h:67
@ no_quorum_freeze
Definition pe_types.h:63
@ no_quorum_ignore
Definition pe_types.h:65
@ no_quorum_stop
Definition pe_types.h:64
#define pe_rsc_stopping
Definition pe_types.h:272
#define pe_rsc_starting
Definition pe_types.h:271
#define pe_rsc_needs_quorum
Definition pe_types.h:279
#define pe_rsc_fence_device
Definition pe_types.h:255
#define pe_flag_have_stonith_resource
Definition pe_types.h:99
#define pe_flag_have_quorum
Definition pe_types.h:94
#define pe_rsc_managed
Definition pe_types.h:249
pe_ordering
Definition pe_types.h:484
@ pe_order_none
Definition pe_types.h:485
@ pe_order_optional
Definition pe_types.h:486
#define pe_flag_enable_unfencing
Definition pe_types.h:100
#define pe_rsc_unique
Definition pe_types.h:254
#define pe_rsc_orphan
Definition pe_types.h:248
@ node_member
Definition pe_types.h:72
@ pe_discover_never
Definition pe_types.h:479
pe_action_flags
Definition pe_types.h:291
@ pe_action_optional
Definition pe_types.h:294
@ pe_action_runnable
Definition pe_types.h:293
@ pe_action_dangle
Definition pe_types.h:306
@ pe_action_pseudo
Definition pe_types.h:292
@ pe_action_have_node_attrs
Definition pe_types.h:297
@ pe_action_requires_any
Definition pe_types.h:311
@ pe_action_dc
Internal state tracking when creating graph.
Definition pe_types.h:317
@ pe_action_migrate_runnable
Definition pe_types.h:299
@ pe_find_any
match base name of any clone instance
Definition pe_types.h:89
@ pe_find_renamed
match resource ID or LRM history ID
Definition pe_types.h:84
@ pe_native
Definition pe_types.h:37
#define pe_flag_stonith_enabled
Definition pe_types.h:98
#define pe_rsc_needs_fencing
Definition pe_types.h:280
#define pe_rsc_promotable
Definition pe_types.h:256
#define pe_warn_once(pe_wo_bit, fmt...)
Definition internal.h:154
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:97
GList * pe__unames_with_tag(pe_working_set_t *data_set, const char *tag_name)
Definition tags.c:51
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition common.c:635
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1116
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:53
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:19
GList * pe__rscs_with_tag(pe_working_set_t *data_set, const char *tag_name)
Definition tags.c:20
#define pe_warn(fmt...)
Definition internal.h:27
@ pe_wo_role_after
Definition internal.h:144
#define pe_action_required(action, reason, text)
Definition internal.h:505
#define pe__set_action_flags_as(function, line, action, flags_to_set)
Definition internal.h:93
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:20
int pe__add_scores(int score1, int score2)
Definition common.c:516
@ RSC_DIGEST_ALL
Definition internal.h:471
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:47
#define pe__clear_action_flags_as(function, line, action, flags_to_clear)
Definition internal.h:102
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:68
#define pe_err(fmt...)
Definition internal.h:22
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:59
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:579
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
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition remote.c:41
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.
Definition utils.c:1546
GList * pe__build_rsc_list(pe_working_set_t *data_set, const char *s)
Definition utils.c:2470
GList * find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
Definition utils.c:1498
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
Definition utils.c:1458
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition utils.c:2387
void node_list_exclude(GHashTable *hash, GList *list, gboolean merge_scores)
Definition utils.c:161
void pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition utils.c:1944
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition utils.c:1428
bool pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
Definition utils.c:2399
void destroy_ticket(gpointer data)
Definition utils.c:1870
void pe_action_set_flag_reason(const char *function, long line, pe_action_t *action, pe_action_t *reason, const char *text, enum pe_action_flags flags, bool overwrite)
Definition utils.c:2220
GHashTable * pe__node_list2table(GList *list)
Definition utils.c:204
void pe__clear_resource_flags_on_all(pe_working_set_t *data_set, uint64_t flag)
Definition utils.c:1935
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
Definition utils.c:2412
void trigger_unfencing(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t *data_set)
Definition utils.c:2149
bool pe__resource_is_disabled(pe_resource_t *rsc)
Definition utils.c:2359
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition utils.c:1854
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, pe_node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set)
Definition utils.c:415
void pe__show_node_weights_as(const char *file, const char *function, int line, bool to_log, pe_resource_t *rsc, const char *comment, GHashTable *nodes, pe_working_set_t *data_set)
Definition utils.c:304
gboolean get_target_role(pe_resource_t *rsc, enum rsc_role_e *role)
Definition utils.c:1770
GList * pe__build_node_name_list(pe_working_set_t *data_set, const char *s)
Definition utils.c:2438
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition utils.c:2418
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition utils.c:218
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition utils.c:1405
void pe_free_action(pe_action_t *action)
Definition utils.c:1344
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:1808
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
Definition utils.c:362
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)
Definition utils.c:2041
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition utils.c:1336
bool pe__shutdown_requested(pe_node_t *node)
Definition utils.c:2312
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition utils.c:1638
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition utils.c:1594
#define sort_return(an_int, why)
Definition utils.c:1628
time_t get_effective_time(pe_working_set_t *data_set)
Definition utils.c:1755
void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name, pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition utils.c:2341
const char * rsc_printable_id(pe_resource_t *rsc)
Definition utils.c:1917
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition utils.c:335
pe_ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition utils.c:1882
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition utils.c:2327
GList * find_recurring_actions(GList *input, pe_node_t *not_on_node)
Definition utils.c:1371
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition utils.c:2278
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition utils.c:142
int pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
Definition utils.c:853
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition cib_utils.c:146
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition utils.c:2184
void pe__clear_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition utils.c:1926
bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
Definition utils.c:90
xmlNode * find_rsc_op_entry(pe_resource_t *rsc, const char *key)
Definition utils.c:1327
#define CRM_ASSERT(expr)
Definition results.h:42
void pe_eval_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *next_change)
Definition rules.c:605
pe_resource_t * pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
Definition status.c:388
pe_node_t * pe_find_node(GList *node_list, const char *uname)
Definition status.c:434
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition status.c:418
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition strings.c:1045
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:610
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:955
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
gboolean pcmk__str_in_list(GList *lst, const gchar *s, uint32_t flags)
Definition strings.c:895
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
char * reason
Definition pe_types.h:418
pe_resource_t * rsc
Definition pe_types.h:411
char * uuid
Definition pe_types.h:416
char * task
Definition pe_types.h:415
GList * actions_after
Definition pe_types.h:449
GHashTable * meta
Definition pe_types.h:425
GList * actions_before
Definition pe_types.h:448
enum pe_ordering type
Definition pe_types.h:533
pe_action_t * action
Definition pe_types.h:535
int weight
Definition pe_types.h:241
int rsc_discover_mode
Definition pe_types.h:245
gboolean fixed
Definition pe_types.h:242
struct pe_node_shared_s * details
Definition pe_types.h:244
gboolean shutdown
Definition pe_types.h:219
const char * id
Definition pe_types.h:208
gboolean online
Definition pe_types.h:213
const char * uname
Definition pe_types.h:209
pe_resource_t * remote_rsc
Definition pe_types.h:230
gboolean unclean
Definition pe_types.h:217
enum node_type type
Definition pe_types.h:210
const char * op_name
Definition common.h:180
GList * running_on
Definition pe_types.h:367
GList * actions
Definition pe_types.h:360
enum pe_obj_types variant
Definition pe_types.h:331
GHashTable * meta
Definition pe_types.h:374
GList * children
Definition pe_types.h:378
gboolean exclusive_discover
Definition pe_types.h:353
pe_resource_t * container
Definition pe_types.h:381
char * clone_name
Definition pe_types.h:323
xmlNode * xml
Definition pe_types.h:324
GHashTable * allowed_nodes
Definition pe_types.h:369
pe_node_t * allocated_to
Definition pe_types.h:364
unsigned long long flags
Definition pe_types.h:349
pe_resource_t * parent
Definition pe_types.h:329
enum rsc_role_e next_role
Definition pe_types.h:372
enum rsc_role_e role
Definition pe_types.h:371
resource_object_functions_t * fns
Definition pe_types.h:333
xmlNode * ops_xml
Definition pe_types.h:326
const char * standard
Definition common.h:174
GHashTable * node_hash
Definition common.h:185
char * id
Definition pe_types.h:466
GList * refs
Definition pe_types.h:467
GHashTable * state
Definition pe_types.h:462
char * id
Definition pe_types.h:458
gboolean standby
Definition pe_types.h:461
gboolean granted
Definition pe_types.h:459
time_t last_granted
Definition pe_types.h:460
GHashTable * singletons
Definition pe_types.h:155
const char * stonith_action
Definition pe_types.h:143
GList * actions
Definition pe_types.h:164
xmlNode * input
Definition pe_types.h:137
GList * resources
Definition pe_types.h:158
unsigned long long flags
Definition pe_types.h:146
xmlNode * op_defaults
Definition pe_types.h:166
enum pe_quorum_policy no_quorum_policy
Definition pe_types.h:149
GHashTable * tickets
Definition pe_types.h:152
time_t recheck_by
Definition pe_types.h:187
int priority_fencing_delay
Definition pe_types.h:190
crm_time_t * now
Definition pe_types.h:138
gboolean(* active)(pe_resource_t *, gboolean)
Definition pe_types.h:52
Wrappers for and extensions to libxml2.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2790
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition xml.c:2816
void free_xml(xmlNode *child)
Definition xml.c:823
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696