pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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>
14 #include <crm/common/util.h>
15 
16 #include <ctype.h>
17 #include <glib.h>
18 #include <stdbool.h>
19 
20 #include <crm/pengine/rules.h>
21 #include <crm/pengine/internal.h>
22 
23 extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
24 void print_str_str(gpointer key, gpointer value, gpointer user_data);
25 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
26 void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
27  pe_working_set_t * data_set);
28 static xmlNode *find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key,
29  gboolean include_disabled);
30 
31 #if ENABLE_VERSIONED_ATTRS
32 pe_rsc_action_details_t *
33 pe_rsc_action_details(pe_action_t *action)
34 {
35  pe_rsc_action_details_t *details;
36 
37  CRM_CHECK(action != NULL, return NULL);
38 
39  if (action->action_details == NULL) {
40  action->action_details = calloc(1, sizeof(pe_rsc_action_details_t));
41  CRM_CHECK(action->action_details != NULL, return NULL);
42  }
43 
44  details = (pe_rsc_action_details_t *) action->action_details;
45  if (details->versioned_parameters == NULL) {
46  details->versioned_parameters = create_xml_node(NULL,
48  }
49  if (details->versioned_meta == NULL) {
50  details->versioned_meta = create_xml_node(NULL, XML_TAG_OP_VER_META);
51  }
52  return details;
53 }
54 
55 static void
56 pe_free_rsc_action_details(pe_action_t *action)
57 {
58  pe_rsc_action_details_t *details;
59 
60  if ((action == NULL) || (action->action_details == NULL)) {
61  return;
62  }
63 
64  details = (pe_rsc_action_details_t *) action->action_details;
65 
66  if (details->versioned_parameters) {
67  free_xml(details->versioned_parameters);
68  }
69  if (details->versioned_meta) {
70  free_xml(details->versioned_meta);
71  }
72 
73  action->action_details = NULL;
74 }
75 #endif
76 
86 bool
88 {
89  if (pe__is_guest_node(node)) {
90  /* Guest nodes are fenced by stopping their container resource. We can
91  * do that if the container's host is either online or fenceable.
92  */
94 
95  for (GList *n = rsc->running_on; n != NULL; n = n->next) {
96  pe_node_t *container_node = n->data;
97 
98  if (!container_node->details->online
99  && !pe_can_fence(data_set, container_node)) {
100  return false;
101  }
102  }
103  return true;
104 
105  } else if(is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
106  return false; /* Turned off */
107 
108  } else if (is_not_set(data_set->flags, pe_flag_have_stonith_resource)) {
109  return false; /* No devices */
110 
111  } else if (is_set(data_set->flags, pe_flag_have_quorum)) {
112  return true;
113 
114  } else if (data_set->no_quorum_policy == no_quorum_ignore) {
115  return true;
116 
117  } else if(node == NULL) {
118  return false;
119 
120  } else if(node->details->online) {
121  crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
122  return true;
123  }
124 
125  crm_trace("Cannot fence %s", node->details->uname);
126  return false;
127 }
128 
138 pe_node_t *
139 pe__copy_node(const pe_node_t *this_node)
140 {
141  pe_node_t *new_node = NULL;
142 
143  CRM_ASSERT(this_node != NULL);
144 
145  new_node = calloc(1, sizeof(pe_node_t));
146  CRM_ASSERT(new_node != NULL);
147 
148  new_node->rsc_discover_mode = this_node->rsc_discover_mode;
149  new_node->weight = this_node->weight;
150  new_node->fixed = this_node->fixed;
151  new_node->details = this_node->details;
152 
153  return new_node;
154 }
155 
156 /* any node in list1 or list2 and not in the other gets a score of -INFINITY */
157 void
158 node_list_exclude(GHashTable * hash, GListPtr list, gboolean merge_scores)
159 {
160  GHashTable *result = hash;
161  pe_node_t *other_node = NULL;
162  GListPtr gIter = list;
163 
164  GHashTableIter iter;
165  pe_node_t *node = NULL;
166 
167  g_hash_table_iter_init(&iter, hash);
168  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
169 
170  other_node = pe_find_node_id(list, node->details->id);
171  if (other_node == NULL) {
172  node->weight = -INFINITY;
173  } else if (merge_scores) {
174  node->weight = pe__add_scores(node->weight, other_node->weight);
175  }
176  }
177 
178  for (; gIter != NULL; gIter = gIter->next) {
179  pe_node_t *node = (pe_node_t *) gIter->data;
180 
181  other_node = pe_hash_table_lookup(result, node->details->id);
182 
183  if (other_node == NULL) {
184  pe_node_t *new_node = pe__copy_node(node);
185 
186  new_node->weight = -INFINITY;
187  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
188  }
189  }
190 }
191 
200 GHashTable *
202 {
203  GHashTable *result = NULL;
204 
205  result = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free);
206  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
207  pe_node_t *new_node = pe__copy_node((pe_node_t *) gIter->data);
208 
209  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
210  }
211  return result;
212 }
213 
214 gint
215 sort_node_uname(gconstpointer a, gconstpointer b)
216 {
217  const char *name_a = ((const pe_node_t *) a)->details->uname;
218  const char *name_b = ((const pe_node_t *) b)->details->uname;
219 
220  while (*name_a && *name_b) {
221  if (isdigit(*name_a) && isdigit(*name_b)) {
222  // If node names contain a number, sort numerically
223 
224  char *end_a = NULL;
225  char *end_b = NULL;
226  long num_a = strtol(name_a, &end_a, 10);
227  long num_b = strtol(name_b, &end_b, 10);
228 
229  // allow ordering e.g. 007 > 7
230  size_t len_a = end_a - name_a;
231  size_t len_b = end_b - name_b;
232 
233  if (num_a < num_b) {
234  return -1;
235  } else if (num_a > num_b) {
236  return 1;
237  } else if (len_a < len_b) {
238  return -1;
239  } else if (len_a > len_b) {
240  return 1;
241  }
242  name_a = end_a;
243  name_b = end_b;
244  } else {
245  // Compare non-digits case-insensitively
246  int lower_a = tolower(*name_a);
247  int lower_b = tolower(*name_b);
248 
249  if (lower_a < lower_b) {
250  return -1;
251  } else if (lower_a > lower_b) {
252  return 1;
253  }
254  ++name_a;
255  ++name_b;
256  }
257  }
258  if (!*name_a && *name_b) {
259  return -1;
260  } else if (*name_a && !*name_b) {
261  return 1;
262  }
263  return 0;
264 }
265 
274 static void
275 pe__output_node_weights(pe_resource_t *rsc, const char *comment,
276  GHashTable *nodes)
277 {
278  char score[128]; // Stack-allocated since this is called frequently
279 
280  // Sort the nodes so the output is consistent for regression tests
281  GList *list = g_list_sort(g_hash_table_get_values(nodes), sort_node_uname);
282 
283  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
284  pe_node_t *node = (pe_node_t *) gIter->data;
285 
286  score2char_stack(node->weight, score, sizeof(score));
287  if (rsc) {
288  printf("%s: %s allocation score on %s: %s\n",
289  comment, rsc->id, node->details->uname, score);
290  } else {
291  printf("%s: %s = %s\n", comment, node->details->uname, score);
292  }
293  }
294  g_list_free(list);
295 }
296 
308 static void
309 pe__log_node_weights(const char *file, const char *function, int line,
310  pe_resource_t *rsc, const char *comment, GHashTable *nodes)
311 {
312  GHashTableIter iter;
313  pe_node_t *node = NULL;
314  char score[128]; // Stack-allocated since this is called frequently
315 
316  // Don't waste time if we're not tracing at this point
317  pcmk__log_else(LOG_TRACE, return);
318 
319  g_hash_table_iter_init(&iter, nodes);
320  while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
321  score2char_stack(node->weight, score, sizeof(score));
322  if (rsc) {
323  qb_log_from_external_source(function, file,
324  "%s: %s allocation score on %s: %s",
325  LOG_TRACE, line, 0,
326  comment, rsc->id,
327  node->details->uname, score);
328  } else {
329  qb_log_from_external_source(function, file, "%s: %s = %s",
330  LOG_TRACE, line, 0,
331  comment, node->details->uname,
332  score);
333  }
334  }
335 }
336 
349 void
350 pe__show_node_weights_as(const char *file, const char *function, int line,
351  bool to_log, pe_resource_t *rsc, const char *comment,
352  GHashTable *nodes)
353 {
354  if (rsc != NULL) {
355  if (is_set(rsc->flags, pe_rsc_orphan)) {
356  // Don't show allocation scores for orphans
357  return;
358  }
359  nodes = rsc->allowed_nodes;
360  }
361  if (nodes == NULL) {
362  // Nothing to show
363  return;
364  }
365 
366  if (to_log) {
367  pe__log_node_weights(file, function, line, rsc, comment, nodes);
368  } else {
369  pe__output_node_weights(rsc, comment, nodes);
370  }
371 
372  // If this resource has children, repeat recursively for each
373  if (rsc && rsc->children) {
374  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
375  pe_resource_t *child = (pe_resource_t *) gIter->data;
376 
377  pe__show_node_weights_as(file, function, line, to_log, child,
378  comment, nodes);
379  }
380  }
381 }
382 
383 static void
384 append_dump_text(gpointer key, gpointer value, gpointer user_data)
385 {
386  char **dump_text = user_data;
387  char *new_text = crm_strdup_printf("%s %s=%s",
388  *dump_text, (char *)key, (char *)value);
389 
390  free(*dump_text);
391  *dump_text = new_text;
392 }
393 
394 void
395 dump_node_capacity(int level, const char *comment, pe_node_t * node)
396 {
397  char *dump_text = crm_strdup_printf("%s: %s capacity:",
398  comment, node->details->uname);
399 
400  g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
401 
402  if (level == LOG_STDOUT) {
403  fprintf(stdout, "%s\n", dump_text);
404  } else {
405  crm_trace("%s", dump_text);
406  }
407 
408  free(dump_text);
409 }
410 
411 void
412 dump_rsc_utilization(int level, const char *comment, pe_resource_t * rsc, pe_node_t * node)
413 {
414  char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
415  comment, rsc->id, node->details->uname);
416 
417  g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
418  switch (level) {
419  case LOG_STDOUT:
420  fprintf(stdout, "%s\n", dump_text);
421  break;
422  case LOG_NEVER:
423  break;
424  default:
425  crm_trace("%s", dump_text);
426  }
427  free(dump_text);
428 }
429 
430 gint
431 sort_rsc_index(gconstpointer a, gconstpointer b)
432 {
433  const pe_resource_t *resource1 = (const pe_resource_t *)a;
434  const pe_resource_t *resource2 = (const pe_resource_t *)b;
435 
436  if (a == NULL && b == NULL) {
437  return 0;
438  }
439  if (a == NULL) {
440  return 1;
441  }
442  if (b == NULL) {
443  return -1;
444  }
445 
446  if (resource1->sort_index > resource2->sort_index) {
447  return -1;
448  }
449 
450  if (resource1->sort_index < resource2->sort_index) {
451  return 1;
452  }
453 
454  return 0;
455 }
456 
457 gint
458 sort_rsc_priority(gconstpointer a, gconstpointer b)
459 {
460  const pe_resource_t *resource1 = (const pe_resource_t *)a;
461  const pe_resource_t *resource2 = (const pe_resource_t *)b;
462 
463  if (a == NULL && b == NULL) {
464  return 0;
465  }
466  if (a == NULL) {
467  return 1;
468  }
469  if (b == NULL) {
470  return -1;
471  }
472 
473  if (resource1->priority > resource2->priority) {
474  return -1;
475  }
476 
477  if (resource1->priority < resource2->priority) {
478  return 1;
479  }
480 
481  return 0;
482 }
483 
484 pe_action_t *
485 custom_action(pe_resource_t * rsc, char *key, const char *task,
486  pe_node_t * on_node, gboolean optional, gboolean save_action,
487  pe_working_set_t * data_set)
488 {
489  pe_action_t *action = NULL;
490  GListPtr possible_matches = NULL;
491 
492  CRM_CHECK(key != NULL, return NULL);
493  CRM_CHECK(task != NULL, free(key); return NULL);
494 
495  if (save_action && rsc != NULL) {
496  possible_matches = find_actions(rsc->actions, key, on_node);
497  } else if(save_action) {
498 #if 0
499  action = g_hash_table_lookup(data_set->singletons, key);
500 #else
501  /* More expensive but takes 'node' into account */
502  possible_matches = find_actions(data_set->actions, key, on_node);
503 #endif
504  }
505 
506  if(data_set->singletons == NULL) {
507  data_set->singletons = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
508  }
509 
510  if (possible_matches != NULL) {
511  if (pcmk__list_of_multiple(possible_matches)) {
512  pe_warn("Action %s for %s on %s exists %d times",
513  task, rsc ? rsc->id : "<NULL>",
514  on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
515  }
516 
517  action = g_list_nth_data(possible_matches, 0);
518  pe_rsc_trace(rsc, "Found existing action %d (%s) for %s (%s) on %s",
519  action->id, action->uuid,
520  (rsc? rsc->id : "no resource"), task,
521  (on_node? on_node->details->uname : "no node"));
522  g_list_free(possible_matches);
523  }
524 
525  if (action == NULL) {
526  if (save_action) {
527  pe_rsc_trace(rsc, "Creating %s action %d: %s for %s (%s) on %s",
528  (optional? "optional" : "mandatory"),
529  data_set->action_id, key,
530  (rsc? rsc->id : "no resource"), task,
531  (on_node? on_node->details->uname : "no node"));
532  }
533 
534  action = calloc(1, sizeof(pe_action_t));
535  if (save_action) {
536  action->id = data_set->action_id++;
537  } else {
538  action->id = 0;
539  }
540  action->rsc = rsc;
541  CRM_ASSERT(task != NULL);
542  action->task = strdup(task);
543  if (on_node) {
544  action->node = pe__copy_node(on_node);
545  }
546  action->uuid = strdup(key);
547 
548  if (safe_str_eq(task, CRM_OP_LRM_DELETE)) {
549  // Resource history deletion for a node can be done on the DC
551  }
552 
554  if (optional) {
556  } else {
558  }
559 
560  action->extra = crm_str_table_new();
561  action->meta = crm_str_table_new();
562 
563  if (save_action) {
564  data_set->actions = g_list_prepend(data_set->actions, action);
565  if(rsc == NULL) {
566  g_hash_table_insert(data_set->singletons, action->uuid, action);
567  }
568  }
569 
570  if (rsc != NULL) {
571  action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
572 
573  unpack_operation(action, action->op_entry, rsc->container, data_set);
574 
575  if (save_action) {
576  rsc->actions = g_list_prepend(rsc->actions, action);
577  }
578  }
579 
580  if (save_action) {
581  pe_rsc_trace(rsc, "Action %d created", action->id);
582  }
583  }
584 
585  if (!optional && is_set(action->flags, pe_action_optional)) {
586  pe_rsc_trace(rsc, "Unset optional on action %d", action->id);
588  }
589 
590  if (rsc != NULL) {
591  enum action_tasks a_task = text2task(action->task);
592  int warn_level = LOG_TRACE;
593 
594  if (save_action) {
595  warn_level = LOG_WARNING;
596  }
597 
598  if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
599  && action->node != NULL && action->op_entry != NULL) {
602  action->node->details->attrs,
603  action->extra, NULL, FALSE, data_set);
604  }
605 
606  if (is_set(action->flags, pe_action_pseudo)) {
607  /* leave untouched */
608 
609  } else if (action->node == NULL) {
610  pe_rsc_trace(rsc, "Unset runnable on %s", action->uuid);
612 
613  } else if (is_not_set(rsc->flags, pe_rsc_managed)
614  && g_hash_table_lookup(action->meta,
615  XML_LRM_ATTR_INTERVAL_MS) == NULL) {
616  crm_debug("Action %s (unmanaged)", action->uuid);
617  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
619 /* action->runnable = FALSE; */
620 
621  } else if (is_not_set(action->flags, pe_action_dc)
622  && !(action->node->details->online)
623  && (!pe__is_guest_node(action->node)
624  || action->node->details->remote_requires_reset)) {
626  do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
627  action->uuid, action->node->details->uname);
628  if (is_set(action->rsc->flags, pe_rsc_managed)
629  && save_action && a_task == stop_rsc
630  && action->node->details->unclean == FALSE) {
631  pe_fence_node(data_set, action->node, "resource actions are unrunnable", FALSE);
632  }
633 
634  } else if (is_not_set(action->flags, pe_action_dc)
635  && action->node->details->pending) {
637  do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
638  action->uuid, action->node->details->uname);
639 
640  } else if (action->needs == rsc_req_nothing) {
641  pe_rsc_trace(rsc, "Action %s does not require anything", action->uuid);
642  pe_action_set_reason(action, NULL, TRUE);
643  if (pe__is_guest_node(action->node)
644  && !pe_can_fence(data_set, action->node)) {
645  /* An action that requires nothing usually does not require any
646  * fencing in order to be runnable. However, there is an
647  * exception: an action cannot be completed if it is on a guest
648  * node whose host is unclean and cannot be fenced.
649  */
651  crm_debug("%s\t%s (cancelled : host cannot be fenced)",
652  action->node->details->uname, action->uuid);
653  } else {
655  }
656 #if 0
657  /*
658  * No point checking this
659  * - if we don't have quorum we can't stonith anyway
660  */
661  } else if (action->needs == rsc_req_stonith) {
662  crm_trace("Action %s requires only stonith", action->uuid);
663  action->runnable = TRUE;
664 #endif
665  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
666  && data_set->no_quorum_policy == no_quorum_stop) {
667  pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "no quorum", pe_action_runnable, TRUE);
668  crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);
669 
670  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
671  && data_set->no_quorum_policy == no_quorum_freeze) {
672  pe_rsc_trace(rsc, "Check resource is already active: %s %s %s %s", rsc->id, action->uuid, role2text(rsc->next_role), role2text(rsc->role));
673  if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
674  pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "quorum freeze", pe_action_runnable, TRUE);
675  pe_rsc_debug(rsc, "%s\t%s (cancelled : quorum freeze)",
676  action->node->details->uname, action->uuid);
677  }
678 
679  } else if(is_not_set(action->flags, pe_action_runnable)) {
680  pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
681  //pe_action_set_reason(action, NULL, TRUE);
683  }
684 
685  if (save_action) {
686  switch (a_task) {
687  case stop_rsc:
689  break;
690  case start_rsc:
692  if (is_set(action->flags, pe_action_runnable)) {
694  }
695  break;
696  default:
697  break;
698  }
699  }
700  }
701 
702  free(key);
703  return action;
704 }
705 
706 static const char *
707 unpack_operation_on_fail(pe_action_t * action)
708 {
709 
710  const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
711 
712  if (safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) {
713  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
714  "action to default value because 'standby' is not "
715  "allowed for stop", action->rsc->id);
716  return NULL;
717  } else if (safe_str_eq(action->task, CRMD_ACTION_DEMOTE) && !value) {
718  /* demote on_fail defaults to master monitor value if present */
719  xmlNode *operation = NULL;
720  const char *name = NULL;
721  const char *role = NULL;
722  const char *on_fail = NULL;
723  const char *interval_spec = NULL;
724  const char *enabled = NULL;
725 
726  CRM_CHECK(action->rsc != NULL, return NULL);
727 
728  for (operation = __xml_first_child_element(action->rsc->ops_xml);
729  operation && !value; operation = __xml_next_element(operation)) {
730 
731  if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
732  continue;
733  }
734  name = crm_element_value(operation, "name");
735  role = crm_element_value(operation, "role");
736  on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
737  enabled = crm_element_value(operation, "enabled");
738  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
739  if (!on_fail) {
740  continue;
741  } else if (enabled && !crm_is_true(enabled)) {
742  continue;
743  } else if (safe_str_neq(name, "monitor") || safe_str_neq(role, "Master")) {
744  continue;
745  } else if (crm_parse_interval_spec(interval_spec) == 0) {
746  continue;
747  }
748 
749  value = on_fail;
750  }
751  } else if (safe_str_eq(action->task, CRM_OP_LRM_DELETE)) {
752  value = "ignore";
753  }
754 
755  return value;
756 }
757 
758 static xmlNode *
759 find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
760 {
761  guint interval_ms = 0;
762  guint min_interval_ms = G_MAXUINT;
763  const char *name = NULL;
764  const char *value = NULL;
765  const char *interval_spec = NULL;
766  xmlNode *op = NULL;
767  xmlNode *operation = NULL;
768 
769  for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
770  operation = __xml_next_element(operation)) {
771 
772  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
773  name = crm_element_value(operation, "name");
774  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
775  value = crm_element_value(operation, "enabled");
776  if (!include_disabled && value && crm_is_true(value) == FALSE) {
777  continue;
778  }
779 
780  if (safe_str_neq(name, RSC_STATUS)) {
781  continue;
782  }
783 
784  interval_ms = crm_parse_interval_spec(interval_spec);
785 
786  if (interval_ms && (interval_ms < min_interval_ms)) {
787  min_interval_ms = interval_ms;
788  op = operation;
789  }
790  }
791  }
792 
793  return op;
794 }
795 
796 static int
797 unpack_start_delay(const char *value, GHashTable *meta)
798 {
799  int start_delay = 0;
800 
801  if (value != NULL) {
802  start_delay = crm_get_msec(value);
803 
804  if (start_delay < 0) {
805  start_delay = 0;
806  }
807 
808  if (meta) {
809  g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY), crm_itoa(start_delay));
810  }
811  }
812 
813  return start_delay;
814 }
815 
816 // true if value contains valid, non-NULL interval origin for recurring op
817 static bool
818 unpack_interval_origin(const char *value, xmlNode *xml_obj, guint interval_ms,
819  crm_time_t *now, long long *start_delay)
820 {
821  long long result = 0;
822  guint interval_sec = interval_ms / 1000;
823  crm_time_t *origin = NULL;
824 
825  // Ignore unspecified values and non-recurring operations
826  if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
827  return false;
828  }
829 
830  // Parse interval origin from text
831  origin = crm_time_new(value);
832  if (origin == NULL) {
833  pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
834  "'%s' because '%s' is not valid",
835  (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
836  return false;
837  }
838 
839  // Get seconds since origin (negative if origin is in the future)
840  result = crm_time_get_seconds(now) - crm_time_get_seconds(origin);
841  crm_time_free(origin);
842 
843  // Calculate seconds from closest interval to now
844  result = result % interval_sec;
845 
846  // Calculate seconds remaining until next interval
847  result = ((result <= 0)? 0 : interval_sec) - result;
848  crm_info("Calculated a start delay of %llds for operation '%s'",
849  result,
850  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
851 
852  if (start_delay != NULL) {
853  *start_delay = result * 1000; // milliseconds
854  }
855  return true;
856 }
857 
858 static int
859 unpack_timeout(const char *value)
860 {
861  int timeout = crm_get_msec(value);
862 
863  if (timeout < 0) {
865  }
866  return timeout;
867 }
868 
869 int
870 pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
871 {
872  xmlNode *child = NULL;
873  const char *timeout = NULL;
874  int timeout_ms = 0;
875 
876  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
877  child != NULL; child = crm_next_same_xml(child)) {
878  if (safe_str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME))) {
879  timeout = crm_element_value(child, XML_ATTR_TIMEOUT);
880  break;
881  }
882  }
883 
884  if (timeout == NULL && data_set->op_defaults) {
885  GHashTable *action_meta = crm_str_table_new();
887  NULL, action_meta, NULL, FALSE, data_set);
888  timeout = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
889  }
890 
891  // @TODO check meta-attributes (including versioned meta-attributes)
892  // @TODO maybe use min-interval monitor timeout as default for monitors
893 
894  timeout_ms = crm_get_msec(timeout);
895  if (timeout_ms < 0) {
897  }
898  return timeout_ms;
899 }
900 
901 #if ENABLE_VERSIONED_ATTRS
902 static void
903 unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj,
904  guint interval_ms, crm_time_t *now)
905 {
906  xmlNode *attrs = NULL;
907  xmlNode *attr = NULL;
908 
909  for (attrs = __xml_first_child_element(versioned_meta); attrs != NULL;
910  attrs = __xml_next_element(attrs)) {
911 
912  for (attr = __xml_first_child_element(attrs); attr != NULL;
913  attr = __xml_next_element(attr)) {
914 
915  const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
916  const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
917 
919  int start_delay = unpack_start_delay(value, NULL);
920 
921  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
922  } else if (safe_str_eq(name, XML_OP_ATTR_ORIGIN)) {
923  long long start_delay = 0;
924 
925  if (unpack_interval_origin(value, xml_obj, interval_ms, now,
926  &start_delay)) {
929  crm_xml_add_ll(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
930  }
931  } else if (safe_str_eq(name, XML_ATTR_TIMEOUT)) {
932  int timeout = unpack_timeout(value);
933 
934  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout);
935  }
936  }
937  }
938 }
939 #endif
940 
953 void
954 unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
955  pe_working_set_t * data_set)
956 {
957  guint interval_ms = 0;
958  int timeout = 0;
959  char *value_ms = NULL;
960  const char *value = NULL;
961  const char *field = NULL;
962  char *default_timeout = NULL;
963 #if ENABLE_VERSIONED_ATTRS
964  pe_rsc_action_details_t *rsc_details = NULL;
965 #endif
966 
967  CRM_CHECK(action && action->rsc, return);
968 
969  // Cluster-wide <op_defaults> <meta_attributes>
971  action->meta, NULL, FALSE, data_set);
972 
973  // Probe timeouts default differently, so handle timeout default later
974  default_timeout = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
975  if (default_timeout) {
976  default_timeout = strdup(default_timeout);
977  g_hash_table_remove(action->meta, XML_ATTR_TIMEOUT);
978  }
979 
980  if (xml_obj) {
981  xmlAttrPtr xIter = NULL;
982 
983  // <op> <meta_attributes> take precedence over defaults
985  action->meta, NULL, TRUE, data_set);
986 
987 #if ENABLE_VERSIONED_ATTRS
988  rsc_details = pe_rsc_action_details(action);
989  pe_unpack_versioned_attributes(data_set->input, xml_obj,
990  XML_TAG_ATTR_SETS, NULL,
991  rsc_details->versioned_parameters,
992  data_set->now, NULL);
993  pe_unpack_versioned_attributes(data_set->input, xml_obj,
994  XML_TAG_META_SETS, NULL,
995  rsc_details->versioned_meta,
996  data_set->now, NULL);
997 #endif
998 
999  /* Anything set as an <op> XML property has highest precedence.
1000  * This ensures we use the name and interval from the <op> tag.
1001  */
1002  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
1003  const char *prop_name = (const char *)xIter->name;
1004  const char *prop_value = crm_element_value(xml_obj, prop_name);
1005 
1006  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
1007  }
1008  }
1009 
1010  g_hash_table_remove(action->meta, "id");
1011 
1012  // Normalize interval to milliseconds
1013  field = XML_LRM_ATTR_INTERVAL;
1014  value = g_hash_table_lookup(action->meta, field);
1015  if (value != NULL) {
1016  interval_ms = crm_parse_interval_spec(value);
1017 
1018  } else if ((xml_obj == NULL) && !strcmp(action->task, RSC_STATUS)) {
1019  /* An orphaned recurring monitor will not have any XML. However, we
1020  * want the interval to be set, so the action can be properly detected
1021  * as a recurring monitor. Parse it from the key in this case.
1022  */
1023  parse_op_key(action->uuid, NULL, NULL, &interval_ms);
1024  }
1025  if (interval_ms > 0) {
1026  value_ms = crm_strdup_printf("%u", interval_ms);
1027  g_hash_table_replace(action->meta, strdup(field), value_ms);
1028 
1029  } else if (value) {
1030  g_hash_table_remove(action->meta, field);
1031  }
1032 
1033  // Handle timeout default, now that we know the interval
1034  if (g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT)) {
1035  free(default_timeout);
1036 
1037  } else {
1038  // Probe timeouts default to minimum-interval monitor's
1039  if (safe_str_eq(action->task, RSC_STATUS) && (interval_ms == 0)) {
1040 
1041  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
1042 
1043  if (min_interval_mon) {
1044  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
1045  if (value) {
1046  crm_trace("\t%s defaults to minimum-interval monitor's timeout '%s'",
1047  action->uuid, value);
1048  free(default_timeout);
1049  default_timeout = strdup(value);
1050  }
1051  }
1052  }
1053 
1054  if (default_timeout) {
1055  g_hash_table_insert(action->meta, strdup(XML_ATTR_TIMEOUT),
1056  default_timeout);
1057  }
1058  }
1059 
1060  if (safe_str_neq(action->task, RSC_START)
1061  && safe_str_neq(action->task, RSC_PROMOTE)) {
1062  action->needs = rsc_req_nothing;
1063  value = "nothing (not start/promote)";
1064 
1065  } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1066  action->needs = rsc_req_stonith;
1067  value = "fencing (resource)";
1068 
1069  } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1070  action->needs = rsc_req_quorum;
1071  value = "quorum (resource)";
1072 
1073  } else {
1074  action->needs = rsc_req_nothing;
1075  value = "nothing (resource)";
1076  }
1077 
1078  pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->uuid, value);
1079 
1080  value = unpack_operation_on_fail(action);
1081 
1082  if (value == NULL) {
1083 
1084  } else if (safe_str_eq(value, "block")) {
1085  action->on_fail = action_fail_block;
1086  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1087  value = "block"; // The above could destroy the original string
1088 
1089  } else if (safe_str_eq(value, "fence")) {
1090  action->on_fail = action_fail_fence;
1091  value = "node fencing";
1092 
1093  if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
1094  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
1095  "operation '%s' to 'stop' because 'fence' is not "
1096  "valid when fencing is disabled", action->uuid);
1097  action->on_fail = action_fail_stop;
1098  action->fail_role = RSC_ROLE_STOPPED;
1099  value = "stop resource";
1100  }
1101 
1102  } else if (safe_str_eq(value, "standby")) {
1103  action->on_fail = action_fail_standby;
1104  value = "node standby";
1105 
1106  } else if (safe_str_eq(value, "ignore")
1107  || safe_str_eq(value, "nothing")) {
1108  action->on_fail = action_fail_ignore;
1109  value = "ignore";
1110 
1111  } else if (safe_str_eq(value, "migrate")) {
1112  action->on_fail = action_fail_migrate;
1113  value = "force migration";
1114 
1115  } else if (safe_str_eq(value, "stop")) {
1116  action->on_fail = action_fail_stop;
1117  action->fail_role = RSC_ROLE_STOPPED;
1118  value = "stop resource";
1119 
1120  } else if (safe_str_eq(value, "restart")) {
1121  action->on_fail = action_fail_recover;
1122  value = "restart (and possibly migrate)";
1123 
1124  } else if (safe_str_eq(value, "restart-container")) {
1125  if (container) {
1127  value = "restart container (and possibly migrate)";
1128 
1129  } else {
1130  value = NULL;
1131  }
1132 
1133  } else {
1134  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1135  value = NULL;
1136  }
1137 
1138  /* defaults */
1139  if (value == NULL && container) {
1141  value = "restart container (and possibly migrate) (default)";
1142 
1143  /* For remote nodes, ensure that any failure that results in dropping an
1144  * active connection to the node results in fencing of the node.
1145  *
1146  * There are only two action failures that don't result in fencing.
1147  * 1. probes - probe failures are expected.
1148  * 2. start - a start failure indicates that an active connection does not already
1149  * exist. The user can set op on-fail=fence if they really want to fence start
1150  * failures. */
1151  } else if (((value == NULL) || !is_set(action->rsc->flags, pe_rsc_managed)) &&
1152  (pe__resource_is_remote_conn(action->rsc, data_set) &&
1153  !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && (interval_ms == 0)) &&
1154  (safe_str_neq(action->task, CRMD_ACTION_START)))) {
1155 
1156  if (!is_set(action->rsc->flags, pe_rsc_managed)) {
1157  action->on_fail = action_fail_stop;
1158  action->fail_role = RSC_ROLE_STOPPED;
1159  value = "stop unmanaged remote node (enforcing default)";
1160 
1161  } else {
1162  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1163  value = "fence remote node (default)";
1164  } else {
1165  value = "recover remote node connection (default)";
1166  }
1167 
1168  if (action->rsc->remote_reconnect_ms) {
1169  action->fail_role = RSC_ROLE_STOPPED;
1170  }
1172  }
1173 
1174  } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
1175  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1176  action->on_fail = action_fail_fence;
1177  value = "resource fence (default)";
1178 
1179  } else {
1180  action->on_fail = action_fail_block;
1181  value = "resource block (default)";
1182  }
1183 
1184  } else if (value == NULL) {
1185  action->on_fail = action_fail_recover;
1186  value = "restart (and possibly migrate) (default)";
1187  }
1188 
1189  pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
1190 
1191  value = NULL;
1192  if (xml_obj != NULL) {
1193  value = g_hash_table_lookup(action->meta, "role_after_failure");
1194  if (value) {
1196  "Support for role_after_failure is deprecated and will be removed in a future release");
1197  }
1198  }
1199  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1200  action->fail_role = text2role(value);
1201  }
1202  /* defaults */
1203  if (action->fail_role == RSC_ROLE_UNKNOWN) {
1204  if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
1205  action->fail_role = RSC_ROLE_SLAVE;
1206  } else {
1207  action->fail_role = RSC_ROLE_STARTED;
1208  }
1209  }
1210  pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
1211  role2text(action->fail_role));
1212 
1213  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1214  if (value) {
1215  unpack_start_delay(value, action->meta);
1216  } else {
1217  long long start_delay = 0;
1218 
1219  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1220  if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
1221  &start_delay)) {
1222  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
1223  crm_strdup_printf("%lld", start_delay));
1224  }
1225  }
1226 
1227  value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
1228  timeout = unpack_timeout(value);
1229  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT), crm_itoa(timeout));
1230 
1231 #if ENABLE_VERSIONED_ATTRS
1232  unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval_ms,
1233  data_set->now);
1234 #endif
1235 }
1236 
1237 static xmlNode *
1238 find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key, gboolean include_disabled)
1239 {
1240  guint interval_ms = 0;
1241  gboolean do_retry = TRUE;
1242  char *local_key = NULL;
1243  const char *name = NULL;
1244  const char *value = NULL;
1245  const char *interval_spec = NULL;
1246  char *match_key = NULL;
1247  xmlNode *op = NULL;
1248  xmlNode *operation = NULL;
1249 
1250  retry:
1251  for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
1252  operation = __xml_next_element(operation)) {
1253  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
1254  name = crm_element_value(operation, "name");
1255  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1256  value = crm_element_value(operation, "enabled");
1257  if (!include_disabled && value && crm_is_true(value) == FALSE) {
1258  continue;
1259  }
1260 
1261  interval_ms = crm_parse_interval_spec(interval_spec);
1262  match_key = pcmk__op_key(rsc->id, name, interval_ms);
1263  if (safe_str_eq(key, match_key)) {
1264  op = operation;
1265  }
1266  free(match_key);
1267 
1268  if (rsc->clone_name) {
1269  match_key = pcmk__op_key(rsc->clone_name, name, interval_ms);
1270  if (safe_str_eq(key, match_key)) {
1271  op = operation;
1272  }
1273  free(match_key);
1274  }
1275 
1276  if (op != NULL) {
1277  free(local_key);
1278  return op;
1279  }
1280  }
1281  }
1282 
1283  free(local_key);
1284  if (do_retry == FALSE) {
1285  return NULL;
1286  }
1287 
1288  do_retry = FALSE;
1289  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1290  local_key = pcmk__op_key(rsc->id, "migrate", 0);
1291  key = local_key;
1292  goto retry;
1293 
1294  } else if (strstr(key, "_notify_")) {
1295  local_key = pcmk__op_key(rsc->id, "notify", 0);
1296  key = local_key;
1297  goto retry;
1298  }
1299 
1300  return NULL;
1301 }
1302 
1303 xmlNode *
1304 find_rsc_op_entry(pe_resource_t * rsc, const char *key)
1305 {
1306  return find_rsc_op_entry_helper(rsc, key, FALSE);
1307 }
1308 
1309 void
1310 print_node(const char *pre_text, pe_node_t * node, gboolean details)
1311 {
1312  if (node == NULL) {
1313  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1314  return;
1315  }
1316 
1317  CRM_ASSERT(node->details);
1318  crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1319  pre_text == NULL ? "" : pre_text,
1320  pre_text == NULL ? "" : ": ",
1321  node->details->online ? "" : "Unavailable/Unclean ",
1322  node->details->uname, node->weight, node->fixed ? "True" : "False");
1323 
1324  if (details) {
1325  int log_level = LOG_TRACE;
1326 
1327  char *pe_mutable = strdup("\t\t");
1328  GListPtr gIter = node->details->running_rsc;
1329 
1330  crm_trace("\t\t===Node Attributes");
1331  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1332  free(pe_mutable);
1333 
1334  crm_trace("\t\t=== Resources");
1335 
1336  for (; gIter != NULL; gIter = gIter->next) {
1337  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1338 
1339  rsc->fns->print(rsc, "\t\t", pe_print_log|pe_print_pending,
1340  &log_level);
1341  }
1342  }
1343 }
1344 
1345 /*
1346  * Used by the HashTable for-loop
1347  */
1348 void
1349 print_str_str(gpointer key, gpointer value, gpointer user_data)
1350 {
1351  crm_trace("%s%s %s ==> %s",
1352  user_data == NULL ? "" : (char *)user_data,
1353  user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1354 }
1355 
1356 void
1358 {
1359  if (action == NULL) {
1360  return;
1361  }
1362  g_list_free_full(action->actions_before, free); /* pe_action_wrapper_t* */
1363  g_list_free_full(action->actions_after, free); /* pe_action_wrapper_t* */
1364  if (action->extra) {
1365  g_hash_table_destroy(action->extra);
1366  }
1367  if (action->meta) {
1368  g_hash_table_destroy(action->meta);
1369  }
1370 #if ENABLE_VERSIONED_ATTRS
1371  if (action->rsc) {
1372  pe_free_rsc_action_details(action);
1373  }
1374 #endif
1375  free(action->cancel_task);
1376  free(action->reason);
1377  free(action->task);
1378  free(action->uuid);
1379  free(action->node);
1380  free(action);
1381 }
1382 
1383 GListPtr
1385 {
1386  const char *value = NULL;
1387  GListPtr result = NULL;
1388  GListPtr gIter = input;
1389 
1390  CRM_CHECK(input != NULL, return NULL);
1391 
1392  for (; gIter != NULL; gIter = gIter->next) {
1393  pe_action_t *action = (pe_action_t *) gIter->data;
1394 
1395  value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL_MS);
1396  if (value == NULL) {
1397  /* skip */
1398  } else if (safe_str_eq(value, "0")) {
1399  /* skip */
1400  } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1401  /* skip */
1402  } else if (not_on_node == NULL) {
1403  crm_trace("(null) Found: %s", action->uuid);
1404  result = g_list_prepend(result, action);
1405 
1406  } else if (action->node == NULL) {
1407  /* skip */
1408  } else if (action->node->details != not_on_node->details) {
1409  crm_trace("Found: %s", action->uuid);
1410  result = g_list_prepend(result, action);
1411  }
1412  }
1413 
1414  return result;
1415 }
1416 
1417 enum action_tasks
1418 get_complex_task(pe_resource_t * rsc, const char *name, gboolean allow_non_atomic)
1419 {
1420  enum action_tasks task = text2task(name);
1421 
1422  if (rsc == NULL) {
1423  return task;
1424 
1425  } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1426  switch (task) {
1427  case stopped_rsc:
1428  case started_rsc:
1429  case action_demoted:
1430  case action_promoted:
1431  crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1432  return task - 1;
1433  break;
1434  default:
1435  break;
1436  }
1437  }
1438  return task;
1439 }
1440 
1441 pe_action_t *
1442 find_first_action(GListPtr input, const char *uuid, const char *task, pe_node_t * on_node)
1443 {
1444  GListPtr gIter = NULL;
1445 
1446  CRM_CHECK(uuid || task, return NULL);
1447 
1448  for (gIter = input; gIter != NULL; gIter = gIter->next) {
1449  pe_action_t *action = (pe_action_t *) gIter->data;
1450 
1451  if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1452  continue;
1453 
1454  } else if (task != NULL && safe_str_neq(task, action->task)) {
1455  continue;
1456 
1457  } else if (on_node == NULL) {
1458  return action;
1459 
1460  } else if (action->node == NULL) {
1461  continue;
1462 
1463  } else if (on_node->details == action->node->details) {
1464  return action;
1465  }
1466  }
1467 
1468  return NULL;
1469 }
1470 
1471 GListPtr
1472 find_actions(GListPtr input, const char *key, const pe_node_t *on_node)
1473 {
1474  GListPtr gIter = input;
1475  GListPtr result = NULL;
1476 
1477  CRM_CHECK(key != NULL, return NULL);
1478 
1479  for (; gIter != NULL; gIter = gIter->next) {
1480  pe_action_t *action = (pe_action_t *) gIter->data;
1481 
1482  if (safe_str_neq(key, action->uuid)) {
1483  crm_trace("%s does not match action %s", key, action->uuid);
1484  continue;
1485 
1486  } else if (on_node == NULL) {
1487  crm_trace("Action %s matches (ignoring node)", key);
1488  result = g_list_prepend(result, action);
1489 
1490  } else if (action->node == NULL) {
1491  crm_trace("Action %s matches (unallocated, assigning to %s)",
1492  key, on_node->details->uname);
1493 
1494  action->node = pe__copy_node(on_node);
1495  result = g_list_prepend(result, action);
1496 
1497  } else if (on_node->details == action->node->details) {
1498  crm_trace("Action %s on %s matches", key, on_node->details->uname);
1499  result = g_list_prepend(result, action);
1500 
1501  } else {
1502  crm_trace("Action %s on node %s does not match requested node %s",
1503  key, action->node->details->uname,
1504  on_node->details->uname);
1505  }
1506  }
1507 
1508  return result;
1509 }
1510 
1511 GList *
1512 find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1513 {
1514  GList *result = NULL;
1515 
1516  CRM_CHECK(key != NULL, return NULL);
1517 
1518  if (on_node == NULL) {
1519  crm_trace("Not searching for action %s because node not specified",
1520  key);
1521  return NULL;
1522  }
1523 
1524  for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1525  pe_action_t *action = (pe_action_t *) gIter->data;
1526 
1527  if (action->node == NULL) {
1528  crm_trace("Skipping comparison of %s vs action %s without node",
1529  key, action->uuid);
1530 
1531  } else if (safe_str_neq(key, action->uuid)) {
1532  crm_trace("Desired action %s doesn't match %s", key, action->uuid);
1533 
1534  } else if (safe_str_neq(on_node->details->id,
1535  action->node->details->id)) {
1536  crm_trace("Action %s desired node ID %s doesn't match %s",
1537  key, on_node->details->id, action->node->details->id);
1538 
1539  } else {
1540  crm_trace("Action %s matches", key);
1541  result = g_list_prepend(result, action);
1542  }
1543  }
1544 
1545  return result;
1546 }
1547 
1560 GList *
1562  const char *task, bool require_node)
1563 {
1564  GList *result = NULL;
1565  char *key = pcmk__op_key(rsc->id, task, 0);
1566 
1567  if (require_node) {
1568  result = find_actions_exact(rsc->actions, key, node);
1569  } else {
1570  result = find_actions(rsc->actions, key, node);
1571  }
1572  free(key);
1573  return result;
1574 }
1575 
1576 static void
1577 resource_node_score(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag)
1578 {
1579  pe_node_t *match = NULL;
1580 
1581  if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
1582  && safe_str_eq(tag, "symmetric_default")) {
1583  /* This string comparision may be fragile, but exclusive resources and
1584  * exclusive nodes should not have the symmetric_default constraint
1585  * applied to them.
1586  */
1587  return;
1588 
1589  } else if (rsc->children) {
1590  GListPtr gIter = rsc->children;
1591 
1592  for (; gIter != NULL; gIter = gIter->next) {
1593  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1594 
1595  resource_node_score(child_rsc, node, score, tag);
1596  }
1597  }
1598 
1599  pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1600  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1601  if (match == NULL) {
1602  match = pe__copy_node(node);
1603  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1604  }
1605  match->weight = pe__add_scores(match->weight, score);
1606 }
1607 
1608 void
1609 resource_location(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag,
1610  pe_working_set_t * data_set)
1611 {
1612  if (node != NULL) {
1613  resource_node_score(rsc, node, score, tag);
1614 
1615  } else if (data_set != NULL) {
1616  GListPtr gIter = data_set->nodes;
1617 
1618  for (; gIter != NULL; gIter = gIter->next) {
1619  pe_node_t *node_iter = (pe_node_t *) gIter->data;
1620 
1621  resource_node_score(rsc, node_iter, score, tag);
1622  }
1623 
1624  } else {
1625  GHashTableIter iter;
1626  pe_node_t *node_iter = NULL;
1627 
1628  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1629  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1630  resource_node_score(rsc, node_iter, score, tag);
1631  }
1632  }
1633 
1634  if (node == NULL && score == -INFINITY) {
1635  if (rsc->allocated_to) {
1636  crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1637  free(rsc->allocated_to);
1638  rsc->allocated_to = NULL;
1639  }
1640  }
1641 }
1642 
1643 #define sort_return(an_int, why) do { \
1644  free(a_uuid); \
1645  free(b_uuid); \
1646  crm_trace("%s (%d) %c %s (%d) : %s", \
1647  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1648  b_xml_id, b_call_id, why); \
1649  return an_int; \
1650  } while(0)
1651 
1652 gint
1653 sort_op_by_callid(gconstpointer a, gconstpointer b)
1654 {
1655  int a_call_id = -1;
1656  int b_call_id = -1;
1657 
1658  char *a_uuid = NULL;
1659  char *b_uuid = NULL;
1660 
1661  const xmlNode *xml_a = a;
1662  const xmlNode *xml_b = b;
1663 
1664  const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1665  const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1666 
1667  if (safe_str_eq(a_xml_id, b_xml_id)) {
1668  /* We have duplicate lrm_rsc_op entries in the status
1669  * section which is unlikely to be a good thing
1670  * - we can handle it easily enough, but we need to get
1671  * to the bottom of why it's happening.
1672  */
1673  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1674  sort_return(0, "duplicate");
1675  }
1676 
1677  crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1678  crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1679 
1680  if (a_call_id == -1 && b_call_id == -1) {
1681  /* both are pending ops so it doesn't matter since
1682  * stops are never pending
1683  */
1684  sort_return(0, "pending");
1685 
1686  } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1687  sort_return(-1, "call id");
1688 
1689  } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1690  sort_return(1, "call id");
1691 
1692  } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1693  /*
1694  * The op and last_failed_op are the same
1695  * Order on last-rc-change
1696  */
1697  time_t last_a = -1;
1698  time_t last_b = -1;
1699 
1702 
1703  crm_trace("rc-change: %lld vs %lld",
1704  (long long) last_a, (long long) last_b);
1705  if (last_a >= 0 && last_a < last_b) {
1706  sort_return(-1, "rc-change");
1707 
1708  } else if (last_b >= 0 && last_a > last_b) {
1709  sort_return(1, "rc-change");
1710  }
1711  sort_return(0, "rc-change");
1712 
1713  } else {
1714  /* One of the inputs is a pending operation
1715  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1716  */
1717 
1718  int a_id = -1;
1719  int b_id = -1;
1720 
1721  const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1722  const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1723 
1724  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1725  if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1726  NULL)) {
1727  sort_return(0, "bad magic a");
1728  }
1729  if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1730  NULL)) {
1731  sort_return(0, "bad magic b");
1732  }
1733  /* try to determine the relative age of the operation...
1734  * some pending operations (e.g. a start) may have been superseded
1735  * by a subsequent stop
1736  *
1737  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1738  */
1739  if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1740  /*
1741  * some of the logic in here may be redundant...
1742  *
1743  * if the UUID from the TE doesn't match then one better
1744  * be a pending operation.
1745  * pending operations don't survive between elections and joins
1746  * because we query the LRM directly
1747  */
1748 
1749  if (b_call_id == -1) {
1750  sort_return(-1, "transition + call");
1751 
1752  } else if (a_call_id == -1) {
1753  sort_return(1, "transition + call");
1754  }
1755 
1756  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1757  sort_return(-1, "transition");
1758 
1759  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1760  sort_return(1, "transition");
1761  }
1762  }
1763 
1764  /* we should never end up here */
1765  CRM_CHECK(FALSE, sort_return(0, "default"));
1766 
1767 }
1768 
1769 time_t
1771 {
1772  if(data_set) {
1773  if (data_set->now == NULL) {
1774  crm_trace("Recording a new 'now'");
1775  data_set->now = crm_time_new(NULL);
1776  }
1777  return crm_time_get_seconds_since_epoch(data_set->now);
1778  }
1779 
1780  crm_trace("Defaulting to 'now'");
1781  return time(NULL);
1782 }
1783 
1784 gboolean
1786 {
1787  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1788  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1789 
1790  CRM_CHECK(role != NULL, return FALSE);
1791 
1792  if (value == NULL || safe_str_eq("started", value)
1793  || safe_str_eq("default", value)) {
1794  return FALSE;
1795  }
1796 
1797  local_role = text2role(value);
1798  if (local_role == RSC_ROLE_UNKNOWN) {
1799  pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1800  "because '%s' is not valid", rsc->id, value);
1801  return FALSE;
1802 
1803  } else if (local_role > RSC_ROLE_STARTED) {
1804  if (is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
1805  if (local_role > RSC_ROLE_SLAVE) {
1806  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1807  return FALSE;
1808  }
1809 
1810  } else {
1811  pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1812  "because '%s' only makes sense for promotable "
1813  "clones", rsc->id, value);
1814  return FALSE;
1815  }
1816  }
1817 
1818  *role = local_role;
1819  return TRUE;
1820 }
1821 
1822 gboolean
1823 order_actions(pe_action_t * lh_action, pe_action_t * rh_action, enum pe_ordering order)
1824 {
1825  GListPtr gIter = NULL;
1826  pe_action_wrapper_t *wrapper = NULL;
1827  GListPtr list = NULL;
1828 
1829  if (order == pe_order_none) {
1830  return FALSE;
1831  }
1832 
1833  if (lh_action == NULL || rh_action == NULL) {
1834  return FALSE;
1835  }
1836 
1837  crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1838 
1839  /* Ensure we never create a dependency on ourselves... it's happened */
1840  CRM_ASSERT(lh_action != rh_action);
1841 
1842  /* Filter dups, otherwise update_action_states() has too much work to do */
1843  gIter = lh_action->actions_after;
1844  for (; gIter != NULL; gIter = gIter->next) {
1845  pe_action_wrapper_t *after = (pe_action_wrapper_t *) gIter->data;
1846 
1847  if (after->action == rh_action && (after->type & order)) {
1848  return FALSE;
1849  }
1850  }
1851 
1852  wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1853  wrapper->action = rh_action;
1854  wrapper->type = order;
1855 
1856  list = lh_action->actions_after;
1857  list = g_list_prepend(list, wrapper);
1858  lh_action->actions_after = list;
1859 
1860  wrapper = NULL;
1861 
1862 /* order |= pe_order_implies_then; */
1863 /* order ^= pe_order_implies_then; */
1864 
1865  wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1866  wrapper->action = lh_action;
1867  wrapper->type = order;
1868  list = rh_action->actions_before;
1869  list = g_list_prepend(list, wrapper);
1870  rh_action->actions_before = list;
1871  return TRUE;
1872 }
1873 
1874 pe_action_t *
1875 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1876 {
1877  pe_action_t *op = NULL;
1878 
1879  if(data_set->singletons) {
1880  op = g_hash_table_lookup(data_set->singletons, name);
1881  }
1882  if (op == NULL) {
1883  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1886  }
1887 
1888  return op;
1889 }
1890 
1891 void
1893 {
1894  pe_ticket_t *ticket = data;
1895 
1896  if (ticket->state) {
1897  g_hash_table_destroy(ticket->state);
1898  }
1899  free(ticket->id);
1900  free(ticket);
1901 }
1902 
1903 pe_ticket_t *
1904 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1905 {
1906  pe_ticket_t *ticket = NULL;
1907 
1908  if (ticket_id == NULL || strlen(ticket_id) == 0) {
1909  return NULL;
1910  }
1911 
1912  if (data_set->tickets == NULL) {
1913  data_set->tickets =
1914  g_hash_table_new_full(crm_str_hash, g_str_equal, free,
1915  destroy_ticket);
1916  }
1917 
1918  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1919  if (ticket == NULL) {
1920 
1921  ticket = calloc(1, sizeof(pe_ticket_t));
1922  if (ticket == NULL) {
1923  crm_err("Cannot allocate ticket '%s'", ticket_id);
1924  return NULL;
1925  }
1926 
1927  crm_trace("Creaing ticket entry for %s", ticket_id);
1928 
1929  ticket->id = strdup(ticket_id);
1930  ticket->granted = FALSE;
1931  ticket->last_granted = -1;
1932  ticket->standby = FALSE;
1933  ticket->state = crm_str_table_new();
1934 
1935  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1936  }
1937 
1938  return ticket;
1939 }
1940 
1941 static void
1942 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1943 {
1944  if (param_set && param_string) {
1945  xmlAttrPtr xIter = param_set->properties;
1946 
1947  while (xIter) {
1948  const char *prop_name = (const char *)xIter->name;
1949  char *name = crm_strdup_printf(" %s ", prop_name);
1950  char *match = strstr(param_string, name);
1951 
1952  free(name);
1953 
1954  // Do now, because current entry might get removed below
1955  xIter = xIter->next;
1956 
1957  if (need_present && match == NULL) {
1958  crm_trace("%s not found in %s", prop_name, param_string);
1959  xml_remove_prop(param_set, prop_name);
1960 
1961  } else if (need_present == FALSE && match) {
1962  crm_trace("%s found in %s", prop_name, param_string);
1963  xml_remove_prop(param_set, prop_name);
1964  }
1965  }
1966  }
1967 }
1968 
1969 #if ENABLE_VERSIONED_ATTRS
1970 static void
1971 append_versioned_params(xmlNode *versioned_params, const char *ra_version, xmlNode *params)
1972 {
1973  GHashTable *hash = pe_unpack_versioned_parameters(versioned_params, ra_version);
1974  char *key = NULL;
1975  char *value = NULL;
1976  GHashTableIter iter;
1977 
1978  g_hash_table_iter_init(&iter, hash);
1979  while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value)) {
1980  crm_xml_add(params, key, value);
1981  }
1982  g_hash_table_destroy(hash);
1983 }
1984 #endif
1985 
2000 static op_digest_cache_t *
2001 rsc_action_digest(pe_resource_t *rsc, const char *task, const char *key,
2002  pe_node_t *node, xmlNode *xml_op, bool calc_secure,
2003  pe_working_set_t *data_set)
2004 {
2005  op_digest_cache_t *data = NULL;
2006 
2007  data = g_hash_table_lookup(node->details->digest_cache, key);
2008  if (data == NULL) {
2009  GHashTable *local_rsc_params = crm_str_table_new();
2010  pe_action_t *action = custom_action(rsc, strdup(key), task, node, TRUE, FALSE, data_set);
2011 #if ENABLE_VERSIONED_ATTRS
2012  xmlNode *local_versioned_params = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
2013  const char *ra_version = NULL;
2014 #endif
2015 
2016  const char *op_version;
2017  const char *restart_list = NULL;
2018  const char *secure_list = " passwd password ";
2019 
2020  data = calloc(1, sizeof(op_digest_cache_t));
2021  CRM_ASSERT(data != NULL);
2022 
2023  get_rsc_attributes(local_rsc_params, rsc, node, data_set);
2024 #if ENABLE_VERSIONED_ATTRS
2025  pe_get_versioned_attributes(local_versioned_params, rsc, node, data_set);
2026 #endif
2027 
2028  data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
2029 
2030  // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
2031  if (pe__add_bundle_remote_name(rsc, data->params_all,
2033  crm_trace("Set address for bundle connection %s (on %s)",
2034  rsc->id, node->details->uname);
2035  }
2036 
2037  g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
2038  g_hash_table_foreach(action->extra, hash2field, data->params_all);
2039  g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
2040  g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
2041 
2042  if(xml_op) {
2043  secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
2044  restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
2045 
2046  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
2047 #if ENABLE_VERSIONED_ATTRS
2048  ra_version = crm_element_value(xml_op, XML_ATTR_RA_VERSION);
2049 #endif
2050 
2051  } else {
2052  op_version = CRM_FEATURE_SET;
2053  }
2054 
2055 #if ENABLE_VERSIONED_ATTRS
2056  append_versioned_params(local_versioned_params, ra_version, data->params_all);
2057  append_versioned_params(rsc->versioned_parameters, ra_version, data->params_all);
2058 
2059  {
2060  pe_rsc_action_details_t *details = pe_rsc_action_details(action);
2061  append_versioned_params(details->versioned_parameters, ra_version, data->params_all);
2062  }
2063 #endif
2064 
2066 
2067  g_hash_table_destroy(local_rsc_params);
2068  pe_free_action(action);
2069 
2070  data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
2071 
2072  if (calc_secure) {
2073  data->params_secure = copy_xml(data->params_all);
2074  if(secure_list) {
2075  filter_parameters(data->params_secure, secure_list, FALSE);
2076  }
2077  data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
2078  }
2079 
2080  if(xml_op && crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
2081  data->params_restart = copy_xml(data->params_all);
2082  if (restart_list) {
2083  filter_parameters(data->params_restart, restart_list, TRUE);
2084  }
2086  }
2087 
2088  g_hash_table_insert(node->details->digest_cache, strdup(key), data);
2089  }
2090 
2091  return data;
2092 }
2093 
2095 rsc_action_digest_cmp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * node,
2096  pe_working_set_t * data_set)
2097 {
2098  op_digest_cache_t *data = NULL;
2099 
2100  char *key = NULL;
2101  guint interval_ms = 0;
2102 
2103  const char *op_version;
2104  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
2105  const char *digest_all;
2106  const char *digest_restart;
2107 
2108  CRM_ASSERT(node != NULL);
2109 
2110  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
2111  digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
2112  digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
2113 
2114  crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
2115  key = pcmk__op_key(rsc->id, task, interval_ms);
2116  data = rsc_action_digest(rsc, task, key, node, xml_op,
2117  is_set(data_set->flags, pe_flag_sanitized),
2118  data_set);
2119 
2120  data->rc = RSC_DIGEST_MATCH;
2121  if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
2122  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
2123  key, node->details->uname,
2124  crm_str(digest_restart), data->digest_restart_calc,
2125  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2126  data->rc = RSC_DIGEST_RESTART;
2127 
2128  } else if (digest_all == NULL) {
2129  /* it is unknown what the previous op digest was */
2130  data->rc = RSC_DIGEST_UNKNOWN;
2131 
2132  } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
2133  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (%s:%s) %s",
2134  key, node->details->uname,
2135  crm_str(digest_all), data->digest_all_calc,
2136  (interval_ms > 0)? "reschedule" : "reload",
2137  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2138  data->rc = RSC_DIGEST_ALL;
2139  }
2140 
2141  free(key);
2142  return data;
2143 }
2144 
2162 static inline char *
2163 create_unfencing_summary(const char *rsc_id, const char *agent_type,
2164  const char *param_digest)
2165 {
2166  return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
2167 }
2168 
2185 static bool
2186 unfencing_digest_matches(const char *rsc_id, const char *agent,
2187  const char *digest_calc, const char *node_summary)
2188 {
2189  bool matches = FALSE;
2190 
2191  if (rsc_id && agent && digest_calc && node_summary) {
2192  char *search_secure = create_unfencing_summary(rsc_id, agent,
2193  digest_calc);
2194 
2195  /* The digest was calculated including the device ID and agent,
2196  * so there is no risk of collision using strstr().
2197  */
2198  matches = (strstr(node_summary, search_secure) != NULL);
2199  crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
2200  search_secure, matches? "" : "not ", node_summary);
2201  free(search_secure);
2202  }
2203  return matches;
2204 }
2205 
2206 /* Magic string to use as action name for digest cache entries used for
2207  * unfencing checks. This is not a real action name (i.e. "on"), so
2208  * check_action_definition() won't confuse these entries with real actions.
2209  */
2210 #define STONITH_DIGEST_TASK "stonith-on"
2211 
2223 static op_digest_cache_t *
2224 fencing_action_digest_cmp(pe_resource_t *rsc, const char *agent,
2225  pe_node_t *node, pe_working_set_t *data_set)
2226 {
2227  const char *node_summary = NULL;
2228 
2229  // Calculate device's current parameter digests
2230  char *key = pcmk__op_key(rsc->id, STONITH_DIGEST_TASK, 0);
2231  op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key,
2232  node, NULL, TRUE, data_set);
2233 
2234  free(key);
2235 
2236  // Check whether node has special unfencing summary node attribute
2237  node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
2238  if (node_summary == NULL) {
2239  data->rc = RSC_DIGEST_UNKNOWN;
2240  return data;
2241  }
2242 
2243  // Check whether full parameter digest matches
2244  if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
2245  node_summary)) {
2246  data->rc = RSC_DIGEST_MATCH;
2247  return data;
2248  }
2249 
2250  // Check whether secure parameter digest matches
2251  node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
2252  if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
2253  node_summary)) {
2254  data->rc = RSC_DIGEST_MATCH;
2255  if (is_set(data_set->flags, pe_flag_stdout)) {
2256  printf("Only 'private' parameters to %s for unfencing %s changed\n",
2257  rsc->id, node->details->uname);
2258  }
2259  return data;
2260  }
2261 
2262  // Parameters don't match
2263  data->rc = RSC_DIGEST_ALL;
2264  if (is_set(data_set->flags, (pe_flag_sanitized|pe_flag_stdout))
2265  && data->digest_secure_calc) {
2266  char *digest = create_unfencing_summary(rsc->id, agent,
2267  data->digest_secure_calc);
2268 
2269  printf("Parameters to %s for unfencing %s changed, try '%s'\n",
2270  rsc->id, node->details->uname, digest);
2271  free(digest);
2272  }
2273  return data;
2274 }
2275 
2277 {
2278  if (is_not_set(rsc->flags, pe_rsc_unique)) {
2279  return ID(rsc->xml);
2280  }
2281  return rsc->id;
2282 }
2283 
2284 void
2285 clear_bit_recursive(pe_resource_t * rsc, unsigned long long flag)
2286 {
2287  GListPtr gIter = rsc->children;
2288 
2289  clear_bit(rsc->flags, flag);
2290  for (; gIter != NULL; gIter = gIter->next) {
2291  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
2292 
2293  clear_bit_recursive(child_rsc, flag);
2294  }
2295 }
2296 
2297 void
2298 set_bit_recursive(pe_resource_t * rsc, unsigned long long flag)
2299 {
2300  GListPtr gIter = rsc->children;
2301 
2302  set_bit(rsc->flags, flag);
2303  for (; gIter != NULL; gIter = gIter->next) {
2304  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
2305 
2306  set_bit_recursive(child_rsc, flag);
2307  }
2308 }
2309 
2310 static GListPtr
2311 find_unfencing_devices(GListPtr candidates, GListPtr matches)
2312 {
2313  for (GListPtr gIter = candidates; gIter != NULL; gIter = gIter->next) {
2314  pe_resource_t *candidate = gIter->data;
2315  const char *provides = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_PROVIDES);
2316  const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
2317 
2318  if(candidate->children) {
2319  matches = find_unfencing_devices(candidate->children, matches);
2320  } else if (is_not_set(candidate->flags, pe_rsc_fence_device)) {
2321  continue;
2322 
2323  } else if (crm_str_eq(provides, "unfencing", FALSE) || crm_str_eq(requires, "unfencing", FALSE)) {
2324  matches = g_list_prepend(matches, candidate);
2325  }
2326  }
2327  return matches;
2328 }
2329 
2330 static int
2331 node_priority_fencing_delay(pe_node_t * node, pe_working_set_t * data_set)
2332 {
2333  int member_count = 0;
2334  int online_count = 0;
2335  int top_priority = 0;
2336  int lowest_priority = 0;
2337  GListPtr gIter = NULL;
2338 
2339  // `priority-fencing-delay` is disabled
2340  if (data_set->priority_fencing_delay <= 0) {
2341  return 0;
2342  }
2343 
2344  /* No need to request a delay if the fencing target is not a normal cluster
2345  * member, for example if it's a remote node or a guest node. */
2346  if (node->details->type != node_member) {
2347  return 0;
2348  }
2349 
2350  // No need to request a delay if the fencing target is in our partition
2351  if (node->details->online) {
2352  return 0;
2353  }
2354 
2355  for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
2356  pe_node_t *n = gIter->data;
2357 
2358  if (n->details->type != node_member) {
2359  continue;
2360  }
2361 
2362  member_count ++;
2363 
2364  if (n->details->online) {
2365  online_count++;
2366  }
2367 
2368  if (member_count == 1
2369  || n->details->priority > top_priority) {
2370  top_priority = n->details->priority;
2371  }
2372 
2373  if (member_count == 1
2374  || n->details->priority < lowest_priority) {
2375  lowest_priority = n->details->priority;
2376  }
2377  }
2378 
2379  // No need to delay if we have more than half of the cluster members
2380  if (online_count > member_count / 2) {
2381  return 0;
2382  }
2383 
2384  /* All the nodes have equal priority.
2385  * Any configured corresponding `pcmk_delay_base/max` will be applied. */
2386  if (lowest_priority == top_priority) {
2387  return 0;
2388  }
2389 
2390  if (node->details->priority < top_priority) {
2391  return 0;
2392  }
2393 
2394  return data_set->priority_fencing_delay;
2395 }
2396 
2397 pe_action_t *
2398 pe_fence_op(pe_node_t * node, const char *op, bool optional, const char *reason,
2399  bool priority_delay, pe_working_set_t * data_set)
2400 {
2401  char *op_key = NULL;
2402  pe_action_t *stonith_op = NULL;
2403 
2404  if(op == NULL) {
2405  op = data_set->stonith_action;
2406  }
2407 
2408  op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2409 
2410  if(data_set->singletons) {
2411  stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2412  }
2413 
2414  if(stonith_op == NULL) {
2415  stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2416 
2417  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2418  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2419  add_hash_param(stonith_op->meta, "stonith_action", op);
2420 
2421  if (pe__is_guest_or_remote_node(node)
2422  && is_set(data_set->flags, pe_flag_enable_unfencing)) {
2423  /* Extra work to detect device changes on remotes
2424  *
2425  * We may do this for all nodes in the future, but for now
2426  * the check_action_definition() based stuff works fine.
2427  */
2428  long max = 1024;
2429  long digests_all_offset = 0;
2430  long digests_secure_offset = 0;
2431 
2432  char *digests_all = calloc(max, sizeof(char));
2433  char *digests_secure = calloc(max, sizeof(char));
2434  GListPtr matches = find_unfencing_devices(data_set->resources, NULL);
2435 
2436  for (GListPtr gIter = matches; gIter != NULL; gIter = gIter->next) {
2437  pe_resource_t *match = gIter->data;
2438  const char *agent = g_hash_table_lookup(match->meta,
2439  XML_ATTR_TYPE);
2440  op_digest_cache_t *data = NULL;
2441 
2442  data = fencing_action_digest_cmp(match, agent, node, data_set);
2443  if(data->rc == RSC_DIGEST_ALL) {
2444  optional = FALSE;
2445  crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2446  if (is_set(data_set->flags, pe_flag_stdout)) {
2447  fprintf(stdout, " notice: Unfencing %s (remote): because the definition of %s changed\n", node->details->uname, match->id);
2448  }
2449  }
2450 
2451  digests_all_offset += snprintf(
2452  digests_all+digests_all_offset, max-digests_all_offset,
2453  "%s:%s:%s,", match->id, agent, data->digest_all_calc);
2454 
2455  digests_secure_offset += snprintf(
2456  digests_secure+digests_secure_offset, max-digests_secure_offset,
2457  "%s:%s:%s,", match->id, agent, data->digest_secure_calc);
2458  }
2459  g_hash_table_insert(stonith_op->meta,
2460  strdup(XML_OP_ATTR_DIGESTS_ALL),
2461  digests_all);
2462  g_hash_table_insert(stonith_op->meta,
2464  digests_secure);
2465  }
2466 
2467  } else {
2468  free(op_key);
2469  }
2470 
2471  if (data_set->priority_fencing_delay > 0
2472 
2473  /* It's a suitable case where `priority-fencing-delay` applies.
2474  * At least add `priority-fencing-delay` field as an indicator. */
2475  && (priority_delay
2476 
2477  /* Re-calculate priority delay for the suitable case when
2478  * pe_fence_op() is called again by stage6() after node priority has
2479  * been actually calculated with native_add_running() */
2480  || g_hash_table_lookup(stonith_op->meta,
2482 
2483  /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
2484  * the targeting node. So that it takes precedence over any possible
2485  * `pcmk_delay_base/max`.
2486  */
2487  char *delay_s = crm_itoa(node_priority_fencing_delay(node, data_set));
2488 
2489  g_hash_table_insert(stonith_op->meta,
2491  delay_s);
2492  }
2493 
2494  if(optional == FALSE && pe_can_fence(data_set, node)) {
2495  pe_action_required(stonith_op, NULL, reason);
2496  } else if(reason && stonith_op->reason == NULL) {
2497  stonith_op->reason = strdup(reason);
2498  }
2499 
2500  return stonith_op;
2501 }
2502 
2503 void
2505  pe_resource_t * rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t * data_set)
2506 {
2507  if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
2508  /* No resources require it */
2509  return;
2510 
2511  } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
2512  /* Wasn't a stonith device */
2513  return;
2514 
2515  } else if(node
2516  && node->details->online
2517  && node->details->unclean == FALSE
2518  && node->details->shutdown == FALSE) {
2519  pe_action_t *unfence = pe_fence_op(node, "on", FALSE, reason, FALSE, data_set);
2520 
2521  if(dependency) {
2522  order_actions(unfence, dependency, pe_order_optional);
2523  }
2524 
2525  } else if(rsc) {
2526  GHashTableIter iter;
2527 
2528  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2529  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2530  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2531  trigger_unfencing(rsc, node, reason, dependency, data_set);
2532  }
2533  }
2534  }
2535 }
2536 
2537 gboolean
2538 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2539 {
2540  pe_tag_t *tag = NULL;
2541  GListPtr gIter = NULL;
2542  gboolean is_existing = FALSE;
2543 
2544  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2545 
2546  tag = g_hash_table_lookup(tags, tag_name);
2547  if (tag == NULL) {
2548  tag = calloc(1, sizeof(pe_tag_t));
2549  if (tag == NULL) {
2550  return FALSE;
2551  }
2552  tag->id = strdup(tag_name);
2553  tag->refs = NULL;
2554  g_hash_table_insert(tags, strdup(tag_name), tag);
2555  }
2556 
2557  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2558  const char *existing_ref = (const char *) gIter->data;
2559 
2560  if (crm_str_eq(existing_ref, obj_ref, TRUE)){
2561  is_existing = TRUE;
2562  break;
2563  }
2564  }
2565 
2566  if (is_existing == FALSE) {
2567  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2568  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2569  }
2570 
2571  return TRUE;
2572 }
2573 
2574 void pe_action_set_flag_reason(const char *function, long line,
2575  pe_action_t *action, pe_action_t *reason, const char *text,
2576  enum pe_action_flags flags, bool overwrite)
2577 {
2578  bool unset = FALSE;
2579  bool update = FALSE;
2580  const char *change = NULL;
2581 
2582  if(is_set(flags, pe_action_runnable)) {
2583  unset = TRUE;
2584  change = "unrunnable";
2585  } else if(is_set(flags, pe_action_optional)) {
2586  unset = TRUE;
2587  change = "required";
2588  } else if(is_set(flags, pe_action_migrate_runnable)) {
2589  unset = TRUE;
2590  overwrite = TRUE;
2591  change = "unrunnable";
2592  } else if(is_set(flags, pe_action_dangle)) {
2593  change = "dangling";
2594  } else if(is_set(flags, pe_action_requires_any)) {
2595  change = "required";
2596  } else {
2597  crm_err("Unknown flag change to %x by %s: 0x%s",
2598  flags, action->uuid, (reason? reason->uuid : "0"));
2599  }
2600 
2601  if(unset) {
2602  if(is_set(action->flags, flags)) {
2603  action->flags = crm_clear_bit(function, line, action->uuid, action->flags, flags);
2604  update = TRUE;
2605  }
2606 
2607  } else {
2608  if(is_not_set(action->flags, flags)) {
2609  action->flags = crm_set_bit(function, line, action->uuid, action->flags, flags);
2610  update = TRUE;
2611  }
2612  }
2613 
2614  if((change && update) || text) {
2615  char *reason_text = NULL;
2616  if(reason == NULL) {
2617  pe_action_set_reason(action, text, overwrite);
2618 
2619  } else if(reason->rsc == NULL) {
2620  reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2621  } else {
2622  reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2623  }
2624 
2625  if(reason_text && action->rsc != reason->rsc) {
2626  pe_action_set_reason(action, reason_text, overwrite);
2627  }
2628  free(reason_text);
2629  }
2630  }
2631 
2632 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
2633 {
2634  if (action->reason != NULL && overwrite) {
2635  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
2636  action->uuid, action->reason, crm_str(reason));
2637  free(action->reason);
2638  } else if (action->reason == NULL) {
2639  pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
2640  action->uuid, crm_str(reason));
2641  } else {
2642  // crm_assert(action->reason != NULL && !overwrite);
2643  return;
2644  }
2645 
2646  if (reason != NULL) {
2647  action->reason = strdup(reason);
2648  } else {
2649  action->reason = NULL;
2650  }
2651 }
2652 
2665 bool
2667 {
2668  const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
2669 
2670  return shutdown && strcmp(shutdown, "0");
2671 }
2672 
2680 void
2681 pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
2682 {
2683  if ((recheck > get_effective_time(data_set))
2684  && ((data_set->recheck_by == 0)
2685  || (data_set->recheck_by > recheck))) {
2686  data_set->recheck_by = recheck;
2687  }
2688 }
2689 
2694 void
2695 pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name,
2696  GHashTable *node_hash, GHashTable *hash,
2697  const char *always_first, gboolean overwrite,
2698  pe_working_set_t *data_set)
2699 {
2700  crm_time_t *next_change = crm_time_new_undefined();
2701 
2702  pe_unpack_nvpairs(data_set->input, xml_obj, set_name, node_hash, hash,
2703  always_first, overwrite, data_set->now, next_change);
2704  if (crm_time_is_defined(next_change)) {
2705  time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
2706 
2707  pe__update_recheck_time(recheck, data_set);
2708  }
2709  crm_time_free(next_change);
2710 }
2711 
2712 bool
2714 {
2715  const char *target_role = NULL;
2716 
2717  CRM_CHECK(rsc != NULL, return false);
2718  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
2719  if (target_role) {
2720  enum rsc_role_e target_role_e = text2role(target_role);
2721 
2722  if ((target_role_e == RSC_ROLE_STOPPED)
2723  || ((target_role_e == RSC_ROLE_SLAVE)
2724  && is_set(uber_parent(rsc)->flags, pe_rsc_promotable))) {
2725  return true;
2726  }
2727  }
2728  return false;
2729 }
2730 
2740 pe_action_t *
2742  pe_working_set_t *data_set)
2743 {
2744  char *key = NULL;
2745 
2746  CRM_ASSERT(rsc && node);
2747  key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
2748  return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
2749  data_set);
2750 }
2751 
2752 bool
2754 {
2755  for (GListPtr ele = rsc->running_on; ele; ele = ele->next) {
2756  pe_node_t *node = (pe_node_t *) ele->data;
2757  if (pcmk__str_in_list(node_list, node->details->uname)) {
2758  return true;
2759  }
2760  }
2761 
2762  return false;
2763 }
2764 
2765 bool
2767 {
2768  return (rsc->fns->active(rsc, FALSE) && !pe__rsc_running_on_any_node_in_list(rsc, only_show));
2769 }
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:220
#define LOG_TRACE
Definition: logging.h:36
#define pe_rsc_starting
Definition: pe_types.h:256
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
GListPtr nodes
Definition: pe_types.h:146
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:280
enum rsc_start_requirement needs
Definition: pe_types.h:398
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:138
A dumping ground.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:48
GHashTable * pe__node_list2table(GList *list)
Definition: utils.c:201
#define crm_notice(fmt, args...)
Definition: logging.h:365
#define CRMD_ACTION_MIGRATED
Definition: crm.h:169
xmlNode * ops_xml
Definition: pe_types.h:309
GHashTable * attrs
Definition: pe_types.h:221
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:18
gboolean fixed
Definition: pe_types.h:229
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:263
#define INFINITY
Definition: crm.h:95
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
Definition: utils.c:458
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
Definition: strings.c:660
#define XML_OP_ATTR_DIGESTS_ALL
Definition: msg_xml.h:222
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:431
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:784
#define CRM_OP_FENCE
Definition: crm.h:141
void pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:1005
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:360
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:439
bool pe__rsc_running_on_any_node_in_list(pe_resource_t *rsc, GListPtr node_list)
Definition: utils.c:2753
pe_resource_t * container
Definition: pe_types.h:364
#define XML_ATTR_TYPE
Definition: msg_xml.h:99
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition: msg_xml.h:351
struct crm_time_s crm_time_t
Definition: iso8601.h:32
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:2681
enum rsc_role_e role
Definition: pe_types.h:354
gboolean standby
Definition: pe_types.h:438
int priority_fencing_delay
Definition: pe_types.h:179
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:144
xmlNode * op_defaults
Definition: pe_types.h:155
#define pcmk__config_err(fmt...)
Definition: internal.h:95
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:4399
#define pe_action_required(action, reason, text)
Definition: internal.h:415
xmlNode * xml
Definition: pe_types.h:307
pe_resource_t * rsc
Definition: pe_types.h:388
enum rsc_role_e next_role
Definition: pe_types.h:355
enum action_fail_response on_fail
Definition: pe_types.h:399
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:424
gboolean exclusive_discover
Definition: pe_types.h:336
#define pcmk__log_else(level, else_action)
Definition: logging.h:207
#define CRM_FEATURE_SET
Definition: crm.h:54
pe_resource_t * remote_rsc
Definition: pe_types.h:217
char * cancel_task
Definition: pe_types.h:394
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:211
GHashTable * meta
Definition: pe_types.h:357
#define pe_rsc_unique
Definition: pe_types.h:241
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:94
resource_object_functions_t * fns
Definition: pe_types.h:316
gboolean pe__is_guest_or_remote_node(pe_node_t *node)
Definition: remote.c:58
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:254
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:2574
GHashTable * parameters
Definition: pe_types.h:358
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:316
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:139
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:273
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:90
#define CRMD_ACTION_PROMOTE
Definition: crm.h:177
#define XML_LRM_ATTR_OP_RESTART
Definition: msg_xml.h:274
gboolean pending
Definition: pe_types.h:203
GListPtr resources
Definition: pe_types.h:147
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:339
#define XML_OP_ATTR_DIGESTS_SECURE
Definition: msg_xml.h:223
char * id
Definition: pe_types.h:443
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1653
#define CRM_ATTR_DIGESTS_ALL
Definition: crm.h:118
void pcmk__filter_op_for_digest(xmlNode *param_set)
Definition: operations.c:272
void print_node(const char *pre_text, pe_node_t *node, gboolean details)
Definition: utils.c:1310
enum action_tasks text2task(const char *task)
Definition: common.c:358
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:1770
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:1609
xmlNode * params_restart
Definition: internal.h:399
xmlNode * op_entry
Definition: pe_types.h:390
#define clear_bit(word, bit)
Definition: crm_internal.h:69
guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:309
#define XML_RSC_ATTR_PROVIDES
Definition: msg_xml.h:204
#define RSC_START
Definition: crm.h:196
void clear_bit_recursive(pe_resource_t *rsc, unsigned long long flag)
Definition: utils.c:2285
GHashTable * tickets
Definition: pe_types.h:141
pe_node_t * allocated_to
Definition: pe_types.h:347
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:217
pe_action_t * action
Definition: pe_types.h:507
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:558
#define pe_flag_have_quorum
Definition: pe_types.h:91
#define LOG_NEVER
Definition: logging.h:46
gboolean remote_requires_reset
Definition: pe_types.h:211
GListPtr actions_before
Definition: pe_types.h:425
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:211
char * reason
Definition: pe_types.h:395
pe_node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:411
void * action_details
Definition: pe_types.h:431
const char * action
Definition: pcmk_fence.c:29
#define XML_LRM_ATTR_OP_SECURE
Definition: msg_xml.h:275
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:2504
GHashTable * extra
Definition: pe_types.h:403
#define CRMD_ACTION_START
Definition: crm.h:171
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2142
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:163
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:260
const char * role2text(enum rsc_role_e role)
Definition: common.c:463
#define CRMD_ACTION_STOP
Definition: crm.h:174
#define pe_warn(fmt...)
Definition: internal.h:22
int weight
Definition: pe_types.h:228
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:167
guint remote_reconnect_ms
Definition: pe_types.h:329
#define CRMD_ACTION_DEMOTE
Definition: crm.h:179
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: utils.c:2632
#define set_bit(word, bit)
Definition: crm_internal.h:68
#define XML_RSC_ATTR_REQUIRES
Definition: msg_xml.h:203
pe_action_flags
Definition: pe_types.h:276
#define XML_ATTR_OP
Definition: msg_xml.h:101
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:614
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1875
#define crm_debug(fmt, args...)
Definition: logging.h:368
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:762
#define pe_flag_sanitized
Definition: pe_types.h:114
gboolean pe__resource_is_remote_conn(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: remote.c:17
#define XML_CIB_ATTR_SHUTDOWN
Definition: msg_xml.h:246
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:96
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:522
GListPtr find_recurring_actions(GListPtr input, pe_node_t *not_on_node)
Definition: utils.c:1384
char * digest_all_calc
Definition: internal.h:400
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:42
pe_ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:1904
char * task
Definition: pe_types.h:392
#define sort_return(an_int, why)
Definition: utils.c:1643
const char * pe__add_bundle_remote_name(pe_resource_t *rsc, xmlNode *xml, const char *field)
Definition: bundle.c:986
GListPtr refs
Definition: pe_types.h:444
#define crm_trace(fmt, args...)
Definition: logging.h:369
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1418
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:150
enum rsc_digest_cmp_val rc
Definition: internal.h:396
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:85
char * digest_secure_calc
Definition: internal.h:401
GHashTable * meta
Definition: pe_types.h:402
GListPtr find_actions(GListPtr input, const char *key, const pe_node_t *on_node)
Definition: utils.c:1472
void unpack_operation(pe_action_t *action, xmlNode *xml_obj, pe_resource_t *container, pe_working_set_t *data_set)
Unpack operation XML into an action structure.
Definition: utils.c:954
const char * stonith_action
Definition: pe_types.h:132
struct pe_node_shared_s * details
Definition: pe_types.h:231
GListPtr running_on
Definition: pe_types.h:350
gboolean get_target_role(pe_resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:1785
#define XML_TAG_OP_VER_META
Definition: msg_xml.h:168
pe_node_t * node
Definition: pe_types.h:389
void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition: utils.c:2695
bool pe__shutdown_requested(pe_node_t *node)
Definition: utils.c:2666
#define pe_rsc_needs_fencing
Definition: pe_types.h:265
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1823
unsigned long long flags
Definition: pe_types.h:332
const char * uname
Definition: pe_types.h:196
#define pe_rsc_promotable
Definition: pe_types.h:243
#define XML_TAG_META_SETS
Definition: msg_xml.h:164
GListPtr actions
Definition: pe_types.h:153
Wrappers for and extensions to libxml2.
Internal state tracking when creating graph.
Definition: pe_types.h:300
char * clone_name
Definition: pe_types.h:306
xmlNode * find_rsc_op_entry(pe_resource_t *rsc, const char *key)
Definition: utils.c:1304
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:2538
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1976
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:176
#define pe_flag_stonith_enabled
Definition: pe_types.h:95
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:649
#define CRM_ATTR_DIGESTS_SECURE
Definition: crm.h:119
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:629
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:138
time_t last_granted
Definition: pe_types.h:437
GHashTable * utilization
Definition: pe_types.h:359
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:196
char * uuid
Definition: pe_types.h:393
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:276
#define XML_TAG_RSC_VER_ATTRS
Definition: msg_xml.h:166
void free_xml(xmlNode *child)
Definition: xml.c:2136
enum rsc_role_e text2role(const char *role)
Definition: common.c:484
enum pe_obj_types variant
Definition: pe_types.h:314
xmlNode * input
Definition: pe_types.h:126
int pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
Definition: utils.c:870
gboolean granted
Definition: pe_types.h:436
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:326
int rsc_discover_mode
Definition: pe_types.h:232
xmlNode * params_all
Definition: internal.h:397
GListPtr actions
Definition: pe_types.h:343
void(* print)(pe_resource_t *, const char *, long, void *)
Definition: pe_types.h:50
const char * id
Definition: pe_types.h:195
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:40
char * id
Definition: pe_types.h:435
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:263
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:474
#define pe_rsc_fence_device
Definition: pe_types.h:242
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:308
bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
Definition: utils.c:87
GListPtr running_rsc
Definition: pe_types.h:218
void dump_node_capacity(int level, const char *comment, pe_node_t *node)
Definition: utils.c:395
void get_rsc_attributes(GHashTable *meta_hash, pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: complex.c:129
gboolean pe__is_guest_node(pe_node_t *node)
Definition: remote.c:47
GListPtr children
Definition: pe_types.h:361
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:573
#define pe_set_action_bit(action, bit)
Definition: internal.h:25
int sort_index
Definition: pe_types.h:326
bool pcmk__rsc_is_filtered(pe_resource_t *rsc, GListPtr only_show)
Definition: utils.c:2766
int pe__add_scores(int score1, int score2)
Definition: common.c:510
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:210
void node_list_exclude(GHashTable *list, GListPtr list2, gboolean merge_scores)
Definition: utils.c:158
op_digest_cache_t * rsc_action_digest_cmp(pe_resource_t *rsc, xmlNode *xml_op, pe_node_t *node, pe_working_set_t *data_set)
Definition: utils.c:2095
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:2276
#define RSC_PROMOTE
Definition: crm.h:202
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:93
#define pe_clear_action_bit(action, bit)
Definition: internal.h:26
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3340
void dump_rsc_utilization(int level, const char *comment, pe_resource_t *rsc, pe_node_t *node)
Definition: utils.c:412
GListPtr actions_after
Definition: pe_types.h:426
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:258
xmlNode * params_secure
Definition: internal.h:398
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:272
#define CRMD_ACTION_MIGRATE
Definition: crm.h:168
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:340
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry, as meta-attribute name.
Definition: nvpair.c:812
#define crm_str_hash
Definition: util.h:66
GHashTable * utilization
Definition: pe_types.h:222
enum rsc_role_e fail_role
Definition: pe_types.h:400
gboolean shutdown
Definition: pe_types.h:206
char data[0]
Definition: internal.h:90
#define crm_str(x)
Definition: logging.h:389
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:79
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:155
#define pe_rsc_stopping
Definition: pe_types.h:257
rsc_role_e
Definition: common.h:76
#define pe_flag_stdout
Definition: pe_types.h:115
enum pe_action_flags flags
Definition: pe_types.h:397
GHashTable * digest_cache
cache of calculated resource digests
Definition: pe_types.h:223
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:218
void destroy_ticket(gpointer data)
Definition: utils.c:1892
#define pe_rsc_needs_quorum
Definition: pe_types.h:264
gboolean crm_is_true(const char *s)
Definition: strings.c:278
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)
Definition: utils.c:350
#define pe_flag_have_stonith_resource
Definition: pe_types.h:96
GList * find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
Definition: utils.c:1512
#define pe_flag_enable_unfencing
Definition: pe_types.h:97
void set_bit_recursive(pe_resource_t *rsc, unsigned long long flag)
Definition: utils.c:2298
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:262
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:19
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:51
bool pe__resource_is_disabled(pe_resource_t *rsc)
Definition: utils.c:2713
pe_action_t * find_first_action(GListPtr input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1442
GHashTable * singletons
Definition: pe_types.h:144
#define ID(x)
Definition: msg_xml.h:418
unsigned long long flags
Definition: pe_types.h:135
#define pe_err(fmt...)
Definition: internal.h:21
#define safe_str_eq(a, b)
Definition: util.h:65
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:1561
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: utils.c:2741
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1349
char * name
Definition: pcmk_fence.c:30
#define CRM_OP_LRM_DELETE
Definition: crm.h:147
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:215
enum pe_ordering type
Definition: pe_types.h:505
gboolean unclean
Definition: pe_types.h:204
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
unsigned int timeout
Definition: pcmk_fence.c:31
#define LOG_STDOUT
Definition: logging.h:41
GList * GListPtr
Definition: crm.h:214
#define STONITH_DIGEST_TASK
Definition: utils.c:2210
enum node_type type
Definition: pe_types.h:197
#define CRMD_ACTION_CANCEL
Definition: crm.h:165
crm_time_t * now
Definition: pe_types.h:127
#define XML_TAG_PARAMS
Definition: msg_xml.h:169
#define crm_info(fmt, args...)
Definition: logging.h:366
char * digest_restart_calc
Definition: internal.h:402
#define pe_rsc_managed
Definition: pe_types.h:236
#define pe_rsc_orphan
Definition: pe_types.h:235
#define XML_ATTR_RA_VERSION
Definition: msg_xml.h:82
pe_ordering
Definition: pe_types.h:461
gboolean online
Definition: pe_types.h:200
uint64_t flags
Definition: remote.c:149
#define XML_TAG_OP_VER_ATTRS
Definition: msg_xml.h:167
action_tasks
Definition: common.h:47
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:2398
void pe_free_action(pe_action_t *action)
Definition: utils.c:1357
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:17
char * id
Definition: pe_types.h:305
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Definition: utils.c:485
GHashTable * allowed_nodes
Definition: pe_types.h:352
#define CRMD_ACTION_STATUS
Definition: crm.h:185
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:4425
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:141