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