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 action_t *
455 custom_action(resource_t * rsc, char *key, const char *task,
456  node_t * on_node, gboolean optional, gboolean save_action,
457  pe_working_set_t * data_set)
458 {
459  action_t *action = NULL;
460  GListPtr possible_matches = NULL;
461 
462  CRM_CHECK(key != NULL, return NULL);
463  CRM_CHECK(task != NULL, free(key); return NULL);
464 
465  if (save_action && rsc != NULL) {
466  possible_matches = find_actions(rsc->actions, key, on_node);
467  } else if(save_action) {
468 #if 0
469  action = g_hash_table_lookup(data_set->singletons, key);
470 #else
471  /* More expensive but takes 'node' into account */
472  possible_matches = find_actions(data_set->actions, key, on_node);
473 #endif
474  }
475 
476  if(data_set->singletons == NULL) {
477  data_set->singletons = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
478  }
479 
480  if (possible_matches != NULL) {
481  if (g_list_length(possible_matches) > 1) {
482  pe_warn("Action %s for %s on %s exists %d times",
483  task, rsc ? rsc->id : "<NULL>",
484  on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
485  }
486 
487  action = g_list_nth_data(possible_matches, 0);
488  pe_rsc_trace(rsc, "Found existing action %d (%s) for %s (%s) on %s",
489  action->id, action->uuid,
490  (rsc? rsc->id : "no resource"), task,
491  (on_node? on_node->details->uname : "no node"));
492  g_list_free(possible_matches);
493  }
494 
495  if (action == NULL) {
496  if (save_action) {
497  pe_rsc_trace(rsc, "Creating %s action %d: %s for %s (%s) on %s",
498  (optional? "optional" : " mandatory"),
499  data_set->action_id, key,
500  (rsc? rsc->id : "no resource"), task,
501  (on_node? on_node->details->uname : "no node"));
502  }
503 
504  action = calloc(1, sizeof(action_t));
505  if (save_action) {
506  action->id = data_set->action_id++;
507  } else {
508  action->id = 0;
509  }
510  action->rsc = rsc;
511  CRM_ASSERT(task != NULL);
512  action->task = strdup(task);
513  if (on_node) {
514  action->node = node_copy(on_node);
515  }
516  action->uuid = strdup(key);
517 
519  if (optional) {
521  } else {
523  }
524 
525  action->extra = crm_str_table_new();
526  action->meta = crm_str_table_new();
527 
528  if (save_action) {
529  data_set->actions = g_list_prepend(data_set->actions, action);
530  if(rsc == NULL) {
531  g_hash_table_insert(data_set->singletons, action->uuid, action);
532  }
533  }
534 
535  if (rsc != NULL) {
536  action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
537 
538  unpack_operation(action, action->op_entry, rsc->container, data_set);
539 
540  if (save_action) {
541  rsc->actions = g_list_prepend(rsc->actions, action);
542  }
543  }
544 
545  if (save_action) {
546  pe_rsc_trace(rsc, "Action %d created", action->id);
547  }
548  }
549 
550  if (!optional && is_set(action->flags, pe_action_optional)) {
551  pe_rsc_trace(rsc, "Unset optional on action %d", action->id);
553  }
554 
555  if (rsc != NULL) {
556  enum action_tasks a_task = text2task(action->task);
557  int warn_level = LOG_TRACE;
558 
559  if (save_action) {
560  warn_level = LOG_WARNING;
561  }
562 
563  if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
564  && action->node != NULL && action->op_entry != NULL) {
567  action->node->details->attrs,
568  action->extra, NULL, FALSE, data_set);
569  }
570 
571  if (is_set(action->flags, pe_action_pseudo)) {
572  /* leave untouched */
573 
574  } else if (action->node == NULL) {
575  pe_rsc_trace(rsc, "Unset runnable on %s", action->uuid);
577 
578  } else if (is_not_set(rsc->flags, pe_rsc_managed)
579  && g_hash_table_lookup(action->meta,
580  XML_LRM_ATTR_INTERVAL_MS) == NULL) {
581  crm_debug("Action %s (unmanaged)", action->uuid);
582  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
584 /* action->runnable = FALSE; */
585 
586  } else if (action->node->details->online == FALSE
587  && (!pe__is_guest_node(action->node)
588  || action->node->details->remote_requires_reset)) {
590  do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
591  action->uuid, action->node->details->uname);
592  if (is_set(action->rsc->flags, pe_rsc_managed)
593  && save_action && a_task == stop_rsc
594  && action->node->details->unclean == FALSE) {
595  pe_fence_node(data_set, action->node, "resource actions are unrunnable");
596  }
597 
598  } else if (action->node->details->pending) {
600  do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
601  action->uuid, action->node->details->uname);
602 
603  } else if (action->needs == rsc_req_nothing) {
604  pe_rsc_trace(rsc, "Action %s does not require anything", action->uuid);
605  pe_action_set_reason(action, NULL, TRUE);
606  if (pe__is_guest_node(action->node)
607  && !pe_can_fence(data_set, action->node)) {
608  /* An action that requires nothing usually does not require any
609  * fencing in order to be runnable. However, there is an
610  * exception: an action cannot be completed if it is on a guest
611  * node whose host is unclean and cannot be fenced.
612  */
614  crm_debug("%s\t%s (cancelled : host cannot be fenced)",
615  action->node->details->uname, action->uuid);
616  } else {
618  }
619 #if 0
620  /*
621  * No point checking this
622  * - if we don't have quorum we can't stonith anyway
623  */
624  } else if (action->needs == rsc_req_stonith) {
625  crm_trace("Action %s requires only stonith", action->uuid);
626  action->runnable = TRUE;
627 #endif
628  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
629  && data_set->no_quorum_policy == no_quorum_stop) {
630  pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "no quorum", pe_action_runnable, TRUE);
631  crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);
632 
633  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
634  && data_set->no_quorum_policy == no_quorum_freeze) {
635  pe_rsc_trace(rsc, "Check resource is already active: %s %s %s %s", rsc->id, action->uuid, role2text(rsc->next_role), role2text(rsc->role));
636  if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
637  pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "quorum freeze", pe_action_runnable, TRUE);
638  pe_rsc_debug(rsc, "%s\t%s (cancelled : quorum freeze)",
639  action->node->details->uname, action->uuid);
640  }
641 
642  } else if(is_not_set(action->flags, pe_action_runnable)) {
643  pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
644  //pe_action_set_reason(action, NULL, TRUE);
646  }
647 
648  if (save_action) {
649  switch (a_task) {
650  case stop_rsc:
652  break;
653  case start_rsc:
655  if (is_set(action->flags, pe_action_runnable)) {
657  }
658  break;
659  default:
660  break;
661  }
662  }
663  }
664 
665  free(key);
666  return action;
667 }
668 
669 static const char *
670 unpack_operation_on_fail(action_t * action)
671 {
672 
673  const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
674 
675  if (safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) {
676  crm_config_err("on-fail=standby is not allowed for stop actions: %s", action->rsc->id);
677  return NULL;
678  } else if (safe_str_eq(action->task, CRMD_ACTION_DEMOTE) && !value) {
679  /* demote on_fail defaults to master monitor value if present */
680  xmlNode *operation = NULL;
681  const char *name = NULL;
682  const char *role = NULL;
683  const char *on_fail = NULL;
684  const char *interval_spec = NULL;
685  const char *enabled = NULL;
686 
687  CRM_CHECK(action->rsc != NULL, return NULL);
688 
689  for (operation = __xml_first_child_element(action->rsc->ops_xml);
690  operation && !value; operation = __xml_next_element(operation)) {
691 
692  if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
693  continue;
694  }
695  name = crm_element_value(operation, "name");
696  role = crm_element_value(operation, "role");
697  on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
698  enabled = crm_element_value(operation, "enabled");
699  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
700  if (!on_fail) {
701  continue;
702  } else if (enabled && !crm_is_true(enabled)) {
703  continue;
704  } else if (safe_str_neq(name, "monitor") || safe_str_neq(role, "Master")) {
705  continue;
706  } else if (crm_parse_interval_spec(interval_spec) == 0) {
707  continue;
708  }
709 
710  value = on_fail;
711  }
712  }
713 
714  return value;
715 }
716 
717 static xmlNode *
718 find_min_interval_mon(resource_t * rsc, gboolean include_disabled)
719 {
720  guint interval_ms = 0;
721  guint min_interval_ms = G_MAXUINT;
722  const char *name = NULL;
723  const char *value = NULL;
724  const char *interval_spec = NULL;
725  xmlNode *op = NULL;
726  xmlNode *operation = NULL;
727 
728  for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
729  operation = __xml_next_element(operation)) {
730 
731  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
732  name = crm_element_value(operation, "name");
733  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
734  value = crm_element_value(operation, "enabled");
735  if (!include_disabled && value && crm_is_true(value) == FALSE) {
736  continue;
737  }
738 
739  if (safe_str_neq(name, RSC_STATUS)) {
740  continue;
741  }
742 
743  interval_ms = crm_parse_interval_spec(interval_spec);
744 
745  if (interval_ms && (interval_ms < min_interval_ms)) {
746  min_interval_ms = interval_ms;
747  op = operation;
748  }
749  }
750  }
751 
752  return op;
753 }
754 
755 static int
756 unpack_start_delay(const char *value, GHashTable *meta)
757 {
758  int start_delay = 0;
759 
760  if (value != NULL) {
761  start_delay = crm_get_msec(value);
762 
763  if (start_delay < 0) {
764  start_delay = 0;
765  }
766 
767  if (meta) {
768  g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY), crm_itoa(start_delay));
769  }
770  }
771 
772  return start_delay;
773 }
774 
775 // true if value contains valid, non-NULL interval origin for recurring op
776 static bool
777 unpack_interval_origin(const char *value, xmlNode *xml_obj, guint interval_ms,
778  crm_time_t *now, long long *start_delay)
779 {
780  long long result = 0;
781  guint interval_sec = interval_ms / 1000;
782  crm_time_t *origin = NULL;
783 
784  // Ignore unspecified values and non-recurring operations
785  if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
786  return false;
787  }
788 
789  // Parse interval origin from text
790  origin = crm_time_new(value);
791  if (origin == NULL) {
792  crm_config_err("Operation '%s' contains invalid " XML_OP_ATTR_ORIGIN
793  " '%s'",
794  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"), value);
795  return false;
796  }
797 
798  // Get seconds since origin (negative if origin is in the future)
799  result = crm_time_get_seconds(now) - crm_time_get_seconds(origin);
800  crm_time_free(origin);
801 
802  // Calculate seconds from closest interval to now
803  result = result % interval_sec;
804 
805  // Calculate seconds remaining until next interval
806  result = ((result <= 0)? 0 : interval_sec) - result;
807  crm_info("Calculated a start delay of %llds for operation '%s'",
808  result,
809  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
810 
811  if (start_delay != NULL) {
812  *start_delay = result * 1000; // milliseconds
813  }
814  return true;
815 }
816 
817 static int
818 unpack_timeout(const char *value)
819 {
820  int timeout = crm_get_msec(value);
821 
822  if (timeout < 0) {
824  }
825  return timeout;
826 }
827 
828 int
829 pe_get_configured_timeout(resource_t *rsc, const char *action, pe_working_set_t *data_set)
830 {
831  xmlNode *child = NULL;
832  const char *timeout = NULL;
833  int timeout_ms = 0;
834 
835  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
836  child != NULL; child = crm_next_same_xml(child)) {
837  if (safe_str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME))) {
838  timeout = crm_element_value(child, XML_ATTR_TIMEOUT);
839  break;
840  }
841  }
842 
843  if (timeout == NULL && data_set->op_defaults) {
844  GHashTable *action_meta = crm_str_table_new();
846  NULL, action_meta, NULL, FALSE, data_set);
847  timeout = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
848  }
849 
850  // @TODO check meta-attributes (including versioned meta-attributes)
851  // @TODO maybe use min-interval monitor timeout as default for monitors
852 
853  timeout_ms = crm_get_msec(timeout);
854  if (timeout_ms < 0) {
856  }
857  return timeout_ms;
858 }
859 
860 #if ENABLE_VERSIONED_ATTRS
861 static void
862 unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj,
863  guint interval_ms, crm_time_t *now)
864 {
865  xmlNode *attrs = NULL;
866  xmlNode *attr = NULL;
867 
868  for (attrs = __xml_first_child_element(versioned_meta); attrs != NULL;
869  attrs = __xml_next_element(attrs)) {
870 
871  for (attr = __xml_first_child_element(attrs); attr != NULL;
872  attr = __xml_next_element(attr)) {
873 
874  const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
875  const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
876 
878  int start_delay = unpack_start_delay(value, NULL);
879 
880  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
881  } else if (safe_str_eq(name, XML_OP_ATTR_ORIGIN)) {
882  long long start_delay = 0;
883 
884  if (unpack_interval_origin(value, xml_obj, interval_ms, now,
885  &start_delay)) {
888  crm_xml_add_ll(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
889  }
890  } else if (safe_str_eq(name, XML_ATTR_TIMEOUT)) {
891  int timeout = unpack_timeout(value);
892 
893  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout);
894  }
895  }
896  }
897 }
898 #endif
899 
912 void
913 unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
914  pe_working_set_t * data_set)
915 {
916  guint interval_ms = 0;
917  int timeout = 0;
918  char *value_ms = NULL;
919  const char *value = NULL;
920  const char *field = NULL;
921  char *default_timeout = NULL;
922 #if ENABLE_VERSIONED_ATTRS
923  pe_rsc_action_details_t *rsc_details = NULL;
924 #endif
925 
926  CRM_CHECK(action && action->rsc, return);
927 
928  // Cluster-wide <op_defaults> <meta_attributes>
930  action->meta, NULL, FALSE, data_set);
931 
932  // Probe timeouts default differently, so handle timeout default later
933  default_timeout = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
934  if (default_timeout) {
935  default_timeout = strdup(default_timeout);
936  g_hash_table_remove(action->meta, XML_ATTR_TIMEOUT);
937  }
938 
939  if (xml_obj) {
940  xmlAttrPtr xIter = NULL;
941 
942  // <op> <meta_attributes> take precedence over defaults
944  action->meta, NULL, TRUE, data_set);
945 
946 #if ENABLE_VERSIONED_ATTRS
947  rsc_details = pe_rsc_action_details(action);
948  pe_unpack_versioned_attributes(data_set->input, xml_obj,
949  XML_TAG_ATTR_SETS, NULL,
950  rsc_details->versioned_parameters,
951  data_set->now, NULL);
952  pe_unpack_versioned_attributes(data_set->input, xml_obj,
953  XML_TAG_META_SETS, NULL,
954  rsc_details->versioned_meta,
955  data_set->now, NULL);
956 #endif
957 
958  /* Anything set as an <op> XML property has highest precedence.
959  * This ensures we use the name and interval from the <op> tag.
960  */
961  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
962  const char *prop_name = (const char *)xIter->name;
963  const char *prop_value = crm_element_value(xml_obj, prop_name);
964 
965  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
966  }
967  }
968 
969  g_hash_table_remove(action->meta, "id");
970 
971  // Normalize interval to milliseconds
972  field = XML_LRM_ATTR_INTERVAL;
973  value = g_hash_table_lookup(action->meta, field);
974  if (value != NULL) {
975  interval_ms = crm_parse_interval_spec(value);
976 
977  } else if ((xml_obj == NULL) && !strcmp(action->task, RSC_STATUS)) {
978  /* An orphaned recurring monitor will not have any XML. However, we
979  * want the interval to be set, so the action can be properly detected
980  * as a recurring monitor. Parse it from the key in this case.
981  */
982  parse_op_key(action->uuid, NULL, NULL, &interval_ms);
983  }
984  if (interval_ms > 0) {
985  value_ms = crm_strdup_printf("%u", interval_ms);
986  g_hash_table_replace(action->meta, strdup(field), value_ms);
987 
988  } else if (value) {
989  g_hash_table_remove(action->meta, field);
990  }
991 
992  // Handle timeout default, now that we know the interval
993  if (g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT)) {
994  free(default_timeout);
995 
996  } else {
997  // Probe timeouts default to minimum-interval monitor's
998  if (safe_str_eq(action->task, RSC_STATUS) && (interval_ms == 0)) {
999 
1000  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
1001 
1002  if (min_interval_mon) {
1003  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
1004  if (value) {
1005  crm_trace("\t%s defaults to minimum-interval monitor's timeout '%s'",
1006  action->uuid, value);
1007  free(default_timeout);
1008  default_timeout = strdup(value);
1009  }
1010  }
1011  }
1012 
1013  if (default_timeout) {
1014  g_hash_table_insert(action->meta, strdup(XML_ATTR_TIMEOUT),
1015  default_timeout);
1016  }
1017  }
1018 
1019  if (safe_str_neq(action->task, RSC_START)
1020  && safe_str_neq(action->task, RSC_PROMOTE)) {
1021  action->needs = rsc_req_nothing;
1022  value = "nothing (not start/promote)";
1023 
1024  } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1025  action->needs = rsc_req_stonith;
1026  value = "fencing (resource)";
1027 
1028  } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1029  action->needs = rsc_req_quorum;
1030  value = "quorum (resource)";
1031 
1032  } else {
1033  action->needs = rsc_req_nothing;
1034  value = "nothing (resource)";
1035  }
1036 
1037  pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->uuid, value);
1038 
1039  value = unpack_operation_on_fail(action);
1040 
1041  if (value == NULL) {
1042 
1043  } else if (safe_str_eq(value, "block")) {
1044  action->on_fail = action_fail_block;
1045  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1046  value = "block"; // The above could destroy the original string
1047 
1048  } else if (safe_str_eq(value, "fence")) {
1049  action->on_fail = action_fail_fence;
1050  value = "node fencing";
1051 
1052  if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
1053  crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense");
1054  action->on_fail = action_fail_stop;
1055  action->fail_role = RSC_ROLE_STOPPED;
1056  value = "stop resource";
1057  }
1058 
1059  } else if (safe_str_eq(value, "standby")) {
1060  action->on_fail = action_fail_standby;
1061  value = "node standby";
1062 
1063  } else if (safe_str_eq(value, "ignore")
1064  || safe_str_eq(value, "nothing")) {
1065  action->on_fail = action_fail_ignore;
1066  value = "ignore";
1067 
1068  } else if (safe_str_eq(value, "migrate")) {
1069  action->on_fail = action_fail_migrate;
1070  value = "force migration";
1071 
1072  } else if (safe_str_eq(value, "stop")) {
1073  action->on_fail = action_fail_stop;
1074  action->fail_role = RSC_ROLE_STOPPED;
1075  value = "stop resource";
1076 
1077  } else if (safe_str_eq(value, "restart")) {
1078  action->on_fail = action_fail_recover;
1079  value = "restart (and possibly migrate)";
1080 
1081  } else if (safe_str_eq(value, "restart-container")) {
1082  if (container) {
1084  value = "restart container (and possibly migrate)";
1085 
1086  } else {
1087  value = NULL;
1088  }
1089 
1090  } else {
1091  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1092  value = NULL;
1093  }
1094 
1095  /* defaults */
1096  if (value == NULL && container) {
1098  value = "restart container (and possibly migrate) (default)";
1099 
1100  /* For remote nodes, ensure that any failure that results in dropping an
1101  * active connection to the node results in fencing of the node.
1102  *
1103  * There are only two action failures that don't result in fencing.
1104  * 1. probes - probe failures are expected.
1105  * 2. start - a start failure indicates that an active connection does not already
1106  * exist. The user can set op on-fail=fence if they really want to fence start
1107  * failures. */
1108  } else if (((value == NULL) || !is_set(action->rsc->flags, pe_rsc_managed)) &&
1109  (pe__resource_is_remote_conn(action->rsc, data_set) &&
1110  !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && (interval_ms == 0)) &&
1111  (safe_str_neq(action->task, CRMD_ACTION_START)))) {
1112 
1113  if (!is_set(action->rsc->flags, pe_rsc_managed)) {
1114  action->on_fail = action_fail_stop;
1115  action->fail_role = RSC_ROLE_STOPPED;
1116  value = "stop unmanaged remote node (enforcing default)";
1117 
1118  } else {
1119  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1120  value = "fence remote node (default)";
1121  } else {
1122  value = "recover remote node connection (default)";
1123  }
1124 
1125  if (action->rsc->remote_reconnect_ms) {
1126  action->fail_role = RSC_ROLE_STOPPED;
1127  }
1129  }
1130 
1131  } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
1132  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1133  action->on_fail = action_fail_fence;
1134  value = "resource fence (default)";
1135 
1136  } else {
1137  action->on_fail = action_fail_block;
1138  value = "resource block (default)";
1139  }
1140 
1141  } else if (value == NULL) {
1142  action->on_fail = action_fail_recover;
1143  value = "restart (and possibly migrate) (default)";
1144  }
1145 
1146  pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
1147 
1148  value = NULL;
1149  if (xml_obj != NULL) {
1150  value = g_hash_table_lookup(action->meta, "role_after_failure");
1151  if (value) {
1153  "Support for role_after_failure is deprecated and will be removed in a future release");
1154  }
1155  }
1156  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1157  action->fail_role = text2role(value);
1158  }
1159  /* defaults */
1160  if (action->fail_role == RSC_ROLE_UNKNOWN) {
1161  if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
1162  action->fail_role = RSC_ROLE_SLAVE;
1163  } else {
1164  action->fail_role = RSC_ROLE_STARTED;
1165  }
1166  }
1167  pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
1168  role2text(action->fail_role));
1169 
1170  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1171  if (value) {
1172  unpack_start_delay(value, action->meta);
1173  } else {
1174  long long start_delay = 0;
1175 
1176  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1177  if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
1178  &start_delay)) {
1179  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
1180  crm_strdup_printf("%lld", start_delay));
1181  }
1182  }
1183 
1184  value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
1185  timeout = unpack_timeout(value);
1186  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT), crm_itoa(timeout));
1187 
1188 #if ENABLE_VERSIONED_ATTRS
1189  unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval_ms,
1190  data_set->now);
1191 #endif
1192 }
1193 
1194 static xmlNode *
1195 find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_disabled)
1196 {
1197  guint interval_ms = 0;
1198  gboolean do_retry = TRUE;
1199  char *local_key = NULL;
1200  const char *name = NULL;
1201  const char *value = NULL;
1202  const char *interval_spec = NULL;
1203  char *match_key = NULL;
1204  xmlNode *op = NULL;
1205  xmlNode *operation = NULL;
1206 
1207  retry:
1208  for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
1209  operation = __xml_next_element(operation)) {
1210  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
1211  name = crm_element_value(operation, "name");
1212  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1213  value = crm_element_value(operation, "enabled");
1214  if (!include_disabled && value && crm_is_true(value) == FALSE) {
1215  continue;
1216  }
1217 
1218  interval_ms = crm_parse_interval_spec(interval_spec);
1219  match_key = generate_op_key(rsc->id, name, interval_ms);
1220  if (safe_str_eq(key, match_key)) {
1221  op = operation;
1222  }
1223  free(match_key);
1224 
1225  if (rsc->clone_name) {
1226  match_key = generate_op_key(rsc->clone_name, name, interval_ms);
1227  if (safe_str_eq(key, match_key)) {
1228  op = operation;
1229  }
1230  free(match_key);
1231  }
1232 
1233  if (op != NULL) {
1234  free(local_key);
1235  return op;
1236  }
1237  }
1238  }
1239 
1240  free(local_key);
1241  if (do_retry == FALSE) {
1242  return NULL;
1243  }
1244 
1245  do_retry = FALSE;
1246  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1247  local_key = generate_op_key(rsc->id, "migrate", 0);
1248  key = local_key;
1249  goto retry;
1250 
1251  } else if (strstr(key, "_notify_")) {
1252  local_key = generate_op_key(rsc->id, "notify", 0);
1253  key = local_key;
1254  goto retry;
1255  }
1256 
1257  return NULL;
1258 }
1259 
1260 xmlNode *
1261 find_rsc_op_entry(resource_t * rsc, const char *key)
1262 {
1263  return find_rsc_op_entry_helper(rsc, key, FALSE);
1264 }
1265 
1266 void
1267 print_node(const char *pre_text, node_t * node, gboolean details)
1268 {
1269  if (node == NULL) {
1270  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1271  return;
1272  }
1273 
1274  CRM_ASSERT(node->details);
1275  crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1276  pre_text == NULL ? "" : pre_text,
1277  pre_text == NULL ? "" : ": ",
1278  node->details->online ? "" : "Unavailable/Unclean ",
1279  node->details->uname, node->weight, node->fixed ? "True" : "False");
1280 
1281  if (details) {
1282  int log_level = LOG_TRACE;
1283 
1284  char *pe_mutable = strdup("\t\t");
1285  GListPtr gIter = node->details->running_rsc;
1286 
1287  crm_trace("\t\t===Node Attributes");
1288  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1289  free(pe_mutable);
1290 
1291  crm_trace("\t\t=== Resources");
1292 
1293  for (; gIter != NULL; gIter = gIter->next) {
1294  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1295 
1296  rsc->fns->print(rsc, "\t\t", pe_print_log|pe_print_pending,
1297  &log_level);
1298  }
1299  }
1300 }
1301 
1302 /*
1303  * Used by the HashTable for-loop
1304  */
1305 void
1306 print_str_str(gpointer key, gpointer value, gpointer user_data)
1307 {
1308  crm_trace("%s%s %s ==> %s",
1309  user_data == NULL ? "" : (char *)user_data,
1310  user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1311 }
1312 
1313 void
1315 {
1316  if (action == NULL) {
1317  return;
1318  }
1319  g_list_free_full(action->actions_before, free); /* action_wrapper_t* */
1320  g_list_free_full(action->actions_after, free); /* action_wrapper_t* */
1321  if (action->extra) {
1322  g_hash_table_destroy(action->extra);
1323  }
1324  if (action->meta) {
1325  g_hash_table_destroy(action->meta);
1326  }
1327 #if ENABLE_VERSIONED_ATTRS
1328  if (action->rsc) {
1329  pe_free_rsc_action_details(action);
1330  }
1331 #endif
1332  free(action->cancel_task);
1333  free(action->reason);
1334  free(action->task);
1335  free(action->uuid);
1336  free(action->node);
1337  free(action);
1338 }
1339 
1340 GListPtr
1342 {
1343  const char *value = NULL;
1344  GListPtr result = NULL;
1345  GListPtr gIter = input;
1346 
1347  CRM_CHECK(input != NULL, return NULL);
1348 
1349  for (; gIter != NULL; gIter = gIter->next) {
1350  action_t *action = (action_t *) gIter->data;
1351 
1352  value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL_MS);
1353  if (value == NULL) {
1354  /* skip */
1355  } else if (safe_str_eq(value, "0")) {
1356  /* skip */
1357  } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1358  /* skip */
1359  } else if (not_on_node == NULL) {
1360  crm_trace("(null) Found: %s", action->uuid);
1361  result = g_list_prepend(result, action);
1362 
1363  } else if (action->node == NULL) {
1364  /* skip */
1365  } else if (action->node->details != not_on_node->details) {
1366  crm_trace("Found: %s", action->uuid);
1367  result = g_list_prepend(result, action);
1368  }
1369  }
1370 
1371  return result;
1372 }
1373 
1374 enum action_tasks
1375 get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic)
1376 {
1377  enum action_tasks task = text2task(name);
1378 
1379  if (rsc == NULL) {
1380  return task;
1381 
1382  } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1383  switch (task) {
1384  case stopped_rsc:
1385  case started_rsc:
1386  case action_demoted:
1387  case action_promoted:
1388  crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1389  return task - 1;
1390  break;
1391  default:
1392  break;
1393  }
1394  }
1395  return task;
1396 }
1397 
1398 action_t *
1399 find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node)
1400 {
1401  GListPtr gIter = NULL;
1402 
1403  CRM_CHECK(uuid || task, return NULL);
1404 
1405  for (gIter = input; gIter != NULL; gIter = gIter->next) {
1406  action_t *action = (action_t *) gIter->data;
1407 
1408  if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1409  continue;
1410 
1411  } else if (task != NULL && safe_str_neq(task, action->task)) {
1412  continue;
1413 
1414  } else if (on_node == NULL) {
1415  return action;
1416 
1417  } else if (action->node == NULL) {
1418  continue;
1419 
1420  } else if (on_node->details == action->node->details) {
1421  return action;
1422  }
1423  }
1424 
1425  return NULL;
1426 }
1427 
1428 GListPtr
1429 find_actions(GListPtr input, const char *key, const node_t *on_node)
1430 {
1431  GListPtr gIter = input;
1432  GListPtr result = NULL;
1433 
1434  CRM_CHECK(key != NULL, return NULL);
1435 
1436  for (; gIter != NULL; gIter = gIter->next) {
1437  action_t *action = (action_t *) gIter->data;
1438 
1439  if (safe_str_neq(key, action->uuid)) {
1440  crm_trace("%s does not match action %s", key, action->uuid);
1441  continue;
1442 
1443  } else if (on_node == NULL) {
1444  crm_trace("Action %s matches (ignoring node)", key);
1445  result = g_list_prepend(result, action);
1446 
1447  } else if (action->node == NULL) {
1448  crm_trace("Action %s matches (unallocated, assigning to %s)",
1449  key, on_node->details->uname);
1450 
1451  action->node = node_copy(on_node);
1452  result = g_list_prepend(result, action);
1453 
1454  } else if (on_node->details == action->node->details) {
1455  crm_trace("Action %s on %s matches", key, on_node->details->uname);
1456  result = g_list_prepend(result, action);
1457 
1458  } else {
1459  crm_trace("Action %s on node %s does not match requested node %s",
1460  key, action->node->details->uname,
1461  on_node->details->uname);
1462  }
1463  }
1464 
1465  return result;
1466 }
1467 
1468 GList *
1469 find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1470 {
1471  GList *result = NULL;
1472 
1473  CRM_CHECK(key != NULL, return NULL);
1474 
1475  if (on_node == NULL) {
1476  crm_trace("Not searching for action %s because node not specified",
1477  key);
1478  return NULL;
1479  }
1480 
1481  for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1482  pe_action_t *action = (pe_action_t *) gIter->data;
1483 
1484  if (action->node == NULL) {
1485  crm_trace("Skipping comparison of %s vs action %s without node",
1486  key, action->uuid);
1487 
1488  } else if (safe_str_neq(key, action->uuid)) {
1489  crm_trace("Desired action %s doesn't match %s", key, action->uuid);
1490 
1491  } else if (safe_str_neq(on_node->details->id,
1492  action->node->details->id)) {
1493  crm_trace("Action %s desired node ID %s doesn't match %s",
1494  key, on_node->details->id, action->node->details->id);
1495 
1496  } else {
1497  crm_trace("Action %s matches", key);
1498  result = g_list_prepend(result, action);
1499  }
1500  }
1501 
1502  return result;
1503 }
1504 
1517 GList *
1519  const char *task, bool require_node)
1520 {
1521  GList *result = NULL;
1522  char *key = generate_op_key(rsc->id, task, 0);
1523 
1524  if (require_node) {
1525  result = find_actions_exact(rsc->actions, key, node);
1526  } else {
1527  result = find_actions(rsc->actions, key, node);
1528  }
1529  free(key);
1530  return result;
1531 }
1532 
1533 static void
1534 resource_node_score(resource_t * rsc, node_t * node, int score, const char *tag)
1535 {
1536  node_t *match = NULL;
1537 
1538  if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
1539  && safe_str_eq(tag, "symmetric_default")) {
1540  /* This string comparision may be fragile, but exclusive resources and
1541  * exclusive nodes should not have the symmetric_default constraint
1542  * applied to them.
1543  */
1544  return;
1545 
1546  } else if (rsc->children) {
1547  GListPtr gIter = rsc->children;
1548 
1549  for (; gIter != NULL; gIter = gIter->next) {
1550  resource_t *child_rsc = (resource_t *) gIter->data;
1551 
1552  resource_node_score(child_rsc, node, score, tag);
1553  }
1554  }
1555 
1556  pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1557  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1558  if (match == NULL) {
1559  match = node_copy(node);
1560  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1561  }
1562  match->weight = merge_weights(match->weight, score);
1563 }
1564 
1565 void
1566 resource_location(resource_t * rsc, node_t * node, int score, const char *tag,
1567  pe_working_set_t * data_set)
1568 {
1569  if (node != NULL) {
1570  resource_node_score(rsc, node, score, tag);
1571 
1572  } else if (data_set != NULL) {
1573  GListPtr gIter = data_set->nodes;
1574 
1575  for (; gIter != NULL; gIter = gIter->next) {
1576  node_t *node_iter = (node_t *) gIter->data;
1577 
1578  resource_node_score(rsc, node_iter, score, tag);
1579  }
1580 
1581  } else {
1582  GHashTableIter iter;
1583  node_t *node_iter = NULL;
1584 
1585  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1586  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1587  resource_node_score(rsc, node_iter, score, tag);
1588  }
1589  }
1590 
1591  if (node == NULL && score == -INFINITY) {
1592  if (rsc->allocated_to) {
1593  crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1594  free(rsc->allocated_to);
1595  rsc->allocated_to = NULL;
1596  }
1597  }
1598 }
1599 
1600 #define sort_return(an_int, why) do { \
1601  free(a_uuid); \
1602  free(b_uuid); \
1603  crm_trace("%s (%d) %c %s (%d) : %s", \
1604  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1605  b_xml_id, b_call_id, why); \
1606  return an_int; \
1607  } while(0)
1608 
1609 gint
1610 sort_op_by_callid(gconstpointer a, gconstpointer b)
1611 {
1612  int a_call_id = -1;
1613  int b_call_id = -1;
1614 
1615  char *a_uuid = NULL;
1616  char *b_uuid = NULL;
1617 
1618  const xmlNode *xml_a = a;
1619  const xmlNode *xml_b = b;
1620 
1621  const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1622  const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1623 
1624  if (safe_str_eq(a_xml_id, b_xml_id)) {
1625  /* We have duplicate lrm_rsc_op entries in the status
1626  * section which is unlikely to be a good thing
1627  * - we can handle it easily enough, but we need to get
1628  * to the bottom of why it's happening.
1629  */
1630  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1631  sort_return(0, "duplicate");
1632  }
1633 
1634  crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1635  crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1636 
1637  if (a_call_id == -1 && b_call_id == -1) {
1638  /* both are pending ops so it doesn't matter since
1639  * stops are never pending
1640  */
1641  sort_return(0, "pending");
1642 
1643  } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1644  sort_return(-1, "call id");
1645 
1646  } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1647  sort_return(1, "call id");
1648 
1649  } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1650  /*
1651  * The op and last_failed_op are the same
1652  * Order on last-rc-change
1653  */
1654  time_t last_a = -1;
1655  time_t last_b = -1;
1656 
1659 
1660  crm_trace("rc-change: %lld vs %lld",
1661  (long long) last_a, (long long) last_b);
1662  if (last_a >= 0 && last_a < last_b) {
1663  sort_return(-1, "rc-change");
1664 
1665  } else if (last_b >= 0 && last_a > last_b) {
1666  sort_return(1, "rc-change");
1667  }
1668  sort_return(0, "rc-change");
1669 
1670  } else {
1671  /* One of the inputs is a pending operation
1672  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1673  */
1674 
1675  int a_id = -1;
1676  int b_id = -1;
1677 
1678  const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1679  const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1680 
1681  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1682  if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1683  NULL)) {
1684  sort_return(0, "bad magic a");
1685  }
1686  if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1687  NULL)) {
1688  sort_return(0, "bad magic b");
1689  }
1690  /* try to determine the relative age of the operation...
1691  * some pending operations (e.g. a start) may have been superseded
1692  * by a subsequent stop
1693  *
1694  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1695  */
1696  if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1697  /*
1698  * some of the logic in here may be redundant...
1699  *
1700  * if the UUID from the TE doesn't match then one better
1701  * be a pending operation.
1702  * pending operations don't survive between elections and joins
1703  * because we query the LRM directly
1704  */
1705 
1706  if (b_call_id == -1) {
1707  sort_return(-1, "transition + call");
1708 
1709  } else if (a_call_id == -1) {
1710  sort_return(1, "transition + call");
1711  }
1712 
1713  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1714  sort_return(-1, "transition");
1715 
1716  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1717  sort_return(1, "transition");
1718  }
1719  }
1720 
1721  /* we should never end up here */
1722  CRM_CHECK(FALSE, sort_return(0, "default"));
1723 
1724 }
1725 
1726 time_t
1728 {
1729  if(data_set) {
1730  if (data_set->now == NULL) {
1731  crm_trace("Recording a new 'now'");
1732  data_set->now = crm_time_new(NULL);
1733  }
1734  return crm_time_get_seconds_since_epoch(data_set->now);
1735  }
1736 
1737  crm_trace("Defaulting to 'now'");
1738  return time(NULL);
1739 }
1740 
1741 gboolean
1743 {
1744  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1745  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1746 
1747  CRM_CHECK(role != NULL, return FALSE);
1748 
1749  if (value == NULL || safe_str_eq("started", value)
1750  || safe_str_eq("default", value)) {
1751  return FALSE;
1752  }
1753 
1754  local_role = text2role(value);
1755  if (local_role == RSC_ROLE_UNKNOWN) {
1756  crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1757  return FALSE;
1758 
1759  } else if (local_role > RSC_ROLE_STARTED) {
1760  if (is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
1761  if (local_role > RSC_ROLE_SLAVE) {
1762  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1763  return FALSE;
1764  }
1765 
1766  } else {
1767  crm_config_err("%s is not part of a promotable clone resource, a %s of '%s' makes no sense",
1768  rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1769  return FALSE;
1770  }
1771  }
1772 
1773  *role = local_role;
1774  return TRUE;
1775 }
1776 
1777 gboolean
1778 order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order)
1779 {
1780  GListPtr gIter = NULL;
1781  action_wrapper_t *wrapper = NULL;
1782  GListPtr list = NULL;
1783 
1784  if (order == pe_order_none) {
1785  return FALSE;
1786  }
1787 
1788  if (lh_action == NULL || rh_action == NULL) {
1789  return FALSE;
1790  }
1791 
1792  crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1793 
1794  /* Ensure we never create a dependency on ourselves... it's happened */
1795  CRM_ASSERT(lh_action != rh_action);
1796 
1797  /* Filter dups, otherwise update_action_states() has too much work to do */
1798  gIter = lh_action->actions_after;
1799  for (; gIter != NULL; gIter = gIter->next) {
1800  action_wrapper_t *after = (action_wrapper_t *) gIter->data;
1801 
1802  if (after->action == rh_action && (after->type & order)) {
1803  return FALSE;
1804  }
1805  }
1806 
1807  wrapper = calloc(1, sizeof(action_wrapper_t));
1808  wrapper->action = rh_action;
1809  wrapper->type = order;
1810 
1811  list = lh_action->actions_after;
1812  list = g_list_prepend(list, wrapper);
1813  lh_action->actions_after = list;
1814 
1815  wrapper = NULL;
1816 
1817 /* order |= pe_order_implies_then; */
1818 /* order ^= pe_order_implies_then; */
1819 
1820  wrapper = calloc(1, sizeof(action_wrapper_t));
1821  wrapper->action = lh_action;
1822  wrapper->type = order;
1823  list = rh_action->actions_before;
1824  list = g_list_prepend(list, wrapper);
1825  rh_action->actions_before = list;
1826  return TRUE;
1827 }
1828 
1829 action_t *
1830 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1831 {
1832  action_t *op = NULL;
1833 
1834  if(data_set->singletons) {
1835  op = g_hash_table_lookup(data_set->singletons, name);
1836  }
1837  if (op == NULL) {
1838  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1841  }
1842 
1843  return op;
1844 }
1845 
1846 void
1848 {
1849  ticket_t *ticket = data;
1850 
1851  if (ticket->state) {
1852  g_hash_table_destroy(ticket->state);
1853  }
1854  free(ticket->id);
1855  free(ticket);
1856 }
1857 
1858 ticket_t *
1859 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1860 {
1861  ticket_t *ticket = NULL;
1862 
1863  if (ticket_id == NULL || strlen(ticket_id) == 0) {
1864  return NULL;
1865  }
1866 
1867  if (data_set->tickets == NULL) {
1868  data_set->tickets =
1869  g_hash_table_new_full(crm_str_hash, g_str_equal, free,
1870  destroy_ticket);
1871  }
1872 
1873  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1874  if (ticket == NULL) {
1875 
1876  ticket = calloc(1, sizeof(ticket_t));
1877  if (ticket == NULL) {
1878  crm_err("Cannot allocate ticket '%s'", ticket_id);
1879  return NULL;
1880  }
1881 
1882  crm_trace("Creaing ticket entry for %s", ticket_id);
1883 
1884  ticket->id = strdup(ticket_id);
1885  ticket->granted = FALSE;
1886  ticket->last_granted = -1;
1887  ticket->standby = FALSE;
1888  ticket->state = crm_str_table_new();
1889 
1890  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1891  }
1892 
1893  return ticket;
1894 }
1895 
1896 static void
1897 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1898 {
1899  if (param_set && param_string) {
1900  xmlAttrPtr xIter = param_set->properties;
1901 
1902  while (xIter) {
1903  const char *prop_name = (const char *)xIter->name;
1904  char *name = crm_strdup_printf(" %s ", prop_name);
1905  char *match = strstr(param_string, name);
1906 
1907  free(name);
1908 
1909  // Do now, because current entry might get removed below
1910  xIter = xIter->next;
1911 
1912  if (need_present && match == NULL) {
1913  crm_trace("%s not found in %s", prop_name, param_string);
1914  xml_remove_prop(param_set, prop_name);
1915 
1916  } else if (need_present == FALSE && match) {
1917  crm_trace("%s found in %s", prop_name, param_string);
1918  xml_remove_prop(param_set, prop_name);
1919  }
1920  }
1921  }
1922 }
1923 
1924 #if ENABLE_VERSIONED_ATTRS
1925 static void
1926 append_versioned_params(xmlNode *versioned_params, const char *ra_version, xmlNode *params)
1927 {
1928  GHashTable *hash = pe_unpack_versioned_parameters(versioned_params, ra_version);
1929  char *key = NULL;
1930  char *value = NULL;
1931  GHashTableIter iter;
1932 
1933  g_hash_table_iter_init(&iter, hash);
1934  while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value)) {
1935  crm_xml_add(params, key, value);
1936  }
1937  g_hash_table_destroy(hash);
1938 }
1939 #endif
1940 
1955 static op_digest_cache_t *
1956 rsc_action_digest(pe_resource_t *rsc, const char *task, const char *key,
1957  pe_node_t *node, xmlNode *xml_op, bool calc_secure,
1958  pe_working_set_t *data_set)
1959 {
1960  op_digest_cache_t *data = NULL;
1961 
1962  data = g_hash_table_lookup(node->details->digest_cache, key);
1963  if (data == NULL) {
1964  GHashTable *local_rsc_params = crm_str_table_new();
1965  action_t *action = custom_action(rsc, strdup(key), task, node, TRUE, FALSE, data_set);
1966 #if ENABLE_VERSIONED_ATTRS
1967  xmlNode *local_versioned_params = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1968  const char *ra_version = NULL;
1969 #endif
1970 
1971  const char *op_version;
1972  const char *restart_list = NULL;
1973  const char *secure_list = " passwd password ";
1974 
1975  data = calloc(1, sizeof(op_digest_cache_t));
1976  CRM_ASSERT(data != NULL);
1977 
1978  get_rsc_attributes(local_rsc_params, rsc, node, data_set);
1979 #if ENABLE_VERSIONED_ATTRS
1980  pe_get_versioned_attributes(local_versioned_params, rsc, node, data_set);
1981 #endif
1982 
1983  data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
1984 
1985  // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
1986  if (pe__add_bundle_remote_name(rsc, data->params_all,
1988  crm_trace("Set address for bundle connection %s (on %s)",
1989  rsc->id, node->details->uname);
1990  }
1991 
1992  g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
1993  g_hash_table_foreach(action->extra, hash2field, data->params_all);
1994  g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
1995  g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
1996 
1997  if(xml_op) {
1998  secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
1999  restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
2000 
2001  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
2002 #if ENABLE_VERSIONED_ATTRS
2003  ra_version = crm_element_value(xml_op, XML_ATTR_RA_VERSION);
2004 #endif
2005 
2006  } else {
2007  op_version = CRM_FEATURE_SET;
2008  }
2009 
2010 #if ENABLE_VERSIONED_ATTRS
2011  append_versioned_params(local_versioned_params, ra_version, data->params_all);
2012  append_versioned_params(rsc->versioned_parameters, ra_version, data->params_all);
2013 
2014  {
2015  pe_rsc_action_details_t *details = pe_rsc_action_details(action);
2016  append_versioned_params(details->versioned_parameters, ra_version, data->params_all);
2017  }
2018 #endif
2019 
2020  filter_action_parameters(data->params_all, op_version);
2021 
2022  g_hash_table_destroy(local_rsc_params);
2023  pe_free_action(action);
2024 
2025  data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
2026 
2027  if (calc_secure) {
2028  data->params_secure = copy_xml(data->params_all);
2029  if(secure_list) {
2030  filter_parameters(data->params_secure, secure_list, FALSE);
2031  }
2032  data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
2033  }
2034 
2035  if(xml_op && crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
2036  data->params_restart = copy_xml(data->params_all);
2037  if (restart_list) {
2038  filter_parameters(data->params_restart, restart_list, TRUE);
2039  }
2040  data->digest_restart_calc = calculate_operation_digest(data->params_restart, op_version);
2041  }
2042 
2043  g_hash_table_insert(node->details->digest_cache, strdup(key), data);
2044  }
2045 
2046  return data;
2047 }
2048 
2050 rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
2051  pe_working_set_t * data_set)
2052 {
2053  op_digest_cache_t *data = NULL;
2054 
2055  char *key = NULL;
2056  guint interval_ms = 0;
2057 
2058  const char *op_version;
2059  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
2060  const char *interval_ms_s = crm_element_value(xml_op,
2062  const char *digest_all;
2063  const char *digest_restart;
2064 
2065  CRM_ASSERT(node != NULL);
2066 
2067  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
2068  digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
2069  digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
2070 
2071  interval_ms = crm_parse_ms(interval_ms_s);
2072  key = generate_op_key(rsc->id, task, interval_ms);
2073  data = rsc_action_digest(rsc, task, key, node, xml_op,
2074  is_set(data_set->flags, pe_flag_sanitized),
2075  data_set);
2076 
2077  data->rc = RSC_DIGEST_MATCH;
2078  if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
2079  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
2080  key, node->details->uname,
2081  crm_str(digest_restart), data->digest_restart_calc,
2082  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2083  data->rc = RSC_DIGEST_RESTART;
2084 
2085  } else if (digest_all == NULL) {
2086  /* it is unknown what the previous op digest was */
2087  data->rc = RSC_DIGEST_UNKNOWN;
2088 
2089  } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
2090  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (%s:%s) %s",
2091  key, node->details->uname,
2092  crm_str(digest_all), data->digest_all_calc,
2093  (interval_ms > 0)? "reschedule" : "reload",
2094  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2095  data->rc = RSC_DIGEST_ALL;
2096  }
2097 
2098  free(key);
2099  return data;
2100 }
2101 
2119 static inline char *
2120 create_unfencing_summary(const char *rsc_id, const char *agent_type,
2121  const char *param_digest)
2122 {
2123  return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
2124 }
2125 
2142 static bool
2143 unfencing_digest_matches(const char *rsc_id, const char *agent,
2144  const char *digest_calc, const char *node_summary)
2145 {
2146  bool matches = FALSE;
2147 
2148  if (rsc_id && agent && digest_calc && node_summary) {
2149  char *search_secure = create_unfencing_summary(rsc_id, agent,
2150  digest_calc);
2151 
2152  /* The digest was calculated including the device ID and agent,
2153  * so there is no risk of collision using strstr().
2154  */
2155  matches = (strstr(node_summary, search_secure) != NULL);
2156  crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
2157  search_secure, matches? "" : "not ", node_summary);
2158  free(search_secure);
2159  }
2160  return matches;
2161 }
2162 
2163 /* Magic string to use as action name for digest cache entries used for
2164  * unfencing checks. This is not a real action name (i.e. "on"), so
2165  * check_action_definition() won't confuse these entries with real actions.
2166  */
2167 #define STONITH_DIGEST_TASK "stonith-on"
2168 
2180 static op_digest_cache_t *
2181 fencing_action_digest_cmp(pe_resource_t *rsc, const char *agent,
2182  pe_node_t *node, pe_working_set_t *data_set)
2183 {
2184  const char *node_summary = NULL;
2185 
2186  // Calculate device's current parameter digests
2187  char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
2188  op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key,
2189  node, NULL, TRUE, data_set);
2190 
2191  free(key);
2192 
2193  // Check whether node has special unfencing summary node attribute
2194  node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
2195  if (node_summary == NULL) {
2196  data->rc = RSC_DIGEST_UNKNOWN;
2197  return data;
2198  }
2199 
2200  // Check whether full parameter digest matches
2201  if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
2202  node_summary)) {
2203  data->rc = RSC_DIGEST_MATCH;
2204  return data;
2205  }
2206 
2207  // Check whether secure parameter digest matches
2208  node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
2209  if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
2210  node_summary)) {
2211  data->rc = RSC_DIGEST_MATCH;
2212  if (is_set(data_set->flags, pe_flag_stdout)) {
2213  printf("Only 'private' parameters to %s for unfencing %s changed\n",
2214  rsc->id, node->details->uname);
2215  }
2216  return data;
2217  }
2218 
2219  // Parameters don't match
2220  data->rc = RSC_DIGEST_ALL;
2221  if (is_set(data_set->flags, (pe_flag_sanitized|pe_flag_stdout))
2222  && data->digest_secure_calc) {
2223  char *digest = create_unfencing_summary(rsc->id, agent,
2224  data->digest_secure_calc);
2225 
2226  printf("Parameters to %s for unfencing %s changed, try '%s'\n",
2227  rsc->id, node->details->uname, digest);
2228  free(digest);
2229  }
2230  return data;
2231 }
2232 
2233 const char *rsc_printable_id(resource_t *rsc)
2234 {
2235  if (is_not_set(rsc->flags, pe_rsc_unique)) {
2236  return ID(rsc->xml);
2237  }
2238  return rsc->id;
2239 }
2240 
2241 void
2242 clear_bit_recursive(resource_t * rsc, unsigned long long flag)
2243 {
2244  GListPtr gIter = rsc->children;
2245 
2246  clear_bit(rsc->flags, flag);
2247  for (; gIter != NULL; gIter = gIter->next) {
2248  resource_t *child_rsc = (resource_t *) gIter->data;
2249 
2250  clear_bit_recursive(child_rsc, flag);
2251  }
2252 }
2253 
2254 void
2255 set_bit_recursive(resource_t * rsc, unsigned long long flag)
2256 {
2257  GListPtr gIter = rsc->children;
2258 
2259  set_bit(rsc->flags, flag);
2260  for (; gIter != NULL; gIter = gIter->next) {
2261  resource_t *child_rsc = (resource_t *) gIter->data;
2262 
2263  set_bit_recursive(child_rsc, flag);
2264  }
2265 }
2266 
2267 static GListPtr
2268 find_unfencing_devices(GListPtr candidates, GListPtr matches)
2269 {
2270  for (GListPtr gIter = candidates; gIter != NULL; gIter = gIter->next) {
2271  resource_t *candidate = gIter->data;
2272  const char *provides = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_PROVIDES);
2273  const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
2274 
2275  if(candidate->children) {
2276  matches = find_unfencing_devices(candidate->children, matches);
2277  } else if (is_not_set(candidate->flags, pe_rsc_fence_device)) {
2278  continue;
2279 
2280  } else if (crm_str_eq(provides, "unfencing", FALSE) || crm_str_eq(requires, "unfencing", FALSE)) {
2281  matches = g_list_prepend(matches, candidate);
2282  }
2283  }
2284  return matches;
2285 }
2286 
2287 
2288 action_t *
2289 pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe_working_set_t * data_set)
2290 {
2291  char *op_key = NULL;
2292  action_t *stonith_op = NULL;
2293 
2294  if(op == NULL) {
2295  op = data_set->stonith_action;
2296  }
2297 
2298  op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2299 
2300  if(data_set->singletons) {
2301  stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2302  }
2303 
2304  if(stonith_op == NULL) {
2305  stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2306 
2307  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2308  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2309  add_hash_param(stonith_op->meta, "stonith_action", op);
2310 
2311  if (pe__is_guest_or_remote_node(node)
2312  && is_set(data_set->flags, pe_flag_enable_unfencing)) {
2313  /* Extra work to detect device changes on remotes
2314  *
2315  * We may do this for all nodes in the future, but for now
2316  * the check_action_definition() based stuff works fine.
2317  */
2318  long max = 1024;
2319  long digests_all_offset = 0;
2320  long digests_secure_offset = 0;
2321 
2322  char *digests_all = calloc(max, sizeof(char));
2323  char *digests_secure = calloc(max, sizeof(char));
2324  GListPtr matches = find_unfencing_devices(data_set->resources, NULL);
2325 
2326  for (GListPtr gIter = matches; gIter != NULL; gIter = gIter->next) {
2327  resource_t *match = gIter->data;
2328  const char *agent = g_hash_table_lookup(match->meta,
2329  XML_ATTR_TYPE);
2330  op_digest_cache_t *data = NULL;
2331 
2332  data = fencing_action_digest_cmp(match, agent, node, data_set);
2333  if(data->rc == RSC_DIGEST_ALL) {
2334  optional = FALSE;
2335  crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2336  if (is_set(data_set->flags, pe_flag_stdout)) {
2337  fprintf(stdout, " notice: Unfencing %s (remote): because the definition of %s changed\n", node->details->uname, match->id);
2338  }
2339  }
2340 
2341  digests_all_offset += snprintf(
2342  digests_all+digests_all_offset, max-digests_all_offset,
2343  "%s:%s:%s,", match->id, agent, data->digest_all_calc);
2344 
2345  digests_secure_offset += snprintf(
2346  digests_secure+digests_secure_offset, max-digests_secure_offset,
2347  "%s:%s:%s,", match->id, agent, data->digest_secure_calc);
2348  }
2349  g_hash_table_insert(stonith_op->meta,
2350  strdup(XML_OP_ATTR_DIGESTS_ALL),
2351  digests_all);
2352  g_hash_table_insert(stonith_op->meta,
2354  digests_secure);
2355  }
2356 
2357  } else {
2358  free(op_key);
2359  }
2360 
2361  if(optional == FALSE && pe_can_fence(data_set, node)) {
2362  pe_action_required(stonith_op, NULL, reason);
2363  } else if(reason && stonith_op->reason == NULL) {
2364  stonith_op->reason = strdup(reason);
2365  }
2366 
2367  return stonith_op;
2368 }
2369 
2370 void
2372  resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set)
2373 {
2374  if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
2375  /* No resources require it */
2376  return;
2377 
2378  } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
2379  /* Wasn't a stonith device */
2380  return;
2381 
2382  } else if(node
2383  && node->details->online
2384  && node->details->unclean == FALSE
2385  && node->details->shutdown == FALSE) {
2386  action_t *unfence = pe_fence_op(node, "on", FALSE, reason, data_set);
2387 
2388  if(dependency) {
2389  order_actions(unfence, dependency, pe_order_optional);
2390  }
2391 
2392  } else if(rsc) {
2393  GHashTableIter iter;
2394 
2395  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2396  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2397  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2398  trigger_unfencing(rsc, node, reason, dependency, data_set);
2399  }
2400  }
2401  }
2402 }
2403 
2404 gboolean
2405 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2406 {
2407  tag_t *tag = NULL;
2408  GListPtr gIter = NULL;
2409  gboolean is_existing = FALSE;
2410 
2411  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2412 
2413  tag = g_hash_table_lookup(tags, tag_name);
2414  if (tag == NULL) {
2415  tag = calloc(1, sizeof(tag_t));
2416  if (tag == NULL) {
2417  return FALSE;
2418  }
2419  tag->id = strdup(tag_name);
2420  tag->refs = NULL;
2421  g_hash_table_insert(tags, strdup(tag_name), tag);
2422  }
2423 
2424  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2425  const char *existing_ref = (const char *) gIter->data;
2426 
2427  if (crm_str_eq(existing_ref, obj_ref, TRUE)){
2428  is_existing = TRUE;
2429  break;
2430  }
2431  }
2432 
2433  if (is_existing == FALSE) {
2434  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2435  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2436  }
2437 
2438  return TRUE;
2439 }
2440 
2441 void pe_action_set_flag_reason(const char *function, long line,
2442  pe_action_t *action, pe_action_t *reason, const char *text,
2443  enum pe_action_flags flags, bool overwrite)
2444 {
2445  bool unset = FALSE;
2446  bool update = FALSE;
2447  const char *change = NULL;
2448 
2449  if(is_set(flags, pe_action_runnable)) {
2450  unset = TRUE;
2451  change = "unrunnable";
2452  } else if(is_set(flags, pe_action_optional)) {
2453  unset = TRUE;
2454  change = "required";
2455  } else if(is_set(flags, pe_action_migrate_runnable)) {
2456  unset = TRUE;
2457  overwrite = TRUE;
2458  change = "unrunnable";
2459  } else if(is_set(flags, pe_action_dangle)) {
2460  change = "dangling";
2461  } else if(is_set(flags, pe_action_requires_any)) {
2462  change = "required";
2463  } else {
2464  crm_err("Unknown flag change to %x by %s: 0x%s",
2465  flags, action->uuid, (reason? reason->uuid : "0"));
2466  }
2467 
2468  if(unset) {
2469  if(is_set(action->flags, flags)) {
2470  action->flags = crm_clear_bit(function, line, action->uuid, action->flags, flags);
2471  update = TRUE;
2472  }
2473 
2474  } else {
2475  if(is_not_set(action->flags, flags)) {
2476  action->flags = crm_set_bit(function, line, action->uuid, action->flags, flags);
2477  update = TRUE;
2478  }
2479  }
2480 
2481  if((change && update) || text) {
2482  char *reason_text = NULL;
2483  if(reason == NULL) {
2484  pe_action_set_reason(action, text, overwrite);
2485 
2486  } else if(reason->rsc == NULL) {
2487  reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2488  } else {
2489  reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2490  }
2491 
2492  if(reason_text && action->rsc != reason->rsc) {
2493  pe_action_set_reason(action, reason_text, overwrite);
2494  }
2495  free(reason_text);
2496  }
2497  }
2498 
2499 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
2500 {
2501  if(action->reason && overwrite) {
2502  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'", action->uuid, action->reason, reason);
2503  free(action->reason);
2504  action->reason = NULL;
2505  }
2506  if(action->reason == NULL) {
2507  if(reason) {
2508  pe_rsc_trace(action->rsc, "Set %s reason to '%s'", action->uuid, reason);
2509  action->reason = strdup(reason);
2510  } else {
2511  action->reason = NULL;
2512  }
2513  }
2514 }
2515 
2528 bool
2530 {
2531  const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
2532 
2533  return shutdown && strcmp(shutdown, "0");
2534 }
2535 
2543 void
2544 pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
2545 {
2546  if ((recheck > get_effective_time(data_set))
2547  && ((data_set->recheck_by == 0)
2548  || (data_set->recheck_by > recheck))) {
2549  data_set->recheck_by = recheck;
2550  }
2551 }
2552 
2557 void
2558 pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name,
2559  GHashTable *node_hash, GHashTable *hash,
2560  const char *always_first, gboolean overwrite,
2561  pe_working_set_t *data_set)
2562 {
2563  crm_time_t *next_change = crm_time_new_undefined();
2564 
2565  pe_unpack_nvpairs(data_set->input, xml_obj, set_name, node_hash, hash,
2566  always_first, overwrite, data_set->now, next_change);
2567  if (crm_time_is_defined(next_change)) {
2568  time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
2569 
2570  pe__update_recheck_time(recheck, data_set);
2571  }
2572  crm_time_free(next_change);
2573 }
2574 
2575 bool
2577 {
2578  const char *target_role = NULL;
2579 
2580  CRM_CHECK(rsc != NULL, return false);
2581  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
2582  if (target_role) {
2583  enum rsc_role_e target_role_e = text2role(target_role);
2584 
2585  if ((target_role_e == RSC_ROLE_STOPPED)
2586  || ((target_role_e == RSC_ROLE_SLAVE)
2587  && is_set(uber_parent(rsc)->flags, pe_rsc_promotable))) {
2588  return true;
2589  }
2590  }
2591  return false;
2592 }
pe_action_flags
pe_action_flags
Definition: pe_types.h:265
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:311
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:224
pe_ticket_s::last_granted
time_t last_granted
Definition: pe_types.h:422
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:2544
find_actions
GListPtr find_actions(GListPtr input, const char *key, const node_t *on_node)
Definition: utils.c:1429
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:214
pe_working_set_s::input
xmlNode * input
Definition: pe_types.h:118
INFINITY
#define INFINITY
Definition: crm.h:95
pe_working_set_s::now
crm_time_t * now
Definition: pe_types.h:119
pe_action_s::needs
enum rsc_start_requirement needs
Definition: pe_types.h:383
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:1566
pe_resource_s::exclusive_discover
gboolean exclusive_discover
Definition: pe_types.h:323
pe_action_set_reason
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: utils.c:2499
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:301
RSC_PROMOTE
#define RSC_PROMOTE
Definition: crm.h:202
pe_print_log
@ pe_print_log
Definition: common.h:103
pe_tag_s::id
char * id
Definition: pe_types.h:428
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:139
pe__resource_is_disabled
bool pe__resource_is_disabled(pe_resource_t *rsc)
Definition: utils.c:2576
action_fail_standby
@ action_fail_standby
Definition: common.h:42
pe_action_s::actions_before
GListPtr actions_before
Definition: pe_types.h:410
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:330
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:342
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:1830
pe_working_set_s::nodes
GListPtr nodes
Definition: pe_types.h:138
msg_xml.h
RSC_ROLE_STOPPED
@ RSC_ROLE_STOPPED
Definition: common.h:88
add_tag_ref
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:2405
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:346
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:168
action_fail_stop
@ action_fail_stop
Definition: common.h:41
print_node
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1267
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:207
LOG_TRACE
#define LOG_TRACE
Definition: logging.h:26
pe_rsc_debug
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:18
started_rsc
@ started_rsc
Definition: common.h:63
pe_action_s::on_fail
enum action_fail_response on_fail
Definition: pe_types.h:384
rsc_req_quorum
@ rsc_req_quorum
Definition: common.h:82
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:421
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:348
pe_resource_s::id
char * id
Definition: pe_types.h:292
clear_bit_recursive
void clear_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2242
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:455
pe_resource_s::allocated_to
pe_node_t * allocated_to
Definition: pe_types.h:334
rsc_role_e
rsc_role_e
Definition: common.h:86
pe_flag_sanitized
#define pe_flag_sanitized
Definition: pe_types.h:111
pe_node_shared_s::running_rsc
GListPtr running_rsc
Definition: pe_types.h:208
stop_rsc
@ stop_rsc
Definition: common.h:60
pe__shutdown_requested
bool pe__shutdown_requested(pe_node_t *node)
Definition: utils.c:2529
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:283
pe_action_s::op_entry
xmlNode * op_entry
Definition: pe_types.h:375
pe_action_s::extra
GHashTable * extra
Definition: pe_types.h:388
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:217
crm_parse_ms
guint crm_parse_ms(const char *text)
Definition: strings.c:147
pe_action_pseudo
@ pe_action_pseudo
Definition: pe_types.h:266
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:213
pe_rsc_fence_device
#define pe_rsc_fence_device
Definition: pe_types.h:231
pe_node_s::details
struct pe_node_shared_s * details
Definition: pe_types.h:220
pe_action_have_node_attrs
@ pe_action_have_node_attrs
Definition: pe_types.h:271
pe_working_set_s::stonith_action
const char * stonith_action
Definition: pe_types.h:124
stopped_rsc
@ stopped_rsc
Definition: common.h:61
crm_notice
#define crm_notice(fmt, args...)
Definition: logging.h:243
action_fail_recover
@ action_fail_recover
Definition: common.h:38
pe_node_shared_s::id
const char * id
Definition: pe_types.h:185
pe_action_s::actions_after
GListPtr actions_after
Definition: pe_types.h:411
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:154
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:344
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:230
pe_node_shared_s::pending
gboolean pending
Definition: pe_types.h:193
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:419
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:382
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:2130
pe_resource_s::running_on
GListPtr running_on
Definition: pe_types.h:337
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:212
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:489
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:379
crm_is_true
gboolean crm_is_true(const char *s)
Definition: strings.c:176
CRMD_ACTION_CANCEL
#define CRMD_ACTION_CANCEL
Definition: crm.h:165
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:201
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:118
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:378
ID
#define ID(x)
Definition: msg_xml.h:415
RSC_START
#define RSC_START
Definition: crm.h:196
pe_ticket_s::id
char * id
Definition: pe_types.h:420
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:40
RSC_ROLE_SLAVE
@ RSC_ROLE_SLAVE
Definition: common.h:90
pe_rsc_starting
#define pe_rsc_starting
Definition: pe_types.h:245
pe_action_s
Definition: pe_types.h:369
pe_node_shared_s::shutdown
gboolean shutdown
Definition: pe_types.h:196
pe_resource_s::xml
xmlNode * xml
Definition: pe_types.h:294
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:1399
pe_action_s::action_details
void * action_details
Definition: pe_types.h:416
action_fail_fence
@ action_fail_fence
Definition: common.h:43
pe_rsc_needs_quorum
#define pe_rsc_needs_quorum
Definition: pe_types.h:253
CRMD_ACTION_MIGRATED
#define CRMD_ACTION_MIGRATED
Definition: crm.h:169
CRM_FEATURE_SET
#define CRM_FEATURE_SET
Definition: crm.h:54
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:542
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:2371
pe_node_s::fixed
gboolean fixed
Definition: pe_types.h:218
action_fail_migrate
@ action_fail_migrate
Definition: common.h:39
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:829
order_actions
gboolean order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1778
action_fail_reset_remote
@ action_fail_reset_remote
Definition: common.h:52
role2text
const char * role2text(enum rsc_role_e role)
Definition: common.c:335
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
CRMD_ACTION_START
#define CRMD_ACTION_START
Definition: crm.h:171
RSC_ROLE_UNKNOWN
@ RSC_ROLE_UNKNOWN
Definition: common.h:87
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:2050
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:246
CRMD_ACTION_MIGRATE
#define CRMD_ACTION_MIGRATE
Definition: crm.h:168
pe_flag_stdout
#define pe_flag_stdout
Definition: pe_types.h:112
pe_action_s::node
pe_node_t * node
Definition: pe_types.h:374
action_demoted
@ action_demoted
Definition: common.h:69
pe_resource_s::sort_index
int sort_index
Definition: pe_types.h:313
CRMD_ACTION_STOP
#define CRMD_ACTION_STOP
Definition: crm.h:174
pe_order_optional
@ pe_order_optional
Definition: pe_types.h:448
rsc_req_stonith
@ rsc_req_stonith
Definition: common.h:83
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:221
pe_action_optional
@ pe_action_optional
Definition: pe_types.h:268
XML_RSC_OP_LAST_CHANGE
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:280
pe_tag_s
Definition: pe_types.h:427
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:1469
print_str_str
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1306
pe_can_fence
bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
Definition: utils.c:89
find_recurring_actions
GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node)
Definition: utils.c:1341
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:44
pe_working_set_s
Definition: pe_types.h:117
action_promoted
@ action_promoted
Definition: common.h:67
sort_return
#define sort_return(an_int, why)
Definition: utils.c:1600
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:380
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:429
text2role
enum rsc_role_e text2role(const char *role)
Definition: common.c:356
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:370
pe_ticket_s::state
GHashTable * state
Definition: pe_types.h:424
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:412
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:351
CRM_OP_FENCE
#define CRM_OP_FENCE
Definition: crm.h:141
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:254
pe_working_set_s::actions
GListPtr actions
Definition: pe_types.h:145
pe_flag_have_stonith_resource
#define pe_flag_have_stonith_resource
Definition: pe_types.h:94
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:230
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:1518
ticket_new
ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:1859
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:2558
RSC_STATUS
#define RSC_STATUS
Definition: crm.h:210
rsc_req_nothing
@ rsc_req_nothing
Definition: common.h:81
pe_ticket_s::standby
gboolean standby
Definition: pe_types.h:423
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:293
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:447
pe_action_s::rsc
pe_resource_t * rsc
Definition: pe_types.h:373
set_bit_recursive
void set_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2255
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:319
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:273
pe_rsc_stopping
#define pe_rsc_stopping
Definition: pe_types.h:246
pe_resource_s::remote_reconnect_ms
guint remote_reconnect_ms
Definition: pe_types.h:316
pe_flag_enable_unfencing
#define pe_flag_enable_unfencing
Definition: pe_types.h:95
CRM_ATTR_DIGESTS_SECURE
#define CRM_ATTR_DIGESTS_SECURE
Definition: crm.h:119
pe_resource_s::role
enum rsc_role_e role
Definition: pe_types.h:341
get_target_role
gboolean get_target_role(resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:1742
destroy_ticket
void destroy_ticket(gpointer data)
Definition: utils.c:1847
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:136
get_complex_task
enum action_tasks get_complex_task(resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1375
pe_free_action
void pe_free_action(action_t *action)
Definition: utils.c:1314
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:267
start_rsc
@ start_rsc
Definition: common.h:62
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:133
pe_action_dangle
@ pe_action_dangle
Definition: pe_types.h:278
CRMD_ACTION_DEMOTE
#define CRMD_ACTION_DEMOTE
Definition: crm.h:179
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:2289
pe_rsc_managed
#define pe_rsc_managed
Definition: pe_types.h:225
pe_action_s::fail_role
enum rsc_role_e fail_role
Definition: pe_types.h:385
action_fail_ignore
@ action_fail_ignore
Definition: common.h:37
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:185
unpack.h
pe_action_wrapper_s::action
pe_action_t * action
Definition: pe_types.h:492
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:2233
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:1261
pe_node_attribute_raw
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:468
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:913
RSC_DIGEST_UNKNOWN
@ RSC_DIGEST_UNKNOWN
Definition: internal.h:325
STONITH_DIGEST_TASK
#define STONITH_DIGEST_TASK
Definition: utils.c:2167
pe_rsc_promotable
#define pe_rsc_promotable
Definition: pe_types.h:232
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:1610
pe_print_pending
@ pe_print_pending
Definition: common.h:115
pe_flag_stonith_enabled
#define pe_flag_stonith_enabled
Definition: pe_types.h:93
merge_weights
int merge_weights(int w1, int w2)
Definition: common.c:375
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:291
pe_working_set_s::op_defaults
xmlNode * op_defaults
Definition: pe_types.h:147
pe_resource_s::allowed_nodes
GHashTable * allowed_nodes
Definition: pe_types.h:339
pe_working_set_s::flags
unsigned long long flags
Definition: pe_types.h:127
pe_node_shared_s::unclean
gboolean unclean
Definition: pe_types.h:194
pe_resource_s::ops_xml
xmlNode * ops_xml
Definition: pe_types.h:296
RSC_ROLE_STARTED
@ RSC_ROLE_STARTED
Definition: common.h:89
pe_working_set_s::no_quorum_policy
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:130
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
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:237
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:190
pe_action_s::task
char * task
Definition: pe_types.h:377
pe_node_shared_s::uname
const char * uname
Definition: pe_types.h:186
get_effective_time
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:1727
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:57
util.h
Utility functions.
pe_node_s
Definition: pe_types.h:216
XML_OP_ATTR_ORIGIN
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:220
pe_resource_s::parameters
GHashTable * parameters
Definition: pe_types.h:345
pe_flag_have_quorum
#define pe_flag_have_quorum
Definition: pe_types.h:89
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:177
pe_discover_never
@ pe_discover_never
Definition: pe_types.h:441
pe_action_s::meta
GHashTable * meta
Definition: pe_types.h:387
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:2441
crm_get_msec
long long crm_get_msec(const char *input)
Definition: utils.c:572
pe_resource_s::fns
resource_object_functions_t * fns
Definition: pe_types.h:303
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:211
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:446
pe_action_wrapper_s::type
enum pe_ordering type
Definition: pe_types.h:490