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