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