pacemaker  1.1.18-7fdfbbe
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (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);
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  pe_action_set_reason(action, NULL, TRUE);
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 if(is_not_set(action->flags, pe_action_runnable)) {
603  pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
604  //pe_action_set_reason(action, NULL, TRUE);
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 int
845 pe_get_configured_timeout(resource_t *rsc, const char *action, pe_working_set_t *data_set)
846 {
847  xmlNode *child = NULL;
848  const char *timeout = NULL;
849  int timeout_ms = 0;
850 
851  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
852  child != NULL; child = crm_next_same_xml(child)) {
853  if (safe_str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME))) {
854  timeout = crm_element_value(child, XML_ATTR_TIMEOUT);
855  break;
856  }
857  }
858 
859  if (timeout == NULL && data_set->op_defaults) {
860  GHashTable *action_meta = crm_str_table_new();
862  NULL, action_meta, NULL, FALSE, data_set->now);
863  timeout = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
864  }
865 
866  if (timeout == NULL && data_set->config_hash) {
867  timeout = pe_pref(data_set->config_hash, "default-action-timeout");
868  }
869 
870  if (timeout == NULL) {
871  timeout = CRM_DEFAULT_OP_TIMEOUT_S;
872  }
873 
874  timeout_ms = crm_get_msec(timeout);
875  if (timeout_ms < 0) {
876  timeout_ms = 0;
877  }
878 
879  return timeout_ms;
880 }
881 
882 #if ENABLE_VERSIONED_ATTRS
883 static void
884 unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj, unsigned long long interval, crm_time_t *now)
885 {
886  xmlNode *attrs = NULL;
887  xmlNode *attr = NULL;
888 
889  for (attrs = __xml_first_child(versioned_meta); attrs != NULL; attrs = __xml_next_element(attrs)) {
890  for (attr = __xml_first_child(attrs); attr != NULL; attr = __xml_next_element(attr)) {
891  const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
892  const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
893 
895  int start_delay = unpack_start_delay(value, NULL);
896 
897  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
898  } else if (safe_str_eq(name, XML_OP_ATTR_ORIGIN)) {
899  int start_delay = unpack_interval_origin(value, NULL, xml_obj, interval, now);
900 
902  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
903  } else if (safe_str_eq(name, XML_ATTR_TIMEOUT)) {
904  int timeout = unpack_timeout(value, NULL, NULL, 0, NULL);
905 
906  crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout);
907  }
908  }
909  }
910 }
911 #endif
912 
913 void
914 unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
915  pe_working_set_t * data_set)
916 {
917  unsigned long long interval = 0;
918  int timeout = 0;
919  char *value_ms = NULL;
920  const char *value = NULL;
921  const char *field = NULL;
922 #if ENABLE_VERSIONED_ATTRS
923  pe_rsc_action_details_t *rsc_details = NULL;
924 #endif
925 
926  CRM_CHECK(action->rsc != NULL, return);
927 
929  action->meta, NULL, FALSE, data_set->now);
930 
931  if (xml_obj) {
932  xmlAttrPtr xIter = NULL;
933 
934  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
935  const char *prop_name = (const char *)xIter->name;
936  const char *prop_value = crm_element_value(xml_obj, prop_name);
937 
938  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
939  }
940  }
941 
943  NULL, action->meta, NULL, FALSE, data_set->now);
944 
946  NULL, action->meta, NULL, FALSE, data_set->now);
947 
948 #if ENABLE_VERSIONED_ATTRS
949  rsc_details = pe_rsc_action_details(action);
950  pe_unpack_versioned_attributes(data_set->input, xml_obj, XML_TAG_ATTR_SETS, NULL,
951  rsc_details->versioned_parameters, data_set->now);
952  pe_unpack_versioned_attributes(data_set->input, xml_obj, XML_TAG_META_SETS, NULL,
953  rsc_details->versioned_meta, data_set->now);
954 #endif
955 
956  g_hash_table_remove(action->meta, "id");
957 
958  field = XML_LRM_ATTR_INTERVAL;
959  value = g_hash_table_lookup(action->meta, field);
960  if (value != NULL) {
961  interval = crm_get_interval(value);
962  if (interval > 0) {
963  value_ms = crm_itoa(interval);
964  g_hash_table_replace(action->meta, strdup(field), value_ms);
965 
966  } else {
967  g_hash_table_remove(action->meta, field);
968  }
969  }
970 
971  /* @COMPAT data sets < 1.1.10 ("requires" on start action not resource) */
972  value = g_hash_table_lookup(action->meta, "requires");
973  if (value) {
974  pe_warn_once(pe_wo_requires, "Support for 'requires' operation meta-attribute"
975  " is deprecated and will be removed in a future version"
976  " (use 'requires' resource meta-attribute instead)");
977  }
978 
979  if (safe_str_neq(action->task, RSC_START)
980  && safe_str_neq(action->task, RSC_PROMOTE)) {
981  action->needs = rsc_req_nothing;
982  value = "nothing (not start/promote)";
983 
984  } else if (safe_str_eq(value, "nothing")) {
985  action->needs = rsc_req_nothing;
986 
987  } else if (safe_str_eq(value, "quorum")) {
988  action->needs = rsc_req_quorum;
989 
990  } else if (safe_str_eq(value, "unfencing")) {
991  action->needs = rsc_req_stonith;
993  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
994  crm_notice("%s requires unfencing but fencing is disabled", action->rsc->id);
995  }
996 
997  } else if (is_set(data_set->flags, pe_flag_stonith_enabled)
998  && safe_str_eq(value, "fencing")) {
999  action->needs = rsc_req_stonith;
1000  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
1001  crm_notice("%s requires fencing but fencing is disabled", action->rsc->id);
1002  }
1003  /* @COMPAT end compatibility code */
1004 
1005  } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1006  action->needs = rsc_req_stonith;
1007  value = "fencing (resource)";
1008 
1009  } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1010  action->needs = rsc_req_quorum;
1011  value = "quorum (resource)";
1012 
1013  } else {
1014  action->needs = rsc_req_nothing;
1015  value = "nothing (resource)";
1016  }
1017 
1018  pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->task, value);
1019 
1020  value = unpack_operation_on_fail(action);
1021 
1022  if (value == NULL) {
1023 
1024  } else if (safe_str_eq(value, "block")) {
1025  action->on_fail = action_fail_block;
1026  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1027 
1028  } else if (safe_str_eq(value, "fence")) {
1029  action->on_fail = action_fail_fence;
1030  value = "node fencing";
1031 
1032  if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
1033  crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense");
1034  action->on_fail = action_fail_stop;
1035  action->fail_role = RSC_ROLE_STOPPED;
1036  value = "stop resource";
1037  }
1038 
1039  } else if (safe_str_eq(value, "standby")) {
1040  action->on_fail = action_fail_standby;
1041  value = "node standby";
1042 
1043  } else if (safe_str_eq(value, "ignore")
1044  || safe_str_eq(value, "nothing")) {
1045  action->on_fail = action_fail_ignore;
1046  value = "ignore";
1047 
1048  } else if (safe_str_eq(value, "migrate")) {
1049  action->on_fail = action_fail_migrate;
1050  value = "force migration";
1051 
1052  } else if (safe_str_eq(value, "stop")) {
1053  action->on_fail = action_fail_stop;
1054  action->fail_role = RSC_ROLE_STOPPED;
1055  value = "stop resource";
1056 
1057  } else if (safe_str_eq(value, "restart")) {
1058  action->on_fail = action_fail_recover;
1059  value = "restart (and possibly migrate)";
1060 
1061  } else if (safe_str_eq(value, "restart-container")) {
1062  if (container) {
1064  value = "restart container (and possibly migrate)";
1065 
1066  } else {
1067  value = NULL;
1068  }
1069 
1070  } else {
1071  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1072  value = NULL;
1073  }
1074 
1075  /* defaults */
1076  if (value == NULL && container) {
1078  value = "restart container (and possibly migrate) (default)";
1079 
1080  /* for baremetal remote nodes, ensure that any failure that results in
1081  * dropping an active connection to a remote node results in fencing of
1082  * the remote node.
1083  *
1084  * There are only two action failures that don't result in fencing.
1085  * 1. probes - probe failures are expected.
1086  * 2. start - a start failure indicates that an active connection does not already
1087  * exist. The user can set op on-fail=fence if they really want to fence start
1088  * failures. */
1089  } else if (((value == NULL) || !is_set(action->rsc->flags, pe_rsc_managed)) &&
1090  (is_rsc_baremetal_remote_node(action->rsc, data_set) &&
1091  !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && interval == 0) &&
1092  (safe_str_neq(action->task, CRMD_ACTION_START)))) {
1093 
1094  if (!is_set(action->rsc->flags, pe_rsc_managed)) {
1095  action->on_fail = action_fail_stop;
1096  action->fail_role = RSC_ROLE_STOPPED;
1097  value = "stop unmanaged baremetal remote node (enforcing default)";
1098 
1099  } else {
1100  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1101  value = "fence baremetal remote node (default)";
1102  } else {
1103  value = "recover baremetal remote node connection (default)";
1104  }
1105 
1106  if (action->rsc->remote_reconnect_interval) {
1107  action->fail_role = RSC_ROLE_STOPPED;
1108  }
1110  }
1111 
1112  } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
1113  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1114  action->on_fail = action_fail_fence;
1115  value = "resource fence (default)";
1116 
1117  } else {
1118  action->on_fail = action_fail_block;
1119  value = "resource block (default)";
1120  }
1121 
1122  } else if (value == NULL) {
1123  action->on_fail = action_fail_recover;
1124  value = "restart (and possibly migrate) (default)";
1125  }
1126 
1127  pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
1128 
1129  value = NULL;
1130  if (xml_obj != NULL) {
1131  value = g_hash_table_lookup(action->meta, "role_after_failure");
1132  }
1133  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1134  action->fail_role = text2role(value);
1135  }
1136  /* defaults */
1137  if (action->fail_role == RSC_ROLE_UNKNOWN) {
1138  if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
1139  action->fail_role = RSC_ROLE_SLAVE;
1140  } else {
1141  action->fail_role = RSC_ROLE_STARTED;
1142  }
1143  }
1144  pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
1145  role2text(action->fail_role));
1146 
1147  field = XML_OP_ATTR_START_DELAY;
1148  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1149  if (value) {
1150  unpack_start_delay(value, action->meta);
1151  } else {
1152  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1153  unpack_interval_origin(value, action->meta, xml_obj, interval, data_set->now);
1154  }
1155 
1156  field = XML_ATTR_TIMEOUT;
1157  value = g_hash_table_lookup(action->meta, field);
1158  timeout = unpack_timeout(value, action, xml_obj, interval, data_set->config_hash);
1159  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT), crm_itoa(timeout));
1160 
1161 #if ENABLE_VERSIONED_ATTRS
1162  unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval,
1163  data_set->now);
1164 #endif
1165 }
1166 
1167 static xmlNode *
1168 find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_disabled)
1169 {
1170  unsigned long long number = 0;
1171  gboolean do_retry = TRUE;
1172  char *local_key = NULL;
1173  const char *name = NULL;
1174  const char *value = NULL;
1175  const char *interval = NULL;
1176  char *match_key = NULL;
1177  xmlNode *op = NULL;
1178  xmlNode *operation = NULL;
1179 
1180  retry:
1181  for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
1182  operation = __xml_next_element(operation)) {
1183  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
1184  name = crm_element_value(operation, "name");
1185  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1186  value = crm_element_value(operation, "enabled");
1187  if (!include_disabled && value && crm_is_true(value) == FALSE) {
1188  continue;
1189  }
1190 
1191  number = crm_get_interval(interval);
1192  match_key = generate_op_key(rsc->id, name, number);
1193  if (safe_str_eq(key, match_key)) {
1194  op = operation;
1195  }
1196  free(match_key);
1197 
1198  if (rsc->clone_name) {
1199  match_key = generate_op_key(rsc->clone_name, name, number);
1200  if (safe_str_eq(key, match_key)) {
1201  op = operation;
1202  }
1203  free(match_key);
1204  }
1205 
1206  if (op != NULL) {
1207  free(local_key);
1208  return op;
1209  }
1210  }
1211  }
1212 
1213  free(local_key);
1214  if (do_retry == FALSE) {
1215  return NULL;
1216  }
1217 
1218  do_retry = FALSE;
1219  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1220  local_key = generate_op_key(rsc->id, "migrate", 0);
1221  key = local_key;
1222  goto retry;
1223 
1224  } else if (strstr(key, "_notify_")) {
1225  local_key = generate_op_key(rsc->id, "notify", 0);
1226  key = local_key;
1227  goto retry;
1228  }
1229 
1230  return NULL;
1231 }
1232 
1233 xmlNode *
1234 find_rsc_op_entry(resource_t * rsc, const char *key)
1235 {
1236  return find_rsc_op_entry_helper(rsc, key, FALSE);
1237 }
1238 
1239 void
1240 print_node(const char *pre_text, node_t * node, gboolean details)
1241 {
1242  if (node == NULL) {
1243  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1244  return;
1245  }
1246 
1247  CRM_ASSERT(node->details);
1248  crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1249  pre_text == NULL ? "" : pre_text,
1250  pre_text == NULL ? "" : ": ",
1251  node->details->online ? "" : "Unavailable/Unclean ",
1252  node->details->uname, node->weight, node->fixed ? "True" : "False");
1253 
1254  if (details) {
1255  char *pe_mutable = strdup("\t\t");
1256  GListPtr gIter = node->details->running_rsc;
1257 
1258  crm_trace("\t\t===Node Attributes");
1259  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1260  free(pe_mutable);
1261 
1262  crm_trace("\t\t=== Resources");
1263 
1264  for (; gIter != NULL; gIter = gIter->next) {
1265  resource_t *rsc = (resource_t *) gIter->data;
1266 
1267  print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE);
1268  }
1269  }
1270 }
1271 
1272 /*
1273  * Used by the HashTable for-loop
1274  */
1275 void
1276 print_str_str(gpointer key, gpointer value, gpointer user_data)
1277 {
1278  crm_trace("%s%s %s ==> %s",
1279  user_data == NULL ? "" : (char *)user_data,
1280  user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1281 }
1282 
1283 void
1284 print_resource(int log_level, const char *pre_text, resource_t * rsc, gboolean details)
1285 {
1286  long options = pe_print_log | pe_print_pending;
1287 
1288  if (rsc == NULL) {
1289  do_crm_log(log_level - 1, "%s%s: <NULL>",
1290  pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1291  return;
1292  }
1293  if (details) {
1294  options |= pe_print_details;
1295  }
1296  rsc->fns->print(rsc, pre_text, options, &log_level);
1297 }
1298 
1299 void
1301 {
1302  if (action == NULL) {
1303  return;
1304  }
1305  g_list_free_full(action->actions_before, free); /* action_wrapper_t* */
1306  g_list_free_full(action->actions_after, free); /* action_wrapper_t* */
1307  if (action->extra) {
1308  g_hash_table_destroy(action->extra);
1309  }
1310  if (action->meta) {
1311  g_hash_table_destroy(action->meta);
1312  }
1313 #if ENABLE_VERSIONED_ATTRS
1314  if (action->rsc) {
1315  pe_free_rsc_action_details(action);
1316  }
1317 #endif
1318  free(action->cancel_task);
1319  free(action->reason);
1320  free(action->task);
1321  free(action->uuid);
1322  free(action->node);
1323  free(action);
1324 }
1325 
1326 GListPtr
1328 {
1329  const char *value = NULL;
1330  GListPtr result = NULL;
1331  GListPtr gIter = input;
1332 
1333  CRM_CHECK(input != NULL, return NULL);
1334 
1335  for (; gIter != NULL; gIter = gIter->next) {
1336  action_t *action = (action_t *) gIter->data;
1337 
1338  value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
1339  if (value == NULL) {
1340  /* skip */
1341  } else if (safe_str_eq(value, "0")) {
1342  /* skip */
1343  } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1344  /* skip */
1345  } else if (not_on_node == NULL) {
1346  crm_trace("(null) Found: %s", action->uuid);
1347  result = g_list_prepend(result, action);
1348 
1349  } else if (action->node == NULL) {
1350  /* skip */
1351  } else if (action->node->details != not_on_node->details) {
1352  crm_trace("Found: %s", action->uuid);
1353  result = g_list_prepend(result, action);
1354  }
1355  }
1356 
1357  return result;
1358 }
1359 
1360 enum action_tasks
1361 get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic)
1362 {
1363  enum action_tasks task = text2task(name);
1364 
1365  if (rsc == NULL) {
1366  return task;
1367 
1368  } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1369  switch (task) {
1370  case stopped_rsc:
1371  case started_rsc:
1372  case action_demoted:
1373  case action_promoted:
1374  crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1375  return task - 1;
1376  break;
1377  default:
1378  break;
1379  }
1380  }
1381  return task;
1382 }
1383 
1384 action_t *
1385 find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node)
1386 {
1387  GListPtr gIter = NULL;
1388 
1389  CRM_CHECK(uuid || task, return NULL);
1390 
1391  for (gIter = input; gIter != NULL; gIter = gIter->next) {
1392  action_t *action = (action_t *) gIter->data;
1393 
1394  if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1395  continue;
1396 
1397  } else if (task != NULL && safe_str_neq(task, action->task)) {
1398  continue;
1399 
1400  } else if (on_node == NULL) {
1401  return action;
1402 
1403  } else if (action->node == NULL) {
1404  continue;
1405 
1406  } else if (on_node->details == action->node->details) {
1407  return action;
1408  }
1409  }
1410 
1411  return NULL;
1412 }
1413 
1414 GListPtr
1415 find_actions(GListPtr input, const char *key, const node_t *on_node)
1416 {
1417  GListPtr gIter = input;
1418  GListPtr result = NULL;
1419 
1420  CRM_CHECK(key != NULL, return NULL);
1421 
1422  for (; gIter != NULL; gIter = gIter->next) {
1423  action_t *action = (action_t *) gIter->data;
1424 
1425  if (safe_str_neq(key, action->uuid)) {
1426  crm_trace("%s does not match action %s", key, action->uuid);
1427  continue;
1428 
1429  } else if (on_node == NULL) {
1430  crm_trace("Action %s matches (ignoring node)", key);
1431  result = g_list_prepend(result, action);
1432 
1433  } else if (action->node == NULL) {
1434  crm_trace("Action %s matches (unallocated, assigning to %s)",
1435  key, on_node->details->uname);
1436 
1437  action->node = node_copy(on_node);
1438  result = g_list_prepend(result, action);
1439 
1440  } else if (on_node->details == action->node->details) {
1441  crm_trace("Action %s on %s matches", key, on_node->details->uname);
1442  result = g_list_prepend(result, action);
1443 
1444  } else {
1445  crm_trace("Action %s on node %s does not match requested node %s",
1446  key, action->node->details->uname,
1447  on_node->details->uname);
1448  }
1449  }
1450 
1451  return result;
1452 }
1453 
1454 GListPtr
1455 find_actions_exact(GListPtr input, const char *key, node_t * on_node)
1456 {
1457  GListPtr gIter = input;
1458  GListPtr result = NULL;
1459 
1460  CRM_CHECK(key != NULL, return NULL);
1461 
1462  for (; gIter != NULL; gIter = gIter->next) {
1463  action_t *action = (action_t *) gIter->data;
1464 
1465  crm_trace("Matching %s against %s", key, action->uuid);
1466  if (safe_str_neq(key, action->uuid)) {
1467  crm_trace("Key mismatch: %s vs. %s", key, action->uuid);
1468  continue;
1469 
1470  } else if (on_node == NULL || action->node == NULL) {
1471  crm_trace("on_node=%p, action->node=%p", on_node, action->node);
1472  continue;
1473 
1474  } else if (safe_str_eq(on_node->details->id, action->node->details->id)) {
1475  result = g_list_prepend(result, action);
1476  }
1477  crm_trace("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id);
1478  }
1479 
1480  return result;
1481 }
1482 
1483 static void
1484 resource_node_score(resource_t * rsc, node_t * node, int score, const char *tag)
1485 {
1486  node_t *match = NULL;
1487 
1488  if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
1489  && safe_str_eq(tag, "symmetric_default")) {
1490  /* This string comparision may be fragile, but exclusive resources and
1491  * exclusive nodes should not have the symmetric_default constraint
1492  * applied to them.
1493  */
1494  return;
1495 
1496  } else if (rsc->children) {
1497  GListPtr gIter = rsc->children;
1498 
1499  for (; gIter != NULL; gIter = gIter->next) {
1500  resource_t *child_rsc = (resource_t *) gIter->data;
1501 
1502  resource_node_score(child_rsc, node, score, tag);
1503  }
1504  }
1505 
1506  pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1507  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1508  if (match == NULL) {
1509  match = node_copy(node);
1510  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1511  }
1512  match->weight = merge_weights(match->weight, score);
1513 }
1514 
1515 void
1516 resource_location(resource_t * rsc, node_t * node, int score, const char *tag,
1517  pe_working_set_t * data_set)
1518 {
1519  if (node != NULL) {
1520  resource_node_score(rsc, node, score, tag);
1521 
1522  } else if (data_set != NULL) {
1523  GListPtr gIter = data_set->nodes;
1524 
1525  for (; gIter != NULL; gIter = gIter->next) {
1526  node_t *node_iter = (node_t *) gIter->data;
1527 
1528  resource_node_score(rsc, node_iter, score, tag);
1529  }
1530 
1531  } else {
1532  GHashTableIter iter;
1533  node_t *node_iter = NULL;
1534 
1535  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1536  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1537  resource_node_score(rsc, node_iter, score, tag);
1538  }
1539  }
1540 
1541  if (node == NULL && score == -INFINITY) {
1542  if (rsc->allocated_to) {
1543  crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1544  free(rsc->allocated_to);
1545  rsc->allocated_to = NULL;
1546  }
1547  }
1548 }
1549 
1550 #define sort_return(an_int, why) do { \
1551  free(a_uuid); \
1552  free(b_uuid); \
1553  crm_trace("%s (%d) %c %s (%d) : %s", \
1554  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1555  b_xml_id, b_call_id, why); \
1556  return an_int; \
1557  } while(0)
1558 
1559 gint
1560 sort_op_by_callid(gconstpointer a, gconstpointer b)
1561 {
1562  int a_call_id = -1;
1563  int b_call_id = -1;
1564 
1565  char *a_uuid = NULL;
1566  char *b_uuid = NULL;
1567 
1568  const xmlNode *xml_a = a;
1569  const xmlNode *xml_b = b;
1570 
1571  const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID);
1572  const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID);
1573 
1574  if (safe_str_eq(a_xml_id, b_xml_id)) {
1575  /* We have duplicate lrm_rsc_op entries in the status
1576  * section which is unliklely to be a good thing
1577  * - we can handle it easily enough, but we need to get
1578  * to the bottom of why it's happening.
1579  */
1580  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1581  sort_return(0, "duplicate");
1582  }
1583 
1586 
1587  if (a_call_id == -1 && b_call_id == -1) {
1588  /* both are pending ops so it doesn't matter since
1589  * stops are never pending
1590  */
1591  sort_return(0, "pending");
1592 
1593  } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1594  sort_return(-1, "call id");
1595 
1596  } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1597  sort_return(1, "call id");
1598 
1599  } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1600  /*
1601  * The op and last_failed_op are the same
1602  * Order on last-rc-change
1603  */
1604  int last_a = -1;
1605  int last_b = -1;
1606 
1609 
1610  crm_trace("rc-change: %d vs %d", last_a, last_b);
1611  if (last_a >= 0 && last_a < last_b) {
1612  sort_return(-1, "rc-change");
1613 
1614  } else if (last_b >= 0 && last_a > last_b) {
1615  sort_return(1, "rc-change");
1616  }
1617  sort_return(0, "rc-change");
1618 
1619  } else {
1620  /* One of the inputs is a pending operation
1621  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1622  */
1623 
1624  int a_id = -1;
1625  int b_id = -1;
1626  int dummy = -1;
1627 
1628  const char *a_magic = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC);
1629  const char *b_magic = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC);
1630 
1631  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1632  if(!decode_transition_magic(a_magic, &a_uuid, &a_id, &dummy, &dummy, &dummy, &dummy)) {
1633  sort_return(0, "bad magic a");
1634  }
1635  if(!decode_transition_magic(b_magic, &b_uuid, &b_id, &dummy, &dummy, &dummy, &dummy)) {
1636  sort_return(0, "bad magic b");
1637  }
1638  /* try to determine the relative age of the operation...
1639  * some pending operations (e.g. a start) may have been superseded
1640  * by a subsequent stop
1641  *
1642  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1643  */
1644  if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1645  /*
1646  * some of the logic in here may be redundant...
1647  *
1648  * if the UUID from the TE doesn't match then one better
1649  * be a pending operation.
1650  * pending operations don't survive between elections and joins
1651  * because we query the LRM directly
1652  */
1653 
1654  if (b_call_id == -1) {
1655  sort_return(-1, "transition + call");
1656 
1657  } else if (a_call_id == -1) {
1658  sort_return(1, "transition + call");
1659  }
1660 
1661  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1662  sort_return(-1, "transition");
1663 
1664  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1665  sort_return(1, "transition");
1666  }
1667  }
1668 
1669  /* we should never end up here */
1670  CRM_CHECK(FALSE, sort_return(0, "default"));
1671 
1672 }
1673 
1674 time_t
1676 {
1677  if(data_set) {
1678  if (data_set->now == NULL) {
1679  crm_trace("Recording a new 'now'");
1680  data_set->now = crm_time_new(NULL);
1681  }
1682  return crm_time_get_seconds_since_epoch(data_set->now);
1683  }
1684 
1685  crm_trace("Defaulting to 'now'");
1686  return time(NULL);
1687 }
1688 
1689 gboolean
1691 {
1692  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1693  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1694 
1695  CRM_CHECK(role != NULL, return FALSE);
1696 
1697  if (value == NULL || safe_str_eq("started", value)
1698  || safe_str_eq("default", value)) {
1699  return FALSE;
1700  }
1701 
1702  local_role = text2role(value);
1703  if (local_role == RSC_ROLE_UNKNOWN) {
1704  crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1705  return FALSE;
1706 
1707  } else if (local_role > RSC_ROLE_STARTED) {
1708  if (uber_parent(rsc)->variant == pe_master) {
1709  if (local_role > RSC_ROLE_SLAVE) {
1710  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1711  return FALSE;
1712  }
1713 
1714  } else {
1715  crm_config_err("%s is not part of a master/slave resource, a %s of '%s' makes no sense",
1716  rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1717  return FALSE;
1718  }
1719  }
1720 
1721  *role = local_role;
1722  return TRUE;
1723 }
1724 
1725 gboolean
1726 order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order)
1727 {
1728  GListPtr gIter = NULL;
1729  action_wrapper_t *wrapper = NULL;
1730  GListPtr list = NULL;
1731 
1732  if (order == pe_order_none) {
1733  return FALSE;
1734  }
1735 
1736  if (lh_action == NULL || rh_action == NULL) {
1737  return FALSE;
1738  }
1739 
1740  crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1741 
1742  /* Ensure we never create a dependency on ourselves... it's happened */
1743  CRM_ASSERT(lh_action != rh_action);
1744 
1745  /* Filter dups, otherwise update_action_states() has too much work to do */
1746  gIter = lh_action->actions_after;
1747  for (; gIter != NULL; gIter = gIter->next) {
1748  action_wrapper_t *after = (action_wrapper_t *) gIter->data;
1749 
1750  if (after->action == rh_action && (after->type & order)) {
1751  return FALSE;
1752  }
1753  }
1754 
1755  wrapper = calloc(1, sizeof(action_wrapper_t));
1756  wrapper->action = rh_action;
1757  wrapper->type = order;
1758 
1759  list = lh_action->actions_after;
1760  list = g_list_prepend(list, wrapper);
1761  lh_action->actions_after = list;
1762 
1763  wrapper = NULL;
1764 
1765 /* order |= pe_order_implies_then; */
1766 /* order ^= pe_order_implies_then; */
1767 
1768  wrapper = calloc(1, sizeof(action_wrapper_t));
1769  wrapper->action = lh_action;
1770  wrapper->type = order;
1771  list = rh_action->actions_before;
1772  list = g_list_prepend(list, wrapper);
1773  rh_action->actions_before = list;
1774  return TRUE;
1775 }
1776 
1777 action_t *
1778 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1779 {
1780  action_t *op = NULL;
1781 
1782  if(data_set->singletons) {
1783  op = g_hash_table_lookup(data_set->singletons, name);
1784  }
1785  if (op == NULL) {
1786  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1789  }
1790 
1791  return op;
1792 }
1793 
1794 void
1796 {
1797  ticket_t *ticket = data;
1798 
1799  if (ticket->state) {
1800  g_hash_table_destroy(ticket->state);
1801  }
1802  free(ticket->id);
1803  free(ticket);
1804 }
1805 
1806 ticket_t *
1807 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1808 {
1809  ticket_t *ticket = NULL;
1810 
1811  if (ticket_id == NULL || strlen(ticket_id) == 0) {
1812  return NULL;
1813  }
1814 
1815  if (data_set->tickets == NULL) {
1816  data_set->tickets =
1817  g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_ticket);
1818  }
1819 
1820  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1821  if (ticket == NULL) {
1822 
1823  ticket = calloc(1, sizeof(ticket_t));
1824  if (ticket == NULL) {
1825  crm_err("Cannot allocate ticket '%s'", ticket_id);
1826  return NULL;
1827  }
1828 
1829  crm_trace("Creaing ticket entry for %s", ticket_id);
1830 
1831  ticket->id = strdup(ticket_id);
1832  ticket->granted = FALSE;
1833  ticket->last_granted = -1;
1834  ticket->standby = FALSE;
1835  ticket->state = crm_str_table_new();
1836 
1837  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1838  }
1839 
1840  return ticket;
1841 }
1842 
1843 static void
1844 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1845 {
1846  if (param_set && param_string) {
1847  xmlAttrPtr xIter = param_set->properties;
1848 
1849  while (xIter) {
1850  const char *prop_name = (const char *)xIter->name;
1851  char *name = crm_strdup_printf(" %s ", prop_name);
1852  char *match = strstr(param_string, name);
1853 
1854  free(name);
1855 
1856  // Do now, because current entry might get removed below
1857  xIter = xIter->next;
1858 
1859  if (need_present && match == NULL) {
1860  crm_trace("%s not found in %s", prop_name, param_string);
1861  xml_remove_prop(param_set, prop_name);
1862 
1863  } else if (need_present == FALSE && match) {
1864  crm_trace("%s found in %s", prop_name, param_string);
1865  xml_remove_prop(param_set, prop_name);
1866  }
1867  }
1868  }
1869 }
1870 
1871 #if ENABLE_VERSIONED_ATTRS
1872 static void
1873 append_versioned_params(xmlNode *versioned_params, const char *ra_version, xmlNode *params)
1874 {
1875  GHashTable *hash = pe_unpack_versioned_parameters(versioned_params, ra_version);
1876  char *key = NULL;
1877  char *value = NULL;
1878  GHashTableIter iter;
1879 
1880  g_hash_table_iter_init(&iter, hash);
1881  while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value)) {
1882  crm_xml_add(params, key, value);
1883  }
1884  g_hash_table_destroy(hash);
1885 }
1886 #endif
1887 
1888 static op_digest_cache_t *
1889 rsc_action_digest(resource_t * rsc, const char *task, const char *key,
1890  node_t * node, xmlNode * xml_op, pe_working_set_t * data_set)
1891 {
1892  op_digest_cache_t *data = NULL;
1893 
1894  data = g_hash_table_lookup(node->details->digest_cache, key);
1895  if (data == NULL) {
1896  GHashTable *local_rsc_params = crm_str_table_new();
1897  action_t *action = custom_action(rsc, strdup(key), task, node, TRUE, FALSE, data_set);
1898 #if ENABLE_VERSIONED_ATTRS
1899  xmlNode *local_versioned_params = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1900  const char *ra_version = NULL;
1901 #endif
1902 
1903  const char *op_version;
1904  const char *restart_list = NULL;
1905  const char *secure_list = " passwd password ";
1906 
1907  data = calloc(1, sizeof(op_digest_cache_t));
1908  CRM_ASSERT(data != NULL);
1909 
1910  get_rsc_attributes(local_rsc_params, rsc, node, data_set);
1911 #if ENABLE_VERSIONED_ATTRS
1912  pe_get_versioned_attributes(local_versioned_params, rsc, node, data_set);
1913 #endif
1914 
1915  data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
1916 
1917  // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
1918  if (container_fix_remote_addr_in(rsc, data->params_all, "addr")) {
1919  crm_trace("Fixed addr for %s on %s", rsc->id, node->details->uname);
1920  }
1921 
1922  g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
1923  g_hash_table_foreach(action->extra, hash2field, data->params_all);
1924  g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
1925  g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
1926 
1927  if(xml_op) {
1928  secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
1929  restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
1930 
1931  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1932 #if ENABLE_VERSIONED_ATTRS
1933  ra_version = crm_element_value(xml_op, XML_ATTR_RA_VERSION);
1934 #endif
1935 
1936  } else {
1937  op_version = CRM_FEATURE_SET;
1938  }
1939 
1940 #if ENABLE_VERSIONED_ATTRS
1941  append_versioned_params(local_versioned_params, ra_version, data->params_all);
1942  append_versioned_params(rsc->versioned_parameters, ra_version, data->params_all);
1943 
1944  {
1945  pe_rsc_action_details_t *details = pe_rsc_action_details(action);
1946  append_versioned_params(details->versioned_parameters, ra_version, data->params_all);
1947  }
1948 #endif
1949 
1950  filter_action_parameters(data->params_all, op_version);
1951 
1952  g_hash_table_destroy(local_rsc_params);
1953  pe_free_action(action);
1954 
1955  data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
1956 
1957  if (is_set(data_set->flags, pe_flag_sanitized)) {
1958  data->params_secure = copy_xml(data->params_all);
1959  if(secure_list) {
1960  filter_parameters(data->params_secure, secure_list, FALSE);
1961  }
1962  data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
1963  }
1964 
1965  if(xml_op && crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1966  data->params_restart = copy_xml(data->params_all);
1967  if (restart_list) {
1968  filter_parameters(data->params_restart, restart_list, TRUE);
1969  }
1971  }
1972 
1973  g_hash_table_insert(node->details->digest_cache, strdup(key), data);
1974  }
1975 
1976  return data;
1977 }
1978 
1980 rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
1981  pe_working_set_t * data_set)
1982 {
1983  op_digest_cache_t *data = NULL;
1984 
1985  char *key = NULL;
1986  int interval = 0;
1987 
1988  const char *op_version;
1989  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1990  const char *interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
1991 
1992  const char *digest_all;
1993  const char *digest_restart;
1994 
1995  CRM_ASSERT(node != NULL);
1996 
1997  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1998  digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
1999  digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
2000 
2001  interval = crm_parse_int(interval_s, "0");
2002  key = generate_op_key(rsc->id, task, interval);
2003  data = rsc_action_digest(rsc, task, key, node, xml_op, data_set);
2004 
2005  data->rc = RSC_DIGEST_MATCH;
2006  if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
2007  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
2008  key, node->details->uname,
2009  crm_str(digest_restart), data->digest_restart_calc,
2010  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2011  data->rc = RSC_DIGEST_RESTART;
2012 
2013  } else if (digest_all == NULL) {
2014  /* it is unknown what the previous op digest was */
2015  data->rc = RSC_DIGEST_UNKNOWN;
2016 
2017  } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
2018  pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (%s:%s) %s",
2019  key, node->details->uname,
2020  crm_str(digest_all), data->digest_all_calc,
2021  (interval > 0)? "reschedule" : "reload",
2022  op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2023  data->rc = RSC_DIGEST_ALL;
2024  }
2025 
2026  free(key);
2027  return data;
2028 }
2029 
2030 #define STONITH_DIGEST_TASK "stonith-on"
2031 
2032 static op_digest_cache_t *
2033 fencing_action_digest_cmp(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
2034 {
2035  char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
2036  op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key, node, NULL, data_set);
2037 
2038  const char *digest_all = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
2039  const char *digest_secure = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
2040 
2041  /* No 'reloads' for fencing device changes
2042  *
2043  * We use the resource id + agent + digest so that we can detect
2044  * changes to the agent and/or the parameters used
2045  */
2046  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);
2047  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);
2048 
2049  data->rc = RSC_DIGEST_ALL;
2050  if (digest_all == NULL) {
2051  /* it is unknown what the previous op digest was */
2052  data->rc = RSC_DIGEST_UNKNOWN;
2053 
2054  } else if (strstr(digest_all, search_all)) {
2055  data->rc = RSC_DIGEST_MATCH;
2056 
2057  } else if(digest_secure && data->digest_secure_calc) {
2058  if(strstr(digest_secure, search_secure)) {
2059  if (is_set(data_set->flags, pe_flag_sanitized)) {
2060  printf("Only 'private' parameters to %s for unfencing %s changed\n",
2061  rsc->id, node->details->uname);
2062  }
2063  data->rc = RSC_DIGEST_MATCH;
2064  }
2065  }
2066 
2067  if (data->rc == RSC_DIGEST_ALL && is_set(data_set->flags, pe_flag_sanitized) && data->digest_secure_calc) {
2068  if (is_set(data_set->flags, pe_flag_sanitized)) {
2069  printf("Parameters to %s for unfencing %s changed, try '%s:%s:%s'\n",
2070  rsc->id, node->details->uname, rsc->id,
2071  (const char *) g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE),
2072  data->digest_secure_calc);
2073  }
2074  }
2075 
2076  free(key);
2077  free(search_all);
2078  free(search_secure);
2079 
2080  return data;
2081 }
2082 
2083 const char *rsc_printable_id(resource_t *rsc)
2084 {
2085  if (is_not_set(rsc->flags, pe_rsc_unique)) {
2086  return ID(rsc->xml);
2087  }
2088  return rsc->id;
2089 }
2090 
2091 void
2092 clear_bit_recursive(resource_t * rsc, unsigned long long flag)
2093 {
2094  GListPtr gIter = rsc->children;
2095 
2096  clear_bit(rsc->flags, flag);
2097  for (; gIter != NULL; gIter = gIter->next) {
2098  resource_t *child_rsc = (resource_t *) gIter->data;
2099 
2100  clear_bit_recursive(child_rsc, flag);
2101  }
2102 }
2103 
2104 void
2105 set_bit_recursive(resource_t * rsc, unsigned long long flag)
2106 {
2107  GListPtr gIter = rsc->children;
2108 
2109  set_bit(rsc->flags, flag);
2110  for (; gIter != NULL; gIter = gIter->next) {
2111  resource_t *child_rsc = (resource_t *) gIter->data;
2112 
2113  set_bit_recursive(child_rsc, flag);
2114  }
2115 }
2116 
2117 static GListPtr
2118 find_unfencing_devices(GListPtr candidates, GListPtr matches)
2119 {
2120  for (GListPtr gIter = candidates; gIter != NULL; gIter = gIter->next) {
2121  resource_t *candidate = gIter->data;
2122  const char *provides = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_PROVIDES);
2123  const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
2124 
2125  if(candidate->children) {
2126  matches = find_unfencing_devices(candidate->children, matches);
2127  } else if (is_not_set(candidate->flags, pe_rsc_fence_device)) {
2128  continue;
2129 
2130  } else if (crm_str_eq(provides, "unfencing", FALSE) || crm_str_eq(requires, "unfencing", FALSE)) {
2131  matches = g_list_prepend(matches, candidate);
2132  }
2133  }
2134  return matches;
2135 }
2136 
2137 
2138 action_t *
2139 pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe_working_set_t * data_set)
2140 {
2141  char *op_key = NULL;
2142  action_t *stonith_op = NULL;
2143 
2144  if(op == NULL) {
2145  op = data_set->stonith_action;
2146  }
2147 
2148  op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2149 
2150  if(data_set->singletons) {
2151  stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2152  }
2153 
2154  if(stonith_op == NULL) {
2155  stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2156 
2157  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2158  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2159  add_hash_param(stonith_op->meta, "stonith_action", op);
2160 
2161  if(is_remote_node(node) && is_set(data_set->flags, pe_flag_enable_unfencing)) {
2162  /* Extra work to detect device changes on remotes
2163  *
2164  * We may do this for all nodes in the future, but for now
2165  * the check_action_definition() based stuff works fine.
2166  *
2167  * Use "stonith-on" to avoid creating cache entries for
2168  * operations check_action_definition() would look for.
2169  */
2170  long max = 1024;
2171  long digests_all_offset = 0;
2172  long digests_secure_offset = 0;
2173 
2174  char *digests_all = malloc(max);
2175  char *digests_secure = malloc(max);
2176  GListPtr matches = find_unfencing_devices(data_set->resources, NULL);
2177 
2178  for (GListPtr gIter = matches; gIter != NULL; gIter = gIter->next) {
2179  resource_t *match = gIter->data;
2180  op_digest_cache_t *data = fencing_action_digest_cmp(match, node, data_set);
2181 
2182  if(data->rc == RSC_DIGEST_ALL) {
2183  optional = FALSE;
2184  crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2185  if (is_set(data_set->flags, pe_flag_sanitized)) {
2186  /* Extra detail for those running from the commandline */
2187  fprintf(stdout, " notice: Unfencing %s (remote): because the definition of %s changed\n", node->details->uname, match->id);
2188  }
2189  }
2190 
2191  digests_all_offset += snprintf(
2192  digests_all+digests_all_offset, max-digests_all_offset,
2193  "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_all_calc);
2194 
2195  digests_secure_offset += snprintf(
2196  digests_secure+digests_secure_offset, max-digests_secure_offset,
2197  "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_secure_calc);
2198  }
2199  g_hash_table_insert(stonith_op->meta,
2200  strdup(XML_OP_ATTR_DIGESTS_ALL),
2201  digests_all);
2202  g_hash_table_insert(stonith_op->meta,
2204  digests_secure);
2205  }
2206 
2207  } else {
2208  free(op_key);
2209  }
2210 
2211  if(optional == FALSE && pe_can_fence(data_set, node)) {
2212  pe_action_required(stonith_op, NULL, reason);
2213  } else if(reason && stonith_op->reason == NULL) {
2214  stonith_op->reason = strdup(reason);
2215  }
2216 
2217  return stonith_op;
2218 }
2219 
2220 void
2222  resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set)
2223 {
2224  if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
2225  /* No resources require it */
2226  return;
2227 
2228  } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
2229  /* Wasn't a stonith device */
2230  return;
2231 
2232  } else if(node
2233  && node->details->online
2234  && node->details->unclean == FALSE
2235  && node->details->shutdown == FALSE) {
2236  action_t *unfence = pe_fence_op(node, "on", FALSE, reason, data_set);
2237 
2238  if(dependency) {
2239  order_actions(unfence, dependency, pe_order_optional);
2240  }
2241 
2242  } else if(rsc) {
2243  GHashTableIter iter;
2244 
2245  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2246  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2247  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2248  trigger_unfencing(rsc, node, reason, dependency, data_set);
2249  }
2250  }
2251  }
2252 }
2253 
2254 gboolean
2255 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2256 {
2257  tag_t *tag = NULL;
2258  GListPtr gIter = NULL;
2259  gboolean is_existing = FALSE;
2260 
2261  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2262 
2263  tag = g_hash_table_lookup(tags, tag_name);
2264  if (tag == NULL) {
2265  tag = calloc(1, sizeof(tag_t));
2266  if (tag == NULL) {
2267  return FALSE;
2268  }
2269  tag->id = strdup(tag_name);
2270  tag->refs = NULL;
2271  g_hash_table_insert(tags, strdup(tag_name), tag);
2272  }
2273 
2274  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2275  const char *existing_ref = (const char *) gIter->data;
2276 
2277  if (crm_str_eq(existing_ref, obj_ref, TRUE)){
2278  is_existing = TRUE;
2279  break;
2280  }
2281  }
2282 
2283  if (is_existing == FALSE) {
2284  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2285  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2286  }
2287 
2288  return TRUE;
2289 }
2290 
2291 void pe_action_set_flag_reason(const char *function, long line,
2292  pe_action_t *action, pe_action_t *reason, const char *text,
2293  enum pe_action_flags flags, bool overwrite)
2294 {
2295  bool unset = FALSE;
2296  bool update = FALSE;
2297  const char *change = NULL;
2298 
2299  if(is_set(flags, pe_action_runnable)) {
2300  unset = TRUE;
2301  change = "unrunnable";
2302  } else if(is_set(flags, pe_action_optional)) {
2303  unset = TRUE;
2304  change = "required";
2305  } else if(is_set(flags, pe_action_failure_is_fatal)) {
2306  change = "fatally failed";
2307  } else if(is_set(flags, pe_action_migrate_runnable)) {
2308  unset = TRUE;
2309  overwrite = TRUE;
2310  change = "unrunnable";
2311  } else if(is_set(flags, pe_action_dangle)) {
2312  change = "dangling";
2313  } else if(is_set(flags, pe_action_requires_any)) {
2314  change = "required";
2315  } else {
2316  crm_err("Unknown flag change to %s by %s: 0x%.16x",
2317  flags, action->uuid, (reason? reason->uuid : 0));
2318  }
2319 
2320  if(unset) {
2321  if(is_set(action->flags, flags)) {
2322  action->flags = crm_clear_bit(function, line, action->uuid, action->flags, flags);
2323  update = TRUE;
2324  }
2325 
2326  } else {
2327  if(is_not_set(action->flags, flags)) {
2328  action->flags = crm_set_bit(function, line, action->uuid, action->flags, flags);
2329  update = TRUE;
2330  }
2331  }
2332 
2333  if((change && update) || text) {
2334  char *reason_text = NULL;
2335  if(reason == NULL) {
2336  pe_action_set_reason(action, text, overwrite);
2337 
2338  } else if(reason->rsc == NULL) {
2339  reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2340  } else {
2341  reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2342  }
2343 
2344  if(reason_text && action->rsc != reason->rsc) {
2345  pe_action_set_reason(action, reason_text, overwrite);
2346  }
2347  free(reason_text);
2348  }
2349  }
2350 
2351 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
2352 {
2353  if(action->reason && overwrite) {
2354  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'", action->uuid, action->reason, reason);
2355  free(action->reason);
2356  action->reason = NULL;
2357  }
2358  if(action->reason == NULL) {
2359  if(reason) {
2360  pe_rsc_trace(action->rsc, "Set %s reason to '%s'", action->uuid, reason);
2361  action->reason = strdup(reason);
2362  } else {
2363  action->reason = NULL;
2364  }
2365  }
2366 }
#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:107
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:304
const char * uname
Definition: status.h:139
enum rsc_start_requirement needs
Definition: status.h:344
enum pe_ordering type
Definition: status.h:460
A dumping ground.
#define LOG_DEBUG_4
Definition: logging.h:33
#define crm_notice(fmt, args...)
Definition: logging.h:250
#define CRMD_ACTION_MIGRATED
Definition: crm.h:173
xmlNode * xml
Definition: status.h:259
void dump_rsc_utilization(int level, const char *comment, resource_t *rsc, node_t *node)
Definition: utils.c:343
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:25
#define pe_flag_have_stonith_resource
Definition: status.h:66
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:219
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
Definition: utils.c:392
#define XML_OP_ATTR_DIGESTS_ALL
Definition: msg_xml.h:244
GHashTable * utilization
Definition: status.h:299
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:365
gboolean get_target_role(resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:1690
#define CRM_OP_FENCE
Definition: crm.h:127
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:384
node_t * node_copy(const node_t *this_node)
Definition: utils.c:127
int crm_element_value_const_int(const xmlNode *data, const char *name, int *dest)
Definition: xml.c:3857
GListPtr node_list_dup(GListPtr list, gboolean reset, gboolean filter)
Definition: utils.c:199
#define crm_time_log_timeofday
Definition: iso8601.h:71
#define pe_flag_enable_unfencing
Definition: status.h:67
const char * id
Definition: status.h:138
int weight
Definition: status.h:175
#define XML_ATTR_TYPE
Definition: msg_xml.h:105
int sort_index
Definition: status.h:274
bool pe_can_fence(pe_working_set_t *data_set, node_t *node)
Definition: utils.c:100
struct crm_time_s crm_time_t
Definition: iso8601.h:37
time_t last_granted
Definition: status.h:392
#define crm_config_err(fmt...)
Definition: crm_internal.h:256
#define pe_rsc_stopping
Definition: status.h:208
enum action_tasks get_complex_task(resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1361
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:230
xmlNode * op_defaults
Definition: status.h:116
#define pe_action_required(action, reason, text)
Definition: internal.h:306
#define pe_rsc_needs_quorum
Definition: status.h:217
gboolean exclusive_discover
Definition: status.h:313
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:2139
enum action_fail_response on_fail
Definition: status.h:345
#define CRM_FEATURE_SET
Definition: crm.h:36
#define pe_rsc_orphan
Definition: status.h:184
GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node)
Definition: utils.c:1455
char * cancel_task
Definition: status.h:341
long long crm_get_msec(const char *input)
Definition: utils.c:598
GListPtr running_rsc
Definition: status.h:153
GListPtr find_actions(GListPtr input, const char *key, const node_t *on_node)
Definition: utils.c:1415
enum pe_obj_types variant
Definition: status.h:265
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:268
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:283
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:2291
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:297
gboolean pending
Definition: status.h:145
#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:176
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1240
GListPtr resources
Definition: status.h:108
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:366
#define XML_OP_ATTR_DIGESTS_SECURE
Definition: msg_xml.h:245
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1560
#define CRM_ATTR_DIGESTS_ALL
Definition: crm.h:106
enum action_tasks text2task(const char *task)
Definition: common.c:233
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:1675
no_quorum_policy_t no_quorum_policy
Definition: status.h:99
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:190
char * clone_name
Definition: status.h:258
xmlNode * params_restart
Definition: internal.h:290
xmlNode * op_entry
Definition: status.h:337
#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:897
int id
Definition: status.h:332
void set_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2105
#define clear_bit(word, bit)
Definition: crm_internal.h:191
#define XML_RSC_ATTR_PROVIDES
Definition: msg_xml.h:228
#define RSC_START
Definition: crm.h:200
action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1778
GHashTable * tickets
Definition: status.h:102
enum rsc_role_e role
Definition: status.h:294
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
GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node)
Definition: utils.c:1327
GListPtr children
Definition: status.h:301
GListPtr actions_before
Definition: status.h:378
char * reason
Definition: status.h:386
#define crm_time_log_duration
Definition: iso8601.h:73
void * action_details
Definition: status.h:384
#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:230
GHashTable * extra
Definition: status.h:356
char * id
Definition: status.h:257
GHashTable * parameters
Definition: status.h:298
#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:161
#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
#define CRMD_ACTION_STOP
Definition: crm.h:178
#define pe_rsc_starting
Definition: status.h:207
gboolean(* active)(resource_t *, gboolean)
Definition: complex.h:48
#define pe_warn(fmt...)
Definition: internal.h:29
struct node_shared_s * details
Definition: status.h:178
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
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: utils.c:2351
#define set_bit(word, bit)
Definition: crm_internal.h:190
#define XML_RSC_ATTR_REQUIRES
Definition: msg_xml.h:227
gboolean unclean
Definition: status.h:146
#define XML_ATTR_OP
Definition: msg_xml.h:110
#define crm_debug(fmt, args...)
Definition: logging.h:253
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:573
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:102
char * digest_all_calc
Definition: internal.h:291
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1073
resource_object_functions_t * fns
Definition: status.h:266
char * task
Definition: status.h:339
#define sort_return(an_int, why)
Definition: utils.c:1550
resource_t * container
Definition: status.h:307
GHashTable * allowed_nodes
Definition: status.h:292
GHashTable * digest_cache
Definition: status.h:164
pe_working_set_t * pe_dataset
Definition: utils.c:31
#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:287
action_t * find_first_action(GListPtr input, const char *uuid, const char *task, node_t *on_node)
Definition: utils.c:1385
char * digest_secure_calc
Definition: internal.h:292
GHashTable * meta
Definition: status.h:355
gboolean is_container_remote_node(node_t *node)
Definition: remote.c:53
GListPtr refs
Definition: status.h:399
const char * stonith_action
Definition: status.h:92
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
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:114
Wrappers for and extensions to libxml2.
const char * container_fix_remote_addr_in(resource_t *rsc, xmlNode *xml, const char *field)
Definition: container.c:791
GHashTable * config_hash
Definition: status.h:101
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:2255
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
action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Definition: utils.c:419
unsigned long long flags
Definition: status.h:281
#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
xmlNode * crm_next_same_xml(xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:5078
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:135
#define crm_time_log(level, prefix, dt, flags)
Definition: iso8601.h:66
xmlNode * find_rsc_op_entry(resource_t *rsc, const char *key)
Definition: utils.c:1234
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:219
char * uuid
Definition: status.h:340
#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:914
#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:86
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
xmlNode * params_all
Definition: internal.h:288
int remote_reconnect_interval
Definition: status.h:314
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:287
node_t * node
Definition: status.h:336
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:270
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4908
action_t * action
Definition: status.h:462
GListPtr actions
Definition: status.h:286
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2490
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2578
pe_ordering
Definition: status.h:415
#define pe_rsc_unique
Definition: status.h:190
GHashTable * node_hash_from_list(GListPtr list)
Definition: utils.c:183
GHashTable * meta
Definition: status.h:297
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:32
#define crm_err(fmt, args...)
Definition: logging.h:248
void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1516
#define RSC_STATUS
Definition: crm.h:214
int pe_get_configured_timeout(resource_t *rsc, const char *action, pe_working_set_t *data_set)
Definition: utils.c:845
void node_list_exclude(GHashTable *list, GListPtr list2, gboolean merge_scores)
Definition: utils.c:148
void(* print)(resource_t *, const char *, long, void *)
Definition: complex.h:47
ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:1807
#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:158
#define pe_clear_action_bit(action, bit)
Definition: internal.h:33
enum rsc_role_e next_role
Definition: status.h:295
gboolean online
Definition: status.h:142
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3881
gboolean shutdown
Definition: status.h:148
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1276
GListPtr actions_after
Definition: status.h:379
xmlNode * params_secure
Definition: internal.h:289
void dump_node_capacity(int level, const char *comment, node_t *node)
Definition: utils.c:322
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:185
#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:346
gboolean remote_requires_reset
Definition: status.h:168
char * id
Definition: status.h:398
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
#define crm_str(x)
Definition: logging.h:274
#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:289
rsc_role_e
Definition: common.h:81
node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:285
enum pe_action_flags flags
Definition: status.h:343
gboolean standby
Definition: status.h:393
Definition: status.h:397
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:239
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
void pe_free_action(action_t *action)
Definition: utils.c:1300
void clear_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2092
#define pe_flag_have_quorum
Definition: status.h:60
void destroy_ticket(gpointer data)
Definition: utils.c:1795
int rsc_discover_mode
Definition: status.h:179
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
gboolean granted
Definition: status.h:391
xmlNode * first_named_child(xmlNode *parent, const char *name)
Definition: xml.c:5053
Definition: status.h:174
gboolean crm_is_true(const char *s)
Definition: strings.c:165
resource_t * rsc
Definition: status.h:335
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:286
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:26
GHashTable * singletons
Definition: status.h:105
#define ID(x)
Definition: msg_xml.h:446
unsigned long long flags
Definition: status.h:95
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:28
void print_resource(int log_level, const char *pre_text, resource_t *rsc, gboolean details)
Definition: utils.c:1284
xmlNode * ops_xml
Definition: status.h:261
char * crm_itoa(int an_int)
Definition: strings.c:60
#define pe_rsc_needs_fencing
Definition: status.h:218
#define safe_str_eq(a, b)
Definition: util.h:72
gboolean order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1726
char * id
Definition: status.h:390
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:1980
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:225
#define pe_flag_sanitized
Definition: status.h:83
#define pe_rsc_fence_device
Definition: status.h:191
GList * GListPtr
Definition: crm.h:218
#define STONITH_DIGEST_TASK
Definition: utils.c:2030
#define CRMD_ACTION_CANCEL
Definition: crm.h:169
crm_time_t * now
Definition: status.h:87
#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:293
void g_hash_destroy_str(gpointer data)
Definition: strings.c:74
#define crm_time_log_date
Definition: iso8601.h:70
void trigger_unfencing(resource_t *rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t *data_set)
Definition: utils.c:2221
const char * rsc_printable_id(resource_t *rsc)
Definition: utils.c:2083
#define XML_ATTR_RA_VERSION
Definition: msg_xml.h:87
GHashTable * state
Definition: status.h:394
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:65
action_tasks
Definition: common.h:52
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: unpack.h:115
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:24
int priority
Definition: status.h:272
#define CRMD_ACTION_STATUS
Definition: crm.h:189
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:116