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