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