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