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