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