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