pacemaker  1.1.17-b36b869ca8
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 
30 
31 extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
32 void print_str_str(gpointer key, gpointer value, gpointer user_data);
33 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
34 void unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
35  pe_working_set_t * data_set);
36 static xmlNode *find_rsc_op_entry_helper(resource_t * rsc, const char *key,
37  gboolean include_disabled);
38 
52 bool pe_can_fence(pe_working_set_t * data_set, node_t *node)
53 {
54  if(is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
55  return FALSE; /* Turned off */
56 
57  } else if (is_not_set(data_set->flags, pe_flag_have_stonith_resource)) {
58  return FALSE; /* No devices */
59 
60  } else if (is_set(data_set->flags, pe_flag_have_quorum)) {
61  return TRUE;
62 
63  } else if (data_set->no_quorum_policy == no_quorum_ignore) {
64  return TRUE;
65 
66  } else if(node == NULL) {
67  return FALSE;
68 
69  } else if(node->details->online) {
70  crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
71  return TRUE;
72  }
73 
74  crm_trace("Cannot fence %s", node->details->uname);
75  return FALSE;
76 }
77 
78 node_t *
79 node_copy(const node_t *this_node)
80 {
81  node_t *new_node = NULL;
82 
83  CRM_CHECK(this_node != NULL, return NULL);
84 
85  new_node = calloc(1, sizeof(node_t));
86  CRM_ASSERT(new_node != NULL);
87 
88  crm_trace("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node);
89 
90  new_node->rsc_discover_mode = this_node->rsc_discover_mode;
91  new_node->weight = this_node->weight;
92  new_node->fixed = this_node->fixed;
93  new_node->details = this_node->details;
94 
95  return new_node;
96 }
97 
98 /* any node in list1 or list2 and not in the other gets a score of -INFINITY */
99 void
100 node_list_exclude(GHashTable * hash, GListPtr list, gboolean merge_scores)
101 {
102  GHashTable *result = hash;
103  node_t *other_node = NULL;
104  GListPtr gIter = list;
105 
106  GHashTableIter iter;
107  node_t *node = NULL;
108 
109  g_hash_table_iter_init(&iter, hash);
110  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
111 
112  other_node = pe_find_node_id(list, node->details->id);
113  if (other_node == NULL) {
114  node->weight = -INFINITY;
115  } else if (merge_scores) {
116  node->weight = merge_weights(node->weight, other_node->weight);
117  }
118  }
119 
120  for (; gIter != NULL; gIter = gIter->next) {
121  node_t *node = (node_t *) gIter->data;
122 
123  other_node = pe_hash_table_lookup(result, node->details->id);
124 
125  if (other_node == NULL) {
126  node_t *new_node = node_copy(node);
127 
128  new_node->weight = -INFINITY;
129  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
130  }
131  }
132 }
133 
134 GHashTable *
136 {
137  GListPtr gIter = list;
138  GHashTable *result = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
139 
140  for (; gIter != NULL; gIter = gIter->next) {
141  node_t *node = (node_t *) gIter->data;
142  node_t *n = node_copy(node);
143 
144  g_hash_table_insert(result, (gpointer) n->details->id, n);
145  }
146 
147  return result;
148 }
149 
150 GListPtr
151 node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
152 {
153  GListPtr result = NULL;
154  GListPtr gIter = list1;
155 
156  for (; gIter != NULL; gIter = gIter->next) {
157  node_t *new_node = NULL;
158  node_t *this_node = (node_t *) gIter->data;
159 
160  if (filter && this_node->weight < 0) {
161  continue;
162  }
163 
164  new_node = node_copy(this_node);
165  if (reset) {
166  new_node->weight = 0;
167  }
168  if (new_node != NULL) {
169  result = g_list_prepend(result, new_node);
170  }
171  }
172 
173  return result;
174 }
175 
176 gint
177 sort_node_uname(gconstpointer a, gconstpointer b)
178 {
179  const node_t *node_a = a;
180  const node_t *node_b = b;
181 
182  return strcmp(node_a->details->uname, node_b->details->uname);
183 }
184 
185 void
186 dump_node_scores_worker(int level, const char *file, const char *function, int line,
187  resource_t * rsc, const char *comment, GHashTable * nodes)
188 {
189  GHashTable *hash = nodes;
190  GHashTableIter iter;
191  node_t *node = NULL;
192 
193  if (rsc) {
194  hash = rsc->allowed_nodes;
195  }
196 
197  if (rsc && is_set(rsc->flags, pe_rsc_orphan)) {
198  /* Don't show the allocation scores for orphans */
199  return;
200  }
201 
202  if (level == 0) {
203  char score[128];
204  int len = sizeof(score);
205  /* For now we want this in sorted order to keep the regression tests happy */
206  GListPtr gIter = NULL;
207  GListPtr list = g_hash_table_get_values(hash);
208 
209  list = g_list_sort(list, sort_node_uname);
210 
211  gIter = list;
212  for (; gIter != NULL; gIter = gIter->next) {
213  node_t *node = (node_t *) gIter->data;
214  /* This function is called a whole lot, use stack allocated score */
215  score2char_stack(node->weight, score, len);
216 
217  if (rsc) {
218  printf("%s: %s allocation score on %s: %s\n",
219  comment, rsc->id, node->details->uname, score);
220  } else {
221  printf("%s: %s = %s\n", comment, node->details->uname, score);
222  }
223  }
224 
225  g_list_free(list);
226 
227  } else if (hash) {
228  char score[128];
229  int len = sizeof(score);
230  g_hash_table_iter_init(&iter, hash);
231  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
232  /* This function is called a whole lot, use stack allocated score */
233  score2char_stack(node->weight, score, len);
234 
235  if (rsc) {
236  do_crm_log_alias(LOG_TRACE, file, function, line,
237  "%s: %s allocation score on %s: %s", comment, rsc->id,
238  node->details->uname, score);
239  } else {
240  do_crm_log_alias(LOG_TRACE, file, function, line + 1, "%s: %s = %s", comment,
241  node->details->uname, score);
242  }
243  }
244  }
245 
246  if (rsc && rsc->children) {
247  GListPtr gIter = NULL;
248 
249  gIter = rsc->children;
250  for (; gIter != NULL; gIter = gIter->next) {
251  resource_t *child = (resource_t *) gIter->data;
252 
253  dump_node_scores_worker(level, file, function, line, child, comment, nodes);
254  }
255  }
256 }
257 
258 static void
259 append_dump_text(gpointer key, gpointer value, gpointer user_data)
260 {
261  char **dump_text = user_data;
262  int len = 0;
263  char *new_text = NULL;
264 
265  len = strlen(*dump_text) + strlen(" ") + strlen(key) + strlen("=") + strlen(value) + 1;
266  new_text = calloc(1, len);
267  sprintf(new_text, "%s %s=%s", *dump_text, (char *)key, (char *)value);
268 
269  free(*dump_text);
270  *dump_text = new_text;
271 }
272 
273 void
274 dump_node_capacity(int level, const char *comment, node_t * node)
275 {
276  int len = 0;
277  char *dump_text = NULL;
278 
279  len = strlen(comment) + strlen(": ") + strlen(node->details->uname) + strlen(" capacity:") + 1;
280  dump_text = calloc(1, len);
281  sprintf(dump_text, "%s: %s capacity:", comment, node->details->uname);
282 
283  g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
284 
285  if (level == 0) {
286  fprintf(stdout, "%s\n", dump_text);
287  } else {
288  crm_trace("%s", dump_text);
289  }
290 
291  free(dump_text);
292 }
293 
294 void
295 dump_rsc_utilization(int level, const char *comment, resource_t * rsc, node_t * node)
296 {
297  int len = 0;
298  char *dump_text = NULL;
299 
300  len = strlen(comment) + strlen(": ") + strlen(rsc->id) + strlen(" utilization on ")
301  + strlen(node->details->uname) + strlen(":") + 1;
302  dump_text = calloc(1, len);
303  sprintf(dump_text, "%s: %s utilization on %s:", comment, rsc->id, node->details->uname);
304 
305  g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
306 
307  if (level == 0) {
308  fprintf(stdout, "%s\n", dump_text);
309  } else {
310  crm_trace("%s", dump_text);
311  }
312 
313  free(dump_text);
314 }
315 
316 gint
317 sort_rsc_index(gconstpointer a, gconstpointer b)
318 {
319  const resource_t *resource1 = (const resource_t *)a;
320  const resource_t *resource2 = (const resource_t *)b;
321 
322  if (a == NULL && b == NULL) {
323  return 0;
324  }
325  if (a == NULL) {
326  return 1;
327  }
328  if (b == NULL) {
329  return -1;
330  }
331 
332  if (resource1->sort_index > resource2->sort_index) {
333  return -1;
334  }
335 
336  if (resource1->sort_index < resource2->sort_index) {
337  return 1;
338  }
339 
340  return 0;
341 }
342 
343 gint
344 sort_rsc_priority(gconstpointer a, gconstpointer b)
345 {
346  const resource_t *resource1 = (const resource_t *)a;
347  const resource_t *resource2 = (const resource_t *)b;
348 
349  if (a == NULL && b == NULL) {
350  return 0;
351  }
352  if (a == NULL) {
353  return 1;
354  }
355  if (b == NULL) {
356  return -1;
357  }
358 
359  if (resource1->priority > resource2->priority) {
360  return -1;
361  }
362 
363  if (resource1->priority < resource2->priority) {
364  return 1;
365  }
366 
367  return 0;
368 }
369 
370 action_t *
371 custom_action(resource_t * rsc, char *key, const char *task,
372  node_t * on_node, gboolean optional, gboolean save_action,
373  pe_working_set_t * data_set)
374 {
375  action_t *action = NULL;
376  GListPtr possible_matches = NULL;
377 
378  CRM_CHECK(key != NULL, return NULL);
379  CRM_CHECK(task != NULL, free(key); return NULL);
380 
381  if (save_action && rsc != NULL) {
382  possible_matches = find_actions(rsc->actions, key, on_node);
383  } else if(save_action) {
384 #if 0
385  action = g_hash_table_lookup(data_set->singletons, key);
386 #else
387  /* More expensive but takes 'node' into account */
388  possible_matches = find_actions(data_set->actions, key, on_node);
389 #endif
390  }
391 
392  if(data_set->singletons == NULL) {
393  data_set->singletons = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
394  }
395 
396  if (possible_matches != NULL) {
397  if (g_list_length(possible_matches) > 1) {
398  pe_warn("Action %s for %s on %s exists %d times",
399  task, rsc ? rsc->id : "<NULL>",
400  on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
401  }
402 
403  action = g_list_nth_data(possible_matches, 0);
404  pe_rsc_trace(rsc, "Found existing action (%d) %s for %s on %s",
405  action->id, task, rsc ? rsc->id : "<NULL>",
406  on_node ? on_node->details->uname : "<NULL>");
407  g_list_free(possible_matches);
408  }
409 
410  if (action == NULL) {
411  if (save_action) {
412  pe_rsc_trace(rsc, "Creating%s action %d: %s for %s on %s %d",
413  optional ? "" : " mandatory", data_set->action_id, key,
414  rsc ? rsc->id : "<NULL>", on_node ? on_node->details->uname : "<NULL>", optional);
415  }
416 
417  action = calloc(1, sizeof(action_t));
418  if (save_action) {
419  action->id = data_set->action_id++;
420  } else {
421  action->id = 0;
422  }
423  action->rsc = rsc;
424  CRM_ASSERT(task != NULL);
425  action->task = strdup(task);
426  if (on_node) {
427  action->node = node_copy(on_node);
428  }
429  action->uuid = strdup(key);
430 
432  if (optional) {
433  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
435  } else {
437  pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
438  }
439 
440 /*
441  Implied by calloc()...
442  action->actions_before = NULL;
443  action->actions_after = NULL;
444 
445  action->pseudo = FALSE;
446  action->dumped = FALSE;
447  action->processed = FALSE;
448  action->seen_count = 0;
449 */
450 
451  action->extra = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
452 
453  action->meta = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
454 
455  if (save_action) {
456  data_set->actions = g_list_prepend(data_set->actions, action);
457  if(rsc == NULL) {
458  g_hash_table_insert(data_set->singletons, action->uuid, action);
459  }
460  }
461 
462  if (rsc != NULL) {
463  action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
464 
465  unpack_operation(action, action->op_entry, rsc->container, data_set);
466 
467  if (save_action) {
468  rsc->actions = g_list_prepend(rsc->actions, action);
469  }
470  }
471 
472  if (save_action) {
473  pe_rsc_trace(rsc, "Action %d created", action->id);
474  }
475  }
476 
477  if (optional == FALSE) {
478  pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
480  }
481 
482  if (rsc != NULL) {
483  enum action_tasks a_task = text2task(action->task);
484  int warn_level = LOG_TRACE;
485 
486  if (save_action) {
487  warn_level = LOG_WARNING;
488  }
489 
490  if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
491  && action->node != NULL && action->op_entry != NULL) {
494  action->node->details->attrs,
495  action->extra, NULL, FALSE, data_set->now);
496  }
497 
498  if (is_set(action->flags, pe_action_pseudo)) {
499  /* leave untouched */
500 
501  } else if (action->node == NULL) {
502  pe_rsc_trace(rsc, "Unset runnable on %s", action->uuid);
504 
505  } else if (is_not_set(rsc->flags, pe_rsc_managed)
506  && g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL) == NULL) {
507  crm_debug("Action %s (unmanaged)", action->uuid);
508  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
510 /* action->runnable = FALSE; */
511 
512  } else if (action->node->details->online == FALSE
513  && (!is_container_remote_node(action->node) || action->node->details->remote_requires_reset)) {
515  do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
516  action->uuid, action->node->details->uname);
517  if (is_set(action->rsc->flags, pe_rsc_managed)
518  && save_action && a_task == stop_rsc
519  && action->node->details->unclean == FALSE) {
520  pe_fence_node(data_set, action->node, "resource actions are unrunnable");
521  }
522 
523  } else if (action->node->details->pending) {
525  do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
526  action->uuid, action->node->details->uname);
527 
528  } else if (action->needs == rsc_req_nothing) {
529  pe_rsc_trace(rsc, "Action %s does not require anything", action->uuid);
531 #if 0
532  /*
533  * No point checking this
534  * - if we don't have quorum we can't stonith anyway
535  */
536  } else if (action->needs == rsc_req_stonith) {
537  crm_trace("Action %s requires only stonith", action->uuid);
538  action->runnable = TRUE;
539 #endif
540  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
541  && data_set->no_quorum_policy == no_quorum_stop) {
543  crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);
544 
545  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
546  && data_set->no_quorum_policy == no_quorum_freeze) {
547  pe_rsc_trace(rsc, "Check resource is already active: %s %s %s %s", rsc->id, action->uuid, role2text(rsc->next_role), role2text(rsc->role));
548  if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
550  pe_rsc_debug(rsc, "%s\t%s (cancelled : quorum freeze)",
551  action->node->details->uname, action->uuid);
552  }
553 
554  } else {
555  pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
557  }
558 
559  if (save_action) {
560  switch (a_task) {
561  case stop_rsc:
563  break;
564  case start_rsc:
566  if (is_set(action->flags, pe_action_runnable)) {
568  }
569  break;
570  default:
571  break;
572  }
573  }
574  }
575 
576  free(key);
577  return action;
578 }
579 
580 static const char *
581 unpack_operation_on_fail(action_t * action)
582 {
583 
584  const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
585 
586  if (safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) {
587  crm_config_err("on-fail=standby is not allowed for stop actions: %s", action->rsc->id);
588  return NULL;
589  } else if (safe_str_eq(action->task, CRMD_ACTION_DEMOTE) && !value) {
590  /* demote on_fail defaults to master monitor value if present */
591  xmlNode *operation = NULL;
592  const char *name = NULL;
593  const char *role = NULL;
594  const char *on_fail = NULL;
595  const char *interval = NULL;
596  const char *enabled = NULL;
597 
598  CRM_CHECK(action->rsc != NULL, return NULL);
599 
600  for (operation = __xml_first_child(action->rsc->ops_xml);
601  operation && !value; operation = __xml_next_element(operation)) {
602 
603  if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
604  continue;
605  }
606  name = crm_element_value(operation, "name");
607  role = crm_element_value(operation, "role");
608  on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
609  enabled = crm_element_value(operation, "enabled");
610  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
611  if (!on_fail) {
612  continue;
613  } else if (enabled && !crm_is_true(enabled)) {
614  continue;
615  } else if (safe_str_neq(name, "monitor") || safe_str_neq(role, "Master")) {
616  continue;
617  } else if (crm_get_interval(interval) <= 0) {
618  continue;
619  }
620 
621  value = on_fail;
622  }
623  }
624 
625  return value;
626 }
627 
628 static xmlNode *
629 find_min_interval_mon(resource_t * rsc, gboolean include_disabled)
630 {
631  int number = 0;
632  int min_interval = -1;
633  const char *name = NULL;
634  const char *value = NULL;
635  const char *interval = NULL;
636  xmlNode *op = NULL;
637  xmlNode *operation = NULL;
638 
639  for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
640  operation = __xml_next_element(operation)) {
641 
642  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
643  name = crm_element_value(operation, "name");
644  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
645  value = crm_element_value(operation, "enabled");
646  if (!include_disabled && value && crm_is_true(value) == FALSE) {
647  continue;
648  }
649 
650  if (safe_str_neq(name, RSC_STATUS)) {
651  continue;
652  }
653 
654  number = crm_get_interval(interval);
655  if (number < 0) {
656  continue;
657  }
658 
659  if (min_interval < 0 || number < min_interval) {
660  min_interval = number;
661  op = operation;
662  }
663  }
664  }
665 
666  return op;
667 }
668 
669 void
670 unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
671  pe_working_set_t * data_set)
672 {
673  int value_i = 0;
674  unsigned long long interval = 0;
675  unsigned long long start_delay = 0;
676  char *value_ms = NULL;
677  const char *value = NULL;
678  const char *field = NULL;
679 
680  CRM_CHECK(action->rsc != NULL, return);
681 
683  action->meta, NULL, FALSE, data_set->now);
684 
685  if (xml_obj) {
686  xmlAttrPtr xIter = NULL;
687 
688  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
689  const char *prop_name = (const char *)xIter->name;
690  const char *prop_value = crm_element_value(xml_obj, prop_name);
691 
692  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
693  }
694  }
695 
697  NULL, action->meta, NULL, FALSE, data_set->now);
698 
700  NULL, action->meta, NULL, FALSE, data_set->now);
701  g_hash_table_remove(action->meta, "id");
702 
703  field = XML_LRM_ATTR_INTERVAL;
704  value = g_hash_table_lookup(action->meta, field);
705  if (value != NULL) {
706  interval = crm_get_interval(value);
707  if (interval > 0) {
708  value_ms = crm_itoa(interval);
709  g_hash_table_replace(action->meta, strdup(field), value_ms);
710 
711  } else {
712  g_hash_table_remove(action->meta, field);
713  }
714  }
715 
716  /* Begin compatibility code ("requires" set on start action not resource) */
717  value = g_hash_table_lookup(action->meta, "requires");
718 
719  if (safe_str_neq(action->task, RSC_START)
720  && safe_str_neq(action->task, RSC_PROMOTE)) {
721  action->needs = rsc_req_nothing;
722  value = "nothing (not start/promote)";
723 
724  } else if (safe_str_eq(value, "nothing")) {
725  action->needs = rsc_req_nothing;
726 
727  } else if (safe_str_eq(value, "quorum")) {
728  action->needs = rsc_req_quorum;
729 
730  } else if (safe_str_eq(value, "unfencing")) {
731  action->needs = rsc_req_stonith;
733  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
734  crm_notice("%s requires unfencing but fencing is disabled", action->rsc->id);
735  }
736 
737  } else if (is_set(data_set->flags, pe_flag_stonith_enabled)
738  && safe_str_eq(value, "fencing")) {
739  action->needs = rsc_req_stonith;
740  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
741  crm_notice("%s requires fencing but fencing is disabled", action->rsc->id);
742  }
743  /* End compatibility code */
744 
745  } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
746  action->needs = rsc_req_stonith;
747  value = "fencing (resource)";
748 
749  } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
750  action->needs = rsc_req_quorum;
751  value = "quorum (resource)";
752 
753  } else {
754  action->needs = rsc_req_nothing;
755  value = "nothing (resource)";
756  }
757 
758  pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->task, value);
759 
760  value = unpack_operation_on_fail(action);
761 
762  if (value == NULL) {
763 
764  } else if (safe_str_eq(value, "block")) {
765  action->on_fail = action_fail_block;
766  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
767 
768  } else if (safe_str_eq(value, "fence")) {
769  action->on_fail = action_fail_fence;
770  value = "node fencing";
771 
772  if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
773  crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense");
774  action->on_fail = action_fail_stop;
775  action->fail_role = RSC_ROLE_STOPPED;
776  value = "stop resource";
777  }
778 
779  } else if (safe_str_eq(value, "standby")) {
780  action->on_fail = action_fail_standby;
781  value = "node standby";
782 
783  } else if (safe_str_eq(value, "ignore")
784  || safe_str_eq(value, "nothing")) {
785  action->on_fail = action_fail_ignore;
786  value = "ignore";
787 
788  } else if (safe_str_eq(value, "migrate")) {
789  action->on_fail = action_fail_migrate;
790  value = "force migration";
791 
792  } else if (safe_str_eq(value, "stop")) {
793  action->on_fail = action_fail_stop;
794  action->fail_role = RSC_ROLE_STOPPED;
795  value = "stop resource";
796 
797  } else if (safe_str_eq(value, "restart")) {
798  action->on_fail = action_fail_recover;
799  value = "restart (and possibly migrate)";
800 
801  } else if (safe_str_eq(value, "restart-container")) {
802  if (container) {
804  value = "restart container (and possibly migrate)";
805 
806  } else {
807  value = NULL;
808  }
809 
810  } else {
811  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
812  value = NULL;
813  }
814 
815  /* defaults */
816  if (value == NULL && container) {
818  value = "restart container (and possibly migrate) (default)";
819 
820  /* for baremetal remote nodes, ensure that any failure that results in
821  * dropping an active connection to a remote node results in fencing of
822  * the remote node.
823  *
824  * There are only two action failures that don't result in fencing.
825  * 1. probes - probe failures are expected.
826  * 2. start - a start failure indicates that an active connection does not already
827  * exist. The user can set op on-fail=fence if they really want to fence start
828  * failures. */
829  } else if (((value == NULL) || !is_set(action->rsc->flags, pe_rsc_managed)) &&
830  (is_rsc_baremetal_remote_node(action->rsc, data_set) &&
831  !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && interval == 0) &&
832  (safe_str_neq(action->task, CRMD_ACTION_START)))) {
833 
834  if (!is_set(action->rsc->flags, pe_rsc_managed)) {
835  action->on_fail = action_fail_stop;
836  action->fail_role = RSC_ROLE_STOPPED;
837  value = "stop unmanaged baremetal remote node (enforcing default)";
838 
839  } else {
840  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
841  value = "fence baremetal remote node (default)";
842  } else {
843  value = "recover baremetal remote node connection (default)";
844  }
845 
846  if (action->rsc->remote_reconnect_interval) {
847  action->fail_role = RSC_ROLE_STOPPED;
848  }
850  }
851 
852  } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
853  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
854  action->on_fail = action_fail_fence;
855  value = "resource fence (default)";
856 
857  } else {
858  action->on_fail = action_fail_block;
859  value = "resource block (default)";
860  }
861 
862  } else if (value == NULL) {
863  action->on_fail = action_fail_recover;
864  value = "restart (and possibly migrate) (default)";
865  }
866 
867  pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
868 
869  value = NULL;
870  if (xml_obj != NULL) {
871  value = g_hash_table_lookup(action->meta, "role_after_failure");
872  }
873  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
874  action->fail_role = text2role(value);
875  }
876  /* defaults */
877  if (action->fail_role == RSC_ROLE_UNKNOWN) {
878  if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
879  action->fail_role = RSC_ROLE_SLAVE;
880  } else {
881  action->fail_role = RSC_ROLE_STARTED;
882  }
883  }
884  pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
885  role2text(action->fail_role));
886 
887  field = XML_OP_ATTR_START_DELAY;
888  value = g_hash_table_lookup(action->meta, field);
889  if (value != NULL) {
890  value_i = crm_get_msec(value);
891  if (value_i < 0) {
892  value_i = 0;
893  }
894  start_delay = value_i;
895  value_ms = crm_itoa(value_i);
896  g_hash_table_replace(action->meta, strdup(field), value_ms);
897 
898  } else if (interval > 0 && g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN)) {
899  crm_time_t *origin = NULL;
900 
901  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
902  origin = crm_time_new(value);
903 
904  if (origin == NULL) {
905  crm_config_err("Operation %s contained an invalid " XML_OP_ATTR_ORIGIN ": %s",
906  ID(xml_obj), value);
907 
908  } else {
909  crm_time_t *delay = NULL;
910  int rc = crm_time_compare(origin, data_set->now);
911  long long delay_s = 0;
912  int interval_s = (interval / 1000);
913 
914  crm_trace("Origin: %s, interval: %d", value, interval_s);
915 
916  /* If 'origin' is in the future, find the most recent "multiple" that occurred in the past */
917  while(rc > 0) {
918  crm_time_add_seconds(origin, -interval_s);
919  rc = crm_time_compare(origin, data_set->now);
920  }
921 
922  /* Now find the first "multiple" that occurs after 'now' */
923  while (rc < 0) {
924  crm_time_add_seconds(origin, interval_s);
925  rc = crm_time_compare(origin, data_set->now);
926  }
927 
928  delay = crm_time_calculate_duration(origin, data_set->now);
929 
930  crm_time_log(LOG_TRACE, "origin", origin,
933  crm_time_log(LOG_TRACE, "now", data_set->now,
936  crm_time_log(LOG_TRACE, "delay", delay, crm_time_log_duration);
937 
938  delay_s = crm_time_get_seconds(delay);
939 
940  CRM_CHECK(delay_s >= 0, delay_s = 0);
941  start_delay = delay_s * 1000;
942 
943  crm_info("Calculated a start delay of %llds for %s", delay_s, ID(xml_obj));
944  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
945  crm_itoa(start_delay));
946  crm_time_free(origin);
947  crm_time_free(delay);
948  }
949  }
950 
951  field = XML_ATTR_TIMEOUT;
952  value = g_hash_table_lookup(action->meta, field);
953  if (value == NULL && xml_obj == NULL && safe_str_eq(action->task, RSC_STATUS) && interval == 0) {
954  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
955 
956  if (min_interval_mon) {
957  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
958  pe_rsc_trace(action->rsc,
959  "\t%s uses the timeout value '%s' from the minimum interval monitor",
960  action->uuid, value);
961  }
962  }
963  if (value == NULL) {
964  value = pe_pref(data_set->config_hash, "default-action-timeout");
965  }
966  value_i = crm_get_msec(value);
967  if (value_i < 0) {
968  value_i = 0;
969  }
970  value_ms = crm_itoa(value_i);
971  g_hash_table_replace(action->meta, strdup(field), value_ms);
972 }
973 
974 static xmlNode *
975 find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_disabled)
976 {
977  unsigned long long number = 0;
978  gboolean do_retry = TRUE;
979  char *local_key = NULL;
980  const char *name = NULL;
981  const char *value = NULL;
982  const char *interval = NULL;
983  char *match_key = NULL;
984  xmlNode *op = NULL;
985  xmlNode *operation = NULL;
986 
987  retry:
988  for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
989  operation = __xml_next_element(operation)) {
990  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
991  name = crm_element_value(operation, "name");
992  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
993  value = crm_element_value(operation, "enabled");
994  if (!include_disabled && value && crm_is_true(value) == FALSE) {
995  continue;
996  }
997 
998  number = crm_get_interval(interval);
999  match_key = generate_op_key(rsc->id, name, number);
1000  if (safe_str_eq(key, match_key)) {
1001  op = operation;
1002  }
1003  free(match_key);
1004 
1005  if (rsc->clone_name) {
1006  match_key = generate_op_key(rsc->clone_name, name, number);
1007  if (safe_str_eq(key, match_key)) {
1008  op = operation;
1009  }
1010  free(match_key);
1011  }
1012 
1013  if (op != NULL) {
1014  free(local_key);
1015  return op;
1016  }
1017  }
1018  }
1019 
1020  free(local_key);
1021  if (do_retry == FALSE) {
1022  return NULL;
1023  }
1024 
1025  do_retry = FALSE;
1026  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1027  local_key = generate_op_key(rsc->id, "migrate", 0);
1028  key = local_key;
1029  goto retry;
1030 
1031  } else if (strstr(key, "_notify_")) {
1032  local_key = generate_op_key(rsc->id, "notify", 0);
1033  key = local_key;
1034  goto retry;
1035  }
1036 
1037  return NULL;
1038 }
1039 
1040 xmlNode *
1041 find_rsc_op_entry(resource_t * rsc, const char *key)
1042 {
1043  return find_rsc_op_entry_helper(rsc, key, FALSE);
1044 }
1045 
1046 void
1047 print_node(const char *pre_text, node_t * node, gboolean details)
1048 {
1049  if (node == NULL) {
1050  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1051  return;
1052  }
1053 
1054  CRM_ASSERT(node->details);
1055  crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1056  pre_text == NULL ? "" : pre_text,
1057  pre_text == NULL ? "" : ": ",
1058  node->details->online ? "" : "Unavailable/Unclean ",
1059  node->details->uname, node->weight, node->fixed ? "True" : "False");
1060 
1061  if (details) {
1062  char *pe_mutable = strdup("\t\t");
1063  GListPtr gIter = node->details->running_rsc;
1064 
1065  crm_trace("\t\t===Node Attributes");
1066  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1067  free(pe_mutable);
1068 
1069  crm_trace("\t\t=== Resources");
1070 
1071  for (; gIter != NULL; gIter = gIter->next) {
1072  resource_t *rsc = (resource_t *) gIter->data;
1073 
1074  print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE);
1075  }
1076  }
1077 }
1078 
1079 /*
1080  * Used by the HashTable for-loop
1081  */
1082 void
1083 print_str_str(gpointer key, gpointer value, gpointer user_data)
1084 {
1085  crm_trace("%s%s %s ==> %s",
1086  user_data == NULL ? "" : (char *)user_data,
1087  user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1088 }
1089 
1090 void
1091 print_resource(int log_level, const char *pre_text, resource_t * rsc, gboolean details)
1092 {
1093  long options = pe_print_log | pe_print_pending;
1094 
1095  if (rsc == NULL) {
1096  do_crm_log(log_level - 1, "%s%s: <NULL>",
1097  pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1098  return;
1099  }
1100  if (details) {
1101  options |= pe_print_details;
1102  }
1103  rsc->fns->print(rsc, pre_text, options, &log_level);
1104 }
1105 
1106 void
1108 {
1109  if (action == NULL) {
1110  return;
1111  }
1112  g_list_free_full(action->actions_before, free); /* action_wrapper_t* */
1113  g_list_free_full(action->actions_after, free); /* action_wrapper_t* */
1114  if (action->extra) {
1115  g_hash_table_destroy(action->extra);
1116  }
1117  if (action->meta) {
1118  g_hash_table_destroy(action->meta);
1119  }
1120  free(action->cancel_task);
1121  free(action->task);
1122  free(action->uuid);
1123  free(action->node);
1124  free(action);
1125 }
1126 
1127 GListPtr
1129 {
1130  const char *value = NULL;
1131  GListPtr result = NULL;
1132  GListPtr gIter = input;
1133 
1134  CRM_CHECK(input != NULL, return NULL);
1135 
1136  for (; gIter != NULL; gIter = gIter->next) {
1137  action_t *action = (action_t *) gIter->data;
1138 
1139  value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
1140  if (value == NULL) {
1141  /* skip */
1142  } else if (safe_str_eq(value, "0")) {
1143  /* skip */
1144  } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1145  /* skip */
1146  } else if (not_on_node == NULL) {
1147  crm_trace("(null) Found: %s", action->uuid);
1148  result = g_list_prepend(result, action);
1149 
1150  } else if (action->node == NULL) {
1151  /* skip */
1152  } else if (action->node->details != not_on_node->details) {
1153  crm_trace("Found: %s", action->uuid);
1154  result = g_list_prepend(result, action);
1155  }
1156  }
1157 
1158  return result;
1159 }
1160 
1161 enum action_tasks
1162 get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic)
1163 {
1164  enum action_tasks task = text2task(name);
1165 
1166  if (rsc == NULL) {
1167  return task;
1168 
1169  } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1170  switch (task) {
1171  case stopped_rsc:
1172  case started_rsc:
1173  case action_demoted:
1174  case action_promoted:
1175  crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1176  return task - 1;
1177  break;
1178  default:
1179  break;
1180  }
1181  }
1182  return task;
1183 }
1184 
1185 action_t *
1186 find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node)
1187 {
1188  GListPtr gIter = NULL;
1189 
1190  CRM_CHECK(uuid || task, return NULL);
1191 
1192  for (gIter = input; gIter != NULL; gIter = gIter->next) {
1193  action_t *action = (action_t *) gIter->data;
1194 
1195  if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1196  continue;
1197 
1198  } else if (task != NULL && safe_str_neq(task, action->task)) {
1199  continue;
1200 
1201  } else if (on_node == NULL) {
1202  return action;
1203 
1204  } else if (action->node == NULL) {
1205  continue;
1206 
1207  } else if (on_node->details == action->node->details) {
1208  return action;
1209  }
1210  }
1211 
1212  return NULL;
1213 }
1214 
1215 GListPtr
1216 find_actions(GListPtr input, const char *key, const node_t *on_node)
1217 {
1218  GListPtr gIter = input;
1219  GListPtr result = NULL;
1220 
1221  CRM_CHECK(key != NULL, return NULL);
1222 
1223  for (; gIter != NULL; gIter = gIter->next) {
1224  action_t *action = (action_t *) gIter->data;
1225 
1226  if (safe_str_neq(key, action->uuid)) {
1227  crm_trace("%s does not match action %s", key, action->uuid);
1228  continue;
1229 
1230  } else if (on_node == NULL) {
1231  crm_trace("Action %s matches (ignoring node)", key);
1232  result = g_list_prepend(result, action);
1233 
1234  } else if (action->node == NULL) {
1235  crm_trace("Action %s matches (unallocated, assigning to %s)",
1236  key, on_node->details->uname);
1237 
1238  action->node = node_copy(on_node);
1239  result = g_list_prepend(result, action);
1240 
1241  } else if (on_node->details == action->node->details) {
1242  crm_trace("Action %s on %s matches", key, on_node->details->uname);
1243  result = g_list_prepend(result, action);
1244 
1245  } else {
1246  crm_trace("Action %s on node %s does not match requested node %s",
1247  key, action->node->details->uname,
1248  on_node->details->uname);
1249  }
1250  }
1251 
1252  return result;
1253 }
1254 
1255 GListPtr
1256 find_actions_exact(GListPtr input, const char *key, node_t * on_node)
1257 {
1258  GListPtr gIter = input;
1259  GListPtr result = NULL;
1260 
1261  CRM_CHECK(key != NULL, return NULL);
1262 
1263  for (; gIter != NULL; gIter = gIter->next) {
1264  action_t *action = (action_t *) gIter->data;
1265 
1266  crm_trace("Matching %s against %s", key, action->uuid);
1267  if (safe_str_neq(key, action->uuid)) {
1268  crm_trace("Key mismatch: %s vs. %s", key, action->uuid);
1269  continue;
1270 
1271  } else if (on_node == NULL || action->node == NULL) {
1272  crm_trace("on_node=%p, action->node=%p", on_node, action->node);
1273  continue;
1274 
1275  } else if (safe_str_eq(on_node->details->id, action->node->details->id)) {
1276  result = g_list_prepend(result, action);
1277  }
1278  crm_trace("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id);
1279  }
1280 
1281  return result;
1282 }
1283 
1284 static void
1285 resource_node_score(resource_t * rsc, node_t * node, int score, const char *tag)
1286 {
1287  node_t *match = NULL;
1288 
1289  if (rsc->children) {
1290  GListPtr gIter = rsc->children;
1291 
1292  for (; gIter != NULL; gIter = gIter->next) {
1293  resource_t *child_rsc = (resource_t *) gIter->data;
1294 
1295  resource_node_score(child_rsc, node, score, tag);
1296  }
1297  }
1298 
1299  pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1300  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1301  if (match == NULL) {
1302  match = node_copy(node);
1303  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1304  }
1305  match->weight = merge_weights(match->weight, score);
1306 }
1307 
1308 void
1309 resource_location(resource_t * rsc, node_t * node, int score, const char *tag,
1310  pe_working_set_t * data_set)
1311 {
1312  if (node != NULL) {
1313  resource_node_score(rsc, node, score, tag);
1314 
1315  } else if (data_set != NULL) {
1316  GListPtr gIter = data_set->nodes;
1317 
1318  for (; gIter != NULL; gIter = gIter->next) {
1319  node_t *node_iter = (node_t *) gIter->data;
1320 
1321  resource_node_score(rsc, node_iter, score, tag);
1322  }
1323 
1324  } else {
1325  GHashTableIter iter;
1326  node_t *node_iter = NULL;
1327 
1328  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1329  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1330  resource_node_score(rsc, node_iter, score, tag);
1331  }
1332  }
1333 
1334  if (node == NULL && score == -INFINITY) {
1335  if (rsc->allocated_to) {
1336  crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1337  free(rsc->allocated_to);
1338  rsc->allocated_to = NULL;
1339  }
1340  }
1341 }
1342 
1343 #define sort_return(an_int, why) do { \
1344  free(a_uuid); \
1345  free(b_uuid); \
1346  crm_trace("%s (%d) %c %s (%d) : %s", \
1347  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1348  b_xml_id, b_call_id, why); \
1349  return an_int; \
1350  } while(0)
1351 
1352 gint
1353 sort_op_by_callid(gconstpointer a, gconstpointer b)
1354 {
1355  int a_call_id = -1;
1356  int b_call_id = -1;
1357 
1358  char *a_uuid = NULL;
1359  char *b_uuid = NULL;
1360 
1361  const xmlNode *xml_a = a;
1362  const xmlNode *xml_b = b;
1363 
1364  const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID);
1365  const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID);
1366 
1367  if (safe_str_eq(a_xml_id, b_xml_id)) {
1368  /* We have duplicate lrm_rsc_op entries in the status
1369  * section which is unliklely to be a good thing
1370  * - we can handle it easily enough, but we need to get
1371  * to the bottom of why its happening.
1372  */
1373  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1374  sort_return(0, "duplicate");
1375  }
1376 
1379 
1380  if (a_call_id == -1 && b_call_id == -1) {
1381  /* both are pending ops so it doesn't matter since
1382  * stops are never pending
1383  */
1384  sort_return(0, "pending");
1385 
1386  } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1387  sort_return(-1, "call id");
1388 
1389  } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1390  sort_return(1, "call id");
1391 
1392  } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1393  /*
1394  * The op and last_failed_op are the same
1395  * Order on last-rc-change
1396  */
1397  int last_a = -1;
1398  int last_b = -1;
1399 
1402 
1403  crm_trace("rc-change: %d vs %d", last_a, last_b);
1404  if (last_a >= 0 && last_a < last_b) {
1405  sort_return(-1, "rc-change");
1406 
1407  } else if (last_b >= 0 && last_a > last_b) {
1408  sort_return(1, "rc-change");
1409  }
1410  sort_return(0, "rc-change");
1411 
1412  } else {
1413  /* One of the inputs is a pending operation
1414  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1415  */
1416 
1417  int a_id = -1;
1418  int b_id = -1;
1419  int dummy = -1;
1420 
1421  const char *a_magic = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC);
1422  const char *b_magic = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC);
1423 
1424  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1425  if(!decode_transition_magic(a_magic, &a_uuid, &a_id, &dummy, &dummy, &dummy, &dummy)) {
1426  sort_return(0, "bad magic a");
1427  }
1428  if(!decode_transition_magic(b_magic, &b_uuid, &b_id, &dummy, &dummy, &dummy, &dummy)) {
1429  sort_return(0, "bad magic b");
1430  }
1431  /* try to determine the relative age of the operation...
1432  * some pending operations (ie. a start) may have been superseded
1433  * by a subsequent stop
1434  *
1435  * [a|b]_id == -1 means its a shutdown operation and _always_ comes last
1436  */
1437  if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1438  /*
1439  * some of the logic in here may be redundant...
1440  *
1441  * if the UUID from the TE doesn't match then one better
1442  * be a pending operation.
1443  * pending operations don't survive between elections and joins
1444  * because we query the LRM directly
1445  */
1446 
1447  if (b_call_id == -1) {
1448  sort_return(-1, "transition + call");
1449 
1450  } else if (a_call_id == -1) {
1451  sort_return(1, "transition + call");
1452  }
1453 
1454  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1455  sort_return(-1, "transition");
1456 
1457  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1458  sort_return(1, "transition");
1459  }
1460  }
1461 
1462  /* we should never end up here */
1463  CRM_CHECK(FALSE, sort_return(0, "default"));
1464 
1465 }
1466 
1467 time_t
1469 {
1470  if(data_set) {
1471  if (data_set->now == NULL) {
1472  crm_trace("Recording a new 'now'");
1473  data_set->now = crm_time_new(NULL);
1474  }
1475  return crm_time_get_seconds_since_epoch(data_set->now);
1476  }
1477 
1478  crm_trace("Defaulting to 'now'");
1479  return time(NULL);
1480 }
1481 
1482 gboolean
1484 {
1485  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1486  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1487 
1488  CRM_CHECK(role != NULL, return FALSE);
1489 
1490  if (value == NULL || safe_str_eq("started", value)
1491  || safe_str_eq("default", value)) {
1492  return FALSE;
1493  }
1494 
1495  local_role = text2role(value);
1496  if (local_role == RSC_ROLE_UNKNOWN) {
1497  crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1498  return FALSE;
1499 
1500  } else if (local_role > RSC_ROLE_STARTED) {
1501  if (uber_parent(rsc)->variant == pe_master) {
1502  if (local_role > RSC_ROLE_SLAVE) {
1503  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1504  return FALSE;
1505  }
1506 
1507  } else {
1508  crm_config_err("%s is not part of a master/slave resource, a %s of '%s' makes no sense",
1509  rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1510  return FALSE;
1511  }
1512  }
1513 
1514  *role = local_role;
1515  return TRUE;
1516 }
1517 
1518 gboolean
1519 order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order)
1520 {
1521  GListPtr gIter = NULL;
1522  action_wrapper_t *wrapper = NULL;
1523  GListPtr list = NULL;
1524 
1525  if (order == pe_order_none) {
1526  return FALSE;
1527  }
1528 
1529  if (lh_action == NULL || rh_action == NULL) {
1530  return FALSE;
1531  }
1532 
1533  crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1534 
1535  /* Ensure we never create a dependency on ourselves... its happened */
1536  CRM_ASSERT(lh_action != rh_action);
1537 
1538  /* Filter dups, otherwise update_action_states() has too much work to do */
1539  gIter = lh_action->actions_after;
1540  for (; gIter != NULL; gIter = gIter->next) {
1541  action_wrapper_t *after = (action_wrapper_t *) gIter->data;
1542 
1543  if (after->action == rh_action && (after->type & order)) {
1544  return FALSE;
1545  }
1546  }
1547 
1548  wrapper = calloc(1, sizeof(action_wrapper_t));
1549  wrapper->action = rh_action;
1550  wrapper->type = order;
1551 
1552  list = lh_action->actions_after;
1553  list = g_list_prepend(list, wrapper);
1554  lh_action->actions_after = list;
1555 
1556  wrapper = NULL;
1557 
1558 /* order |= pe_order_implies_then; */
1559 /* order ^= pe_order_implies_then; */
1560 
1561  wrapper = calloc(1, sizeof(action_wrapper_t));
1562  wrapper->action = lh_action;
1563  wrapper->type = order;
1564  list = rh_action->actions_before;
1565  list = g_list_prepend(list, wrapper);
1566  rh_action->actions_before = list;
1567  return TRUE;
1568 }
1569 
1570 action_t *
1571 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1572 {
1573  action_t *op = NULL;
1574 
1575  if(data_set->singletons) {
1576  op = g_hash_table_lookup(data_set->singletons, name);
1577  }
1578  if (op == NULL) {
1579  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1582  }
1583 
1584  return op;
1585 }
1586 
1587 void
1589 {
1590  ticket_t *ticket = data;
1591 
1592  if (ticket->state) {
1593  g_hash_table_destroy(ticket->state);
1594  }
1595  free(ticket->id);
1596  free(ticket);
1597 }
1598 
1599 ticket_t *
1600 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1601 {
1602  ticket_t *ticket = NULL;
1603 
1604  if (ticket_id == NULL || strlen(ticket_id) == 0) {
1605  return NULL;
1606  }
1607 
1608  if (data_set->tickets == NULL) {
1609  data_set->tickets =
1610  g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_ticket);
1611  }
1612 
1613  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1614  if (ticket == NULL) {
1615 
1616  ticket = calloc(1, sizeof(ticket_t));
1617  if (ticket == NULL) {
1618  crm_err("Cannot allocate ticket '%s'", ticket_id);
1619  return NULL;
1620  }
1621 
1622  crm_trace("Creaing ticket entry for %s", ticket_id);
1623 
1624  ticket->id = strdup(ticket_id);
1625  ticket->granted = FALSE;
1626  ticket->last_granted = -1;
1627  ticket->standby = FALSE;
1628  ticket->state = g_hash_table_new_full(crm_str_hash, g_str_equal,
1630 
1631  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1632  }
1633 
1634  return ticket;
1635 }
1636 
1637 static void
1638 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1639 {
1640  int len = 0;
1641  char *name = NULL;
1642  char *match = NULL;
1643 
1644  if (param_set == NULL) {
1645  return;
1646  }
1647 
1648  if (param_set) {
1649  xmlAttrPtr xIter = param_set->properties;
1650 
1651  while (xIter) {
1652  const char *prop_name = (const char *)xIter->name;
1653 
1654  xIter = xIter->next;
1655  name = NULL;
1656  len = strlen(prop_name) + 3;
1657 
1658  name = malloc(len);
1659  if(name) {
1660  sprintf(name, " %s ", prop_name);
1661  name[len - 1] = 0;
1662  match = strstr(param_string, name);
1663  }
1664 
1665  if (need_present && match == NULL) {
1666  crm_trace("%s not found in %s", prop_name, param_string);
1667  xml_remove_prop(param_set, prop_name);
1668 
1669  } else if (need_present == FALSE && match) {
1670  crm_trace("%s found in %s", prop_name, param_string);
1671  xml_remove_prop(param_set, prop_name);
1672  }
1673  free(name);
1674  }
1675  }
1676 }
1677 
1679 {
1680  const char *name;
1681  const char *value;
1682  const char *attr_list[] = {
1683  XML_ATTR_TYPE,
1686  };
1687  const char *value_list[] = {
1688  "remote",
1689  "ocf",
1690  "pacemaker"
1691  };
1692 
1693  if(rsc == NULL) {
1694  return FALSE;
1695  }
1696 
1697  name = "addr";
1698  value = g_hash_table_lookup(rsc->parameters, name);
1699  if (safe_str_eq(value, "#uname") == FALSE) {
1700  return FALSE;
1701  }
1702 
1703  for (int lpc = 0; lpc < DIMOF(attr_list); lpc++) {
1704  name = attr_list[lpc];
1705  value = crm_element_value(rsc->xml, attr_list[lpc]);
1706  if (safe_str_eq(value, value_list[lpc]) == FALSE) {
1707  return FALSE;
1708  }
1709  }
1710 
1711  return TRUE;
1712 }
1713 
1715 rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
1716  pe_working_set_t * data_set)
1717 {
1718  op_digest_cache_t *data = NULL;
1719 
1720  GHashTable *local_rsc_params = NULL;
1721 #ifdef ENABLE_VERSIONED_ATTRS
1722  xmlNode *local_versioned_params = NULL;
1723 #endif
1724 
1725  action_t *action = NULL;
1726  char *key = NULL;
1727 
1728  int interval = 0;
1729  const char *op_id = ID(xml_op);
1730  const char *interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
1731  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1732  const char *digest_all;
1733  const char *digest_restart;
1734  const char *secure_list;
1735  const char *restart_list;
1736  const char *op_version;
1737 
1738  CRM_ASSERT(node != NULL);
1739 
1740  data = g_hash_table_lookup(node->details->digest_cache, op_id);
1741  if (data) {
1742  return data;
1743  }
1744 
1745  data = calloc(1, sizeof(op_digest_cache_t));
1746  CRM_ASSERT(data != NULL);
1747 
1748  digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
1749  digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
1750 
1751  secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
1752  restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
1753 
1754  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1755 
1756  /* key is freed in custom_action */
1757  interval = crm_parse_int(interval_s, "0");
1758  key = generate_op_key(rsc->id, task, interval);
1759  action = custom_action(rsc, key, task, node, TRUE, FALSE, data_set);
1760  key = NULL;
1761 
1762  local_rsc_params = g_hash_table_new_full(crm_str_hash, g_str_equal,
1764  get_rsc_attributes(local_rsc_params, rsc, node, data_set);
1765 #ifdef ENABLE_VERSIONED_ATTRS
1766  local_versioned_params = create_xml_node(NULL, XML_TAG_VER_ATTRS);
1767  pe_get_versioned_attributes(local_versioned_params, rsc, node, data_set);
1768 #endif
1769  data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
1770 
1771  if (fix_remote_addr(rsc)) {
1772  // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
1773  crm_xml_add(data->params_all, "addr", node->details->uname);
1774  crm_trace("Fixing addr for %s on %s", rsc->id, node->details->uname);
1775  }
1776 
1777  g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
1778  g_hash_table_foreach(action->extra, hash2field, data->params_all);
1779  g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
1780  g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
1781  filter_action_parameters(data->params_all, op_version);
1782 #ifdef ENABLE_VERSIONED_ATTRS
1783  crm_summarize_versioned_params(data->params_all, rsc->versioned_parameters);
1784  crm_summarize_versioned_params(data->params_all, local_versioned_params);
1785 #endif
1786 
1787  data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
1788 
1789  if (secure_list && is_set(data_set->flags, pe_flag_sanitized)) {
1790  data->params_secure = copy_xml(data->params_all);
1791 
1792  if (secure_list) {
1793  filter_parameters(data->params_secure, secure_list, FALSE);
1794  }
1795  data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
1796  }
1797 
1798  if (digest_restart) {
1799  data->params_restart = copy_xml(data->params_all);
1800 
1801  if (restart_list) {
1802  filter_parameters(data->params_restart, restart_list, TRUE);
1803  }
1805  }
1806 
1807  data->rc = RSC_DIGEST_MATCH;
1808  if (digest_restart && strcmp(data->digest_restart_calc, digest_restart) != 0) {
1809  data->rc = RSC_DIGEST_RESTART;
1810 
1811  } else if (digest_all == NULL) {
1812  /* it is unknown what the previous op digest was */
1813  data->rc = RSC_DIGEST_UNKNOWN;
1814 
1815  } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
1816  data->rc = RSC_DIGEST_ALL;
1817  }
1818 
1819  g_hash_table_insert(node->details->digest_cache, strdup(op_id), data);
1820  g_hash_table_destroy(local_rsc_params);
1821 #ifdef ENABLE_VERSIONED_ATTRS
1822  free_xml(local_versioned_params);
1823 #endif
1824  pe_free_action(action);
1825 
1826  return data;
1827 }
1828 
1829 const char *rsc_printable_id(resource_t *rsc)
1830 {
1831  if (is_not_set(rsc->flags, pe_rsc_unique)) {
1832  return ID(rsc->xml);
1833  }
1834  return rsc->id;
1835 }
1836 
1837 void
1838 clear_bit_recursive(resource_t * rsc, unsigned long long flag)
1839 {
1840  GListPtr gIter = rsc->children;
1841 
1842  clear_bit(rsc->flags, flag);
1843  for (; gIter != NULL; gIter = gIter->next) {
1844  resource_t *child_rsc = (resource_t *) gIter->data;
1845 
1846  clear_bit_recursive(child_rsc, flag);
1847  }
1848 }
1849 
1850 void
1851 set_bit_recursive(resource_t * rsc, unsigned long long flag)
1852 {
1853  GListPtr gIter = rsc->children;
1854 
1855  set_bit(rsc->flags, flag);
1856  for (; gIter != NULL; gIter = gIter->next) {
1857  resource_t *child_rsc = (resource_t *) gIter->data;
1858 
1859  set_bit_recursive(child_rsc, flag);
1860  }
1861 }
1862 
1863 action_t *
1864 pe_fence_op(node_t * node, const char *op, bool optional, pe_working_set_t * data_set)
1865 {
1866  char *key = NULL;
1867  action_t *stonith_op = NULL;
1868 
1869  if(op == NULL) {
1870  op = data_set->stonith_action;
1871  }
1872 
1873  key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
1874 
1875  if(data_set->singletons) {
1876  stonith_op = g_hash_table_lookup(data_set->singletons, key);
1877  }
1878 
1879  if(stonith_op == NULL) {
1880  stonith_op = custom_action(NULL, key, CRM_OP_FENCE, node, optional, TRUE, data_set);
1881 
1882  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1883  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
1884  add_hash_param(stonith_op->meta, "stonith_action", op);
1885  } else {
1886  free(key);
1887  }
1888 
1889  if(optional == FALSE) {
1890  crm_trace("%s is no longer optional", stonith_op->uuid);
1892  }
1893 
1894  return stonith_op;
1895 }
1896 
1897 void
1899  resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set)
1900 {
1901  if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
1902  /* No resources require it */
1903  return;
1904 
1905  } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
1906  /* Wasn't a stonith device */
1907  return;
1908 
1909  } else if(node
1910  && node->details->online
1911  && node->details->unclean == FALSE
1912  && node->details->shutdown == FALSE) {
1913  action_t *unfence = pe_fence_op(node, "on", FALSE, data_set);
1914 
1915  crm_notice("Unfencing %s: %s", node->details->uname, reason);
1916  if(dependency) {
1917  order_actions(unfence, dependency, pe_order_optional);
1918  }
1919 
1920  } else if(rsc) {
1921  GHashTableIter iter;
1922 
1923  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1924  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1925  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
1926  trigger_unfencing(rsc, node, reason, dependency, data_set);
1927  }
1928  }
1929  }
1930 }
1931 
1932 gboolean
1933 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
1934 {
1935  tag_t *tag = NULL;
1936  GListPtr gIter = NULL;
1937  gboolean is_existing = FALSE;
1938 
1939  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
1940 
1941  tag = g_hash_table_lookup(tags, tag_name);
1942  if (tag == NULL) {
1943  tag = calloc(1, sizeof(tag_t));
1944  if (tag == NULL) {
1945  return FALSE;
1946  }
1947  tag->id = strdup(tag_name);
1948  tag->refs = NULL;
1949  g_hash_table_insert(tags, strdup(tag_name), tag);
1950  }
1951 
1952  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
1953  const char *existing_ref = (const char *) gIter->data;
1954 
1955  if (crm_str_eq(existing_ref, obj_ref, TRUE)){
1956  is_existing = TRUE;
1957  break;
1958  }
1959  }
1960 
1961  if (is_existing == FALSE) {
1962  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
1963  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
1964  }
1965 
1966  return TRUE;
1967 }
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:234
#define LOG_TRACE
Definition: logging.h:29
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
GListPtr nodes
Definition: status.h:102
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:292
const char * uname
Definition: status.h:134
enum rsc_start_requirement needs
Definition: status.h:331
enum pe_ordering type
Definition: status.h:429
A dumping ground.
long long crm_get_msec(const char *input)
Definition: utils.c:586
#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:371
void destroy_ticket(gpointer data)
Definition: utils.c:1588
#define crm_notice(fmt, args...)
Definition: logging.h:250
#define CRMD_ACTION_MIGRATED
Definition: crm.h:160
xmlNode * xml
Definition: status.h:254
enum action_tasks get_complex_task(resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1162
#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:1175
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:214
GHashTable * utilization
Definition: status.h:294
#define CRM_OP_FENCE
Definition: crm.h:114
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:1468
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:372
GHashTable * node_hash_from_list(GListPtr list)
Definition: utils.c:135
int crm_element_value_const_int(const xmlNode *data, const char *name, int *dest)
Definition: xml.c:3881
#define crm_time_log_timeofday
Definition: iso8601.h:71
#define pe_flag_enable_unfencing
Definition: status.h:65
const char * id
Definition: status.h:133
pe_working_set_t * pe_dataset
Definition: utils.c:29
void node_list_exclude(GHashTable *hash, GListPtr list, gboolean merge_scores)
Definition: utils.c:100
int weight
Definition: status.h:170
#define XML_ATTR_TYPE
Definition: msg_xml.h:104
int sort_index
Definition: status.h:269
struct crm_time_s crm_time_t
Definition: iso8601.h:37
time_t last_granted
Definition: status.h:372
bool pe_can_fence(pe_working_set_t *data_set, node_t *node)
Definition: utils.c:52
#define crm_config_err(fmt...)
Definition: crm_internal.h:258
#define pe_rsc_stopping
Definition: status.h:204
xmlNode * op_defaults
Definition: status.h:111
#define pe_rsc_needs_quorum
Definition: status.h:212
enum action_fail_response on_fail
Definition: status.h:332
#define pe_rsc_orphan
Definition: status.h:179
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1353
xmlNode * find_rsc_op_entry(resource_t *rsc, const char *key)
Definition: utils.c:1041
char * cancel_task
Definition: status.h:328
GListPtr running_rsc
Definition: status.h:148
enum pe_obj_types variant
Definition: status.h:260
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:271
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:285
gboolean pending
Definition: status.h:140
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:95
#define CRMD_ACTION_PROMOTE
Definition: crm.h:168
#define XML_LRM_ATTR_OP_RESTART
Definition: msg_xml.h:286
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:172
gboolean fixed
Definition: status.h:171
enum action_tasks text2task(const char *task)
Definition: common.c:230
no_quorum_policy_t no_quorum_policy
Definition: status.h:96
GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node)
Definition: utils.c:1256
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:187
void dump_node_capacity(int level, const char *comment, node_t *node)
Definition: utils.c:274
char * clone_name
Definition: status.h:253
action_t * find_first_action(GListPtr input, const char *uuid, const char *task, node_t *on_node)
Definition: utils.c:1186
xmlNode * params_restart
Definition: internal.h:267
xmlNode * op_entry
Definition: status.h:324
#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:841
int id
Definition: status.h:319
#define clear_bit(word, bit)
Definition: crm_internal.h:193
void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1309
#define RSC_START
Definition: crm.h:185
GHashTable * tickets
Definition: status.h:99
enum rsc_role_e role
Definition: status.h:289
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:230
node_t * node_copy(const node_t *this_node)
Definition: utils.c:79
GListPtr children
Definition: status.h:296
gboolean get_target_role(resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:1483
void print_resource(int log_level, const char *pre_text, resource_t *rsc, gboolean details)
Definition: utils.c:1091
GListPtr actions_before
Definition: status.h:365
#define crm_time_log_duration
Definition: iso8601.h:73
gboolean order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1519
#define XML_LRM_ATTR_OP_SECURE
Definition: msg_xml.h:287
gboolean is_rsc_baremetal_remote_node(resource_t *rsc, pe_working_set_t *data_set)
Definition: remote.c:25
GHashTable * extra
Definition: status.h:343
char * id
Definition: status.h:252
GHashTable * parameters
Definition: status.h:293
#define CRMD_ACTION_START
Definition: crm.h:162
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2711
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:177
GHashTable * utilization
Definition: status.h:156
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:272
const char * role2text(enum rsc_role_e role)
Definition: common.c:343
void hash2field(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4884
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:1933
#define CRMD_ACTION_STOP
Definition: crm.h:165
#define pe_rsc_starting
Definition: status.h:203
#define pe_warn(fmt...)
Definition: internal.h:28
struct node_shared_s * details
Definition: status.h:173
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:170
#define set_bit(word, bit)
Definition: crm_internal.h:192
gboolean unclean
Definition: status.h:141
#define crm_debug(fmt, args...)
Definition: logging.h:253
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:101
GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node)
Definition: utils.c:1128
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:1071
ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:1600
resource_object_functions_t * fns
Definition: status.h:261
char * task
Definition: status.h:326
#define sort_return(an_int, why)
Definition: utils.c:1343
void pe_free_action(action_t *action)
Definition: utils.c:1107
resource_t * container
Definition: status.h:302
GHashTable * allowed_nodes
Definition: status.h:287
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:561
GHashTable * digest_cache
Definition: status.h:159
#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:1851
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:295
GHashTable * meta
Definition: status.h:342
gboolean is_container_remote_node(node_t *node)
Definition: remote.c:53
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:177
GListPtr refs
Definition: status.h:379
bool fix_remote_addr(resource_t *rsc)
Definition: utils.c:1678
const char * stonith_action
Definition: status.h:89
const char * crm_element_value_const(const xmlNode *data, const char *name)
Definition: xml.c:3887
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:244
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:74
#define XML_TAG_META_SETS
Definition: msg_xml.h:178
GListPtr actions
Definition: status.h:109
Wrappers for and extensions to libxml2.
GHashTable * config_hash
Definition: status.h:98
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2587
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:5134
unsigned long long flags
Definition: status.h:276
#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:211
char * uuid
Definition: status.h:327
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:288
void unpack_operation(action_t *action, xmlNode *xml_obj, resource_t *container, pe_working_set_t *data_set)
Definition: utils.c:670
void free_xml(xmlNode *child)
Definition: xml.c:2705
#define crm_time_log_with_timezone
Definition: iso8601.h:72
enum rsc_role_e text2role(const char *role)
Definition: common.c:363
xmlNode * input
Definition: status.h:83
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: utils.c:898
xmlNode * params_all
Definition: internal.h:265
int remote_reconnect_interval
Definition: status.h:309
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: utils.c:789
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:275
node_t * node
Definition: status.h:323
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:4900
action_t * action
Definition: status.h:431
GListPtr actions
Definition: status.h:281
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2489
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:186
pe_ordering
Definition: status.h:389
void(* print)(resource_t *, const char *, long, void *)
Definition: complex.h:47
#define pe_rsc_unique
Definition: status.h:185
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:317
GHashTable * meta
Definition: status.h:292
void trigger_unfencing(resource_t *rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t *data_set)
Definition: utils.c:1898
const char * rsc_printable_id(resource_t *rsc)
Definition: utils.c:1829
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:419
#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:1216
#define crm_err(fmt, args...)
Definition: logging.h:248
#define RSC_STATUS
Definition: crm.h:199
#define RSC_PROMOTE
Definition: crm.h:191
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:99
GHashTable * attrs
Definition: status.h:153
#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:1715
enum rsc_role_e next_role
Definition: status.h:290
gboolean online
Definition: status.h:137
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3905
gboolean shutdown
Definition: status.h:143
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1083
GListPtr actions_after
Definition: status.h:366
xmlNode * params_secure
Definition: internal.h:266
#define DIMOF(a)
Definition: crm.h:39
int merge_weights(int w1, int w2)
Definition: common.c:382
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:284
#define pe_rsc_managed
Definition: status.h:180
#define CRMD_ACTION_MIGRATE
Definition: crm.h:159
enum rsc_role_e fail_role
Definition: status.h:333
gboolean remote_requires_reset
Definition: status.h:163
char * id
Definition: status.h:378
#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:1148
node_t * allocated_to
Definition: status.h:284
rsc_role_e
Definition: common.h:81
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Generate an operation key.
Definition: utils.c:652
node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:282
enum pe_action_flags flags
Definition: status.h:330
gboolean standby
Definition: status.h:373
Definition: status.h:377
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:231
#define pe_flag_have_quorum
Definition: status.h:58
int rsc_discover_mode
Definition: status.h:174
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:950
action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1571
gboolean granted
Definition: status.h:371
Definition: status.h:169
gboolean crm_is_true(const char *s)
Definition: strings.c:165
action_t * pe_fence_op(node_t *node, const char *op, bool optional, pe_working_set_t *data_set)
Definition: utils.c:1864
resource_t * rsc
Definition: status.h:322
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:274
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:25
GHashTable * singletons
Definition: status.h:100
#define ID(x)
Definition: msg_xml.h:434
unsigned long long flags
Definition: status.h:92
#define pe_err(fmt...)
Definition: internal.h:27
xmlNode * ops_xml
Definition: status.h:256
char * crm_itoa(int an_int)
Definition: strings.c:60
#define pe_rsc_needs_fencing
Definition: status.h:213
#define safe_str_eq(a, b)
Definition: util.h:64
char * id
Definition: status.h:370
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_str_hash
Definition: crm.h:208
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
Definition: utils.c:344
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1047
#define pe_flag_sanitized
Definition: status.h:80
#define pe_rsc_fence_device
Definition: status.h:186
GList * GListPtr
Definition: crm.h:202
#define CRMD_ACTION_CANCEL
Definition: crm.h:156
crm_time_t * now
Definition: status.h:84
#define XML_TAG_PARAMS
Definition: msg_xml.h:183
#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:151
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:271
#define crm_time_log_date
Definition: iso8601.h:70
GHashTable * state
Definition: status.h:374
#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:1838
int priority
Definition: status.h:267
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:243
#define CRMD_ACTION_STATUS
Definition: crm.h:176
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:116