pacemaker  2.1.1-52dc28db4
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 pe_action_t *
415 custom_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
545  if (!pcmk_is_set(action->flags, pe_action_pseudo)
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:
641  if (pcmk_is_set(action->flags, pe_action_runnable)) {
643  }
644  break;
645  default:
646  break;
647  }
648  }
649  }
650 
651  free(key);
652  return action;
653 }
654 
655 static bool
656 valid_stop_on_fail(const char *value)
657 {
658  return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
659 }
660 
661 static const char *
662 unpack_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 
739 static xmlNode *
740 find_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 
778 static int
779 unpack_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
800 static bool
801 unpack_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 
841 static int
842 unpack_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 
852 int
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),
872  pcmk__str_casei)) {
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
900 static void
901 unpack_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 
952 static void
953 unpack_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  }
1196  action->on_fail = action_fail_reset_remote;
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 
1259 static xmlNode *
1260 find_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 
1326 xmlNode *
1327 find_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  */
1335 void
1336 print_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 
1343 void
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 
1370 GList *
1371 find_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 
1404 enum action_tasks
1405 get_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 
1427 pe_action_t *
1428 find_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 
1457 GList *
1458 find_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 
1497 GList *
1498 find_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 
1545 GList *
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 
1561 static void
1562 resource_node_score(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag)
1563 {
1564  pe_node_t *match = NULL;
1565 
1566  if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
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 
1593 void
1594 resource_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 
1637 gint
1638 sort_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 
1754 time_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 
1769 gboolean
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 
1807 gboolean
1808 order_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 
1853 pe_action_t *
1854 get_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 
1869 void
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 
1881 pe_ticket_t *
1882 ticket_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 
1925 void
1927 {
1929  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1931  }
1932 }
1933 
1934 void
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 
1943 void
1945 {
1947  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1949  }
1950 }
1951 
1952 static GList *
1953 find_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 
1973 static int
1974 node_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 
2040 pe_action_t *
2041 pe_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);
2061  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2062  add_hash_param(stonith_op->meta, "stonith_action", op);
2063 
2064  if (pe__is_guest_or_remote_node(node)
2065  && pcmk_is_set(data_set->flags, pe_flag_enable_unfencing)) {
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,
2082  XML_ATTR_TYPE);
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,
2105  strdup(XML_OP_ATTR_DIGESTS_ALL),
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 
2148 void
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)
2157  && !pcmk_is_set(rsc->flags, pe_rsc_fence_device)) {
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 
2183 gboolean
2184 add_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 
2220 void 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";
2240  } else if (pcmk_is_set(flags, pe_action_requires_any)) {
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 
2278 void 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 
2311 bool
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 
2326 void
2327 pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
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 
2340 void
2341 pe__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 
2358 bool
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 
2386 pe_action_t *
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 
2398 bool
2399 pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
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 
2411 bool
2413 {
2414  return (rsc->fns->active(rsc, FALSE) && !pe__rsc_running_on_any(rsc, only_node));
2415 }
2416 
2417 GList *
2418 pe__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  */
2428  if (pcmk__str_in_list(filter, rsc_printable_id(rsc), pcmk__str_none) ||
2429  (rsc->parent && pcmk__str_in_list(filter, rsc_printable_id(rsc->parent), pcmk__str_none))) {
2430  retval = g_list_prepend(retval, rsc);
2431  }
2432  }
2433 
2434  return retval;
2435 }
2436 
2437 GList *
2438 pe__build_node_name_list(pe_working_set_t *data_set, const char *s) {
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 
2469 GList *
2470 pe__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 }
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:117
#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:2041
#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:2312
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
#define pe__clear_action_flags_as(function, line, action, flags_to_clear)
Definition: internal.h:102
#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:1458
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:1870
#define crm_notice(fmt, args...)
Definition: logging.h:352
#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:2149
#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:1755
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1808
#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:133
GHashTable * state
Definition: pe_types.h:462
GList * pe__build_rsc_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:2470
#define PCMK_STONITH_PROVIDES
Definition: agents.h:36
pe_resource_t * container
Definition: pe_types.h:381
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
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
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
#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:371
int pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
Definition: utils.c:853
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
GList * children
Definition: pe_types.h:378
gboolean standby
Definition: pe_types.h:461
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:2790
#define pe_action_required(action, reason, text)
Definition: internal.h:505
xmlNode * xml
Definition: pe_types.h:324
pe_resource_t * rsc
Definition: pe_types.h:411
GList * find_recurring_actions(GList *input, pe_node_t *not_on_node)
Definition: utils.c:1371
enum rsc_role_e next_role
Definition: pe_types.h:372
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
gboolean exclusive_discover
Definition: pe_types.h:353
gboolean pcmk__str_in_list(GList *lst, const gchar *s, uint32_t flags)
Definition: strings.c:895
#define pcmk__config_err(fmt...)
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1638
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:363
GHashTable * meta
Definition: pe_types.h:374
#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:324
#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:466
#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
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:2412
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:364
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:254
pe_action_t * action
Definition: pe_types.h:535
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
#define pe_flag_have_quorum
Definition: pe_types.h:94
char * reason
Definition: pe_types.h:418
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1428
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:1882
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: utils.c:2278
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:2327
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:2359
#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:2184
#define CRMD_ACTION_STOP
Definition: crm.h:179
#define pe_warn(fmt...)
Definition: internal.h:27
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:2341
#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:2399
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:530
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:1770
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:154
char * task
Definition: pe_types.h:415
#define sort_return(an_int, why)
Definition: utils.c:1628
GList * actions_after
Definition: pe_types.h:449
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:68
#define crm_trace(fmt, args...)
Definition: logging.h:356
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:159
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
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * meta
Definition: pe_types.h:425
#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:349
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:1405
#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
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:351
time_t recheck_by
Definition: pe_types.h:187
void pe_free_action(pe_action_t *action)
Definition: utils.c:1344
#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:651
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:635
GList * actions
Definition: pe_types.h:360
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:73
time_t last_granted
Definition: pe_types.h:460
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:146
#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)
Definition: utils.c:415
char * uuid
Definition: pe_types.h:416
void pe__clear_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition: utils.c:1926
void free_xml(xmlNode *child)
Definition: xml.c:823
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:459
#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:458
#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:482
#define pe_rsc_fence_device
Definition: pe_types.h:255
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:308
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:1327
GList * refs
Definition: pe_types.h:467
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:2438
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:610
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:579
int sort_index
Definition: pe_types.h:343
int pe__add_scores(int score1, int score2)
Definition: common.c:516
#define crm_err(fmt, args...)
Definition: logging.h:350
#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:93
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:2387
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:1336
#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:1498
#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:376
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:1045
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:1944
GList * running_on
Definition: pe_types.h:367
#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:1935
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition: utils.c:2418
#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:415
#define pe_flag_have_stonith_resource
Definition: pe_types.h:99
#define pe_flag_enable_unfencing
Definition: pe_types.h:100
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:1917
#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:1854
enum pe_ordering type
Definition: pe_types.h:533
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:1546
#define crm_info(fmt, args...)
Definition: logging.h:353
#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:484
gboolean online
Definition: pe_types.h:213
uint64_t flags
Definition: remote.c:149
GList * actions_before
Definition: pe_types.h:448
#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:369
#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:2816
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:141
#define pe__set_action_flags_as(function, line, action, flags_to_set)
Definition: internal.h:93