pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
pe_actions.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <glib.h>
13 #include <stdbool.h>
14 
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/pengine/internal.h>
18 #include "pe_status_private.h"
19 
20 static void unpack_operation(pe_action_t *action, const xmlNode *xml_obj,
21  const pe_resource_t *container,
22  pe_working_set_t *data_set, guint interval_ms);
23 
24 static void
26 {
27  if (data_set->singletons == NULL) {
28  data_set->singletons = pcmk__strkey_table(NULL, NULL);
29  }
30  g_hash_table_insert(data_set->singletons, action->uuid, action);
31 }
32 
33 static pe_action_t *
34 lookup_singleton(pe_working_set_t *data_set, const char *action_uuid)
35 {
36  if (data_set->singletons == NULL) {
37  return NULL;
38  }
39  return g_hash_table_lookup(data_set->singletons, action_uuid);
40 }
41 
53 static pe_action_t *
54 find_existing_action(const char *key, const pe_resource_t *rsc,
55  const pe_node_t *node, const pe_working_set_t *data_set)
56 {
57  GList *matches = NULL;
58  pe_action_t *action = NULL;
59 
60  /* When rsc is NULL, it would be quicker to check data_set->singletons,
61  * but checking all data_set->actions takes the node into account.
62  */
63  matches = find_actions(((rsc == NULL)? data_set->actions : rsc->actions),
64  key, node);
65  if (matches == NULL) {
66  return NULL;
67  }
68  CRM_LOG_ASSERT(!pcmk__list_of_multiple(matches));
69 
70  action = matches->data;
71  g_list_free(matches);
72  return action;
73 }
74 
75 static xmlNode *
76 find_rsc_op_entry_helper(const pe_resource_t *rsc, const char *key,
77  gboolean include_disabled)
78 {
79  guint interval_ms = 0;
80  gboolean do_retry = TRUE;
81  char *local_key = NULL;
82  const char *name = NULL;
83  const char *interval_spec = NULL;
84  char *match_key = NULL;
85  xmlNode *op = NULL;
86  xmlNode *operation = NULL;
87 
88  retry:
89  for (operation = pcmk__xe_first_child(rsc->ops_xml); operation != NULL;
90  operation = pcmk__xe_next(operation)) {
91 
92  if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
93  bool enabled = false;
94 
95  name = crm_element_value(operation, "name");
96  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
97  if (!include_disabled && pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok &&
98  !enabled) {
99  continue;
100  }
101 
102  interval_ms = crm_parse_interval_spec(interval_spec);
103  match_key = pcmk__op_key(rsc->id, name, interval_ms);
104  if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
105  op = operation;
106  }
107  free(match_key);
108 
109  if (rsc->clone_name) {
110  match_key = pcmk__op_key(rsc->clone_name, name, interval_ms);
111  if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
112  op = operation;
113  }
114  free(match_key);
115  }
116 
117  if (op != NULL) {
118  free(local_key);
119  return op;
120  }
121  }
122  }
123 
124  free(local_key);
125  if (do_retry == FALSE) {
126  return NULL;
127  }
128 
129  do_retry = FALSE;
130  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
131  local_key = pcmk__op_key(rsc->id, "migrate", 0);
132  key = local_key;
133  goto retry;
134 
135  } else if (strstr(key, "_notify_")) {
136  local_key = pcmk__op_key(rsc->id, "notify", 0);
137  key = local_key;
138  goto retry;
139  }
140 
141  return NULL;
142 }
143 
144 xmlNode *
145 find_rsc_op_entry(const pe_resource_t *rsc, const char *key)
146 {
147  return find_rsc_op_entry_helper(rsc, key, FALSE);
148 }
149 
166 static pe_action_t *
167 new_action(char *key, const char *task, pe_resource_t *rsc,
168  const pe_node_t *node, bool optional, bool for_graph,
170 {
171  pe_action_t *action = calloc(1, sizeof(pe_action_t));
172 
173  CRM_ASSERT(action != NULL);
174 
175  action->rsc = rsc;
176  action->task = strdup(task); CRM_ASSERT(action->task != NULL);
177  action->uuid = key;
178  action->extra = pcmk__strkey_table(free, free);
179  action->meta = pcmk__strkey_table(free, free);
180 
181  if (node) {
182  action->node = pe__copy_node(node);
183  }
184 
185  if (pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
186  // Resource history deletion for a node can be done on the DC
188  }
189 
191  if (optional) {
193  } else {
195  }
196 
197  if (rsc != NULL) {
198  guint interval_ms = 0;
199 
200  action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
201  parse_op_key(key, NULL, NULL, &interval_ms);
202  unpack_operation(action, action->op_entry, rsc->container, data_set,
203  interval_ms);
204  }
205 
206  if (for_graph) {
207  pe_rsc_trace(rsc, "Created %s action %d (%s): %s for %s on %s",
208  (optional? "optional" : "required"),
209  data_set->action_id, key, task,
210  ((rsc == NULL)? "no resource" : rsc->id),
211  pe__node_name(node));
212  action->id = data_set->action_id++;
213 
214  data_set->actions = g_list_prepend(data_set->actions, action);
215  if (rsc == NULL) {
216  add_singleton(data_set, action);
217  } else {
218  rsc->actions = g_list_prepend(rsc->actions, action);
219  }
220  }
221  return action;
222 }
223 
231 static void
232 unpack_action_node_attributes(pe_action_t *action, pe_working_set_t *data_set)
233 {
235  && (action->op_entry != NULL)) {
236 
237  pe_rule_eval_data_t rule_data = {
238  .node_hash = action->node->details->attrs,
239  .role = RSC_ROLE_UNKNOWN,
240  .now = data_set->now,
241  .match_data = NULL,
242  .rsc_data = NULL,
243  .op_data = NULL
244  };
245 
248  &rule_data, action->extra, NULL,
249  FALSE, data_set);
250  }
251 }
252 
260 static void
261 update_action_optional(pe_action_t *action, gboolean optional)
262 {
263  // Force a non-recurring action to be optional if its resource is unmanaged
264  if ((action->rsc != NULL) && (action->node != NULL)
265  && !pcmk_is_set(action->flags, pe_action_pseudo)
266  && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
267  && (g_hash_table_lookup(action->meta,
268  XML_LRM_ATTR_INTERVAL_MS) == NULL)) {
269  pe_rsc_debug(action->rsc, "%s on %s is optional (%s is unmanaged)",
270  action->uuid, pe__node_name(action->node),
271  action->rsc->id);
273  // We shouldn't clear runnable here because ... something
274 
275  // Otherwise require the action if requested
276  } else if (!optional) {
278  }
279 }
280 
281 static enum pe_quorum_policy
282 effective_quorum_policy(pe_resource_t *rsc, pe_working_set_t *data_set)
283 {
285 
287  policy = no_quorum_ignore;
288 
289  } else if (data_set->no_quorum_policy == no_quorum_demote) {
290  switch (rsc->role) {
291  case RSC_ROLE_PROMOTED:
292  case RSC_ROLE_UNPROMOTED:
293  if (rsc->next_role > RSC_ROLE_UNPROMOTED) {
295  "no-quorum-policy=demote");
296  }
297  policy = no_quorum_ignore;
298  break;
299  default:
300  policy = no_quorum_stop;
301  break;
302  }
303  }
304  return policy;
305 }
306 
317 static void
318 update_resource_action_runnable(pe_action_t *action, bool for_graph,
320 {
321  if (pcmk_is_set(action->flags, pe_action_pseudo)) {
322  return;
323  }
324 
325  if (action->node == NULL) {
326  pe_rsc_trace(action->rsc, "%s is unrunnable (unallocated)",
327  action->uuid);
329 
330  } else if (!pcmk_is_set(action->flags, pe_action_dc)
331  && !(action->node->details->online)
332  && (!pe__is_guest_node(action->node)
333  || action->node->details->remote_requires_reset)) {
335  do_crm_log((for_graph? LOG_WARNING: LOG_TRACE),
336  "%s on %s is unrunnable (node is offline)",
337  action->uuid, pe__node_name(action->node));
338  if (pcmk_is_set(action->rsc->flags, pe_rsc_managed)
339  && for_graph
340  && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
341  && !(action->node->details->unclean)) {
342  pe_fence_node(data_set, action->node, "stop is unrunnable", false);
343  }
344 
345  } else if (!pcmk_is_set(action->flags, pe_action_dc)
346  && action->node->details->pending) {
348  do_crm_log((for_graph? LOG_WARNING: LOG_TRACE),
349  "Action %s on %s is unrunnable (node is pending)",
350  action->uuid, pe__node_name(action->node));
351 
352  } else if (action->needs == rsc_req_nothing) {
353  pe_action_set_reason(action, NULL, TRUE);
354  if (pe__is_guest_node(action->node)
355  && !pe_can_fence(data_set, action->node)) {
356  /* An action that requires nothing usually does not require any
357  * fencing in order to be runnable. However, there is an exception:
358  * such an action cannot be completed if it is on a guest node whose
359  * host is unclean and cannot be fenced.
360  */
361  pe_rsc_debug(action->rsc, "%s on %s is unrunnable "
362  "(node's host cannot be fenced)",
363  action->uuid, pe__node_name(action->node));
365  } else {
366  pe_rsc_trace(action->rsc,
367  "%s on %s does not require fencing or quorum",
368  action->uuid, pe__node_name(action->node));
370  }
371 
372  } else {
373  switch (effective_quorum_policy(action->rsc, data_set)) {
374  case no_quorum_stop:
375  pe_rsc_debug(action->rsc, "%s on %s is unrunnable (no quorum)",
376  action->uuid, pe__node_name(action->node));
378  pe_action_set_reason(action, "no quorum", true);
379  break;
380 
381  case no_quorum_freeze:
382  if (!action->rsc->fns->active(action->rsc, TRUE)
383  || (action->rsc->next_role > action->rsc->role)) {
384  pe_rsc_debug(action->rsc,
385  "%s on %s is unrunnable (no quorum)",
386  action->uuid, pe__node_name(action->node));
388  pe_action_set_reason(action, "quorum freeze", true);
389  }
390  break;
391 
392  default:
393  //pe_action_set_reason(action, NULL, TRUE);
395  break;
396  }
397  }
398 }
399 
407 static void
408 update_resource_flags_for_action(pe_resource_t *rsc, const pe_action_t *action)
409 {
410  /* @COMPAT pe_rsc_starting and pe_rsc_stopping are not actually used
411  * within Pacemaker, and should be deprecated and eventually removed
412  */
413  if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
415 
416  } else if (pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
417  if (pcmk_is_set(action->flags, pe_action_runnable)) {
419  } else {
421  }
422  }
423 }
424 
425 static bool
426 valid_stop_on_fail(const char *value)
427 {
428  return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
429 }
430 
431 static const char *
432 unpack_operation_on_fail(pe_action_t * action)
433 {
434  const char *name = NULL;
435  const char *role = NULL;
436  const char *on_fail = NULL;
437  const char *interval_spec = NULL;
438  const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
439 
440  if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
441  && !valid_stop_on_fail(value)) {
442 
443  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
444  "action to default value because '%s' is not "
445  "allowed for stop", action->rsc->id, value);
446  return NULL;
447 
448  } else if (pcmk__str_eq(action->task, CRMD_ACTION_DEMOTE, pcmk__str_casei) && !value) {
449  // demote on_fail defaults to monitor value for promoted role if present
450  xmlNode *operation = NULL;
451 
452  CRM_CHECK(action->rsc != NULL, return NULL);
453 
454  for (operation = pcmk__xe_first_child(action->rsc->ops_xml);
455  (operation != NULL) && (value == NULL);
456  operation = pcmk__xe_next(operation)) {
457  bool enabled = false;
458 
459  if (!pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
460  continue;
461  }
462  name = crm_element_value(operation, "name");
463  role = crm_element_value(operation, "role");
464  on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
465  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
466  if (!on_fail) {
467  continue;
468  } else if (pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok && !enabled) {
469  continue;
470  } else if (!pcmk__str_eq(name, "monitor", pcmk__str_casei)
473  NULL)) {
474  continue;
475  } else if (crm_parse_interval_spec(interval_spec) == 0) {
476  continue;
477  } else if (pcmk__str_eq(on_fail, "demote", pcmk__str_casei)) {
478  continue;
479  }
480 
481  value = on_fail;
482  }
483  } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
484  value = "ignore";
485 
486  } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
487  name = crm_element_value(action->op_entry, "name");
488  role = crm_element_value(action->op_entry, "role");
489  interval_spec = crm_element_value(action->op_entry,
491 
492  if (!pcmk__str_eq(name, CRMD_ACTION_PROMOTE, pcmk__str_casei)
493  && (!pcmk__str_eq(name, CRMD_ACTION_STATUS, pcmk__str_casei)
496  || (crm_parse_interval_spec(interval_spec) == 0))) {
497  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
498  "action to default value because 'demote' is not "
499  "allowed for it", action->rsc->id, name);
500  return NULL;
501  }
502  }
503 
504  return value;
505 }
506 
507 static int
508 unpack_timeout(const char *value)
509 {
510  int timeout_ms = crm_get_msec(value);
511 
512  if (timeout_ms < 0) {
514  }
515  return timeout_ms;
516 }
517 
518 // true if value contains valid, non-NULL interval origin for recurring op
519 static bool
520 unpack_interval_origin(const char *value, const xmlNode *xml_obj,
521  guint interval_ms, const crm_time_t *now,
522  long long *start_delay)
523 {
524  long long result = 0;
525  guint interval_sec = interval_ms / 1000;
526  crm_time_t *origin = NULL;
527 
528  // Ignore unspecified values and non-recurring operations
529  if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
530  return false;
531  }
532 
533  // Parse interval origin from text
534  origin = crm_time_new(value);
535  if (origin == NULL) {
536  pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
537  "'%s' because '%s' is not valid",
538  (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
539  return false;
540  }
541 
542  // Get seconds since origin (negative if origin is in the future)
544  crm_time_free(origin);
545 
546  // Calculate seconds from closest interval to now
547  result = result % interval_sec;
548 
549  // Calculate seconds remaining until next interval
550  result = ((result <= 0)? 0 : interval_sec) - result;
551  crm_info("Calculated a start delay of %llds for operation '%s'",
552  result,
553  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
554 
555  if (start_delay != NULL) {
556  *start_delay = result * 1000; // milliseconds
557  }
558  return true;
559 }
560 
561 static int
562 unpack_start_delay(const char *value, GHashTable *meta)
563 {
564  int start_delay = 0;
565 
566  if (value != NULL) {
567  start_delay = crm_get_msec(value);
568 
569  if (start_delay < 0) {
570  start_delay = 0;
571  }
572 
573  if (meta) {
574  g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
575  pcmk__itoa(start_delay));
576  }
577  }
578 
579  return start_delay;
580 }
581 
582 static xmlNode *
583 find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
584 {
585  guint interval_ms = 0;
586  guint min_interval_ms = G_MAXUINT;
587  const char *name = NULL;
588  const char *interval_spec = NULL;
589  xmlNode *op = NULL;
590  xmlNode *operation = NULL;
591 
592  for (operation = pcmk__xe_first_child(rsc->ops_xml);
593  operation != NULL;
594  operation = pcmk__xe_next(operation)) {
595 
596  if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
597  bool enabled = false;
598 
599  name = crm_element_value(operation, "name");
600  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
601  if (!include_disabled && pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok &&
602  !enabled) {
603  continue;
604  }
605 
606  if (!pcmk__str_eq(name, RSC_STATUS, pcmk__str_casei)) {
607  continue;
608  }
609 
610  interval_ms = crm_parse_interval_spec(interval_spec);
611 
612  if (interval_ms && (interval_ms < min_interval_ms)) {
613  min_interval_ms = interval_ms;
614  op = operation;
615  }
616  }
617  }
618 
619  return op;
620 }
621 
635 static void
636 unpack_operation(pe_action_t *action, const xmlNode *xml_obj,
637  const pe_resource_t *container,
638  pe_working_set_t *data_set, guint interval_ms)
639 {
640  int timeout_ms = 0;
641  const char *value = NULL;
642  bool is_probe = false;
643 
644  pe_rsc_eval_data_t rsc_rule_data = {
646  .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER),
647  .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE)
648  };
649 
650  pe_op_eval_data_t op_rule_data = {
651  .op_name = action->task,
652  .interval = interval_ms
653  };
654 
655  pe_rule_eval_data_t rule_data = {
656  .node_hash = NULL,
657  .role = RSC_ROLE_UNKNOWN,
658  .now = data_set->now,
659  .match_data = NULL,
660  .rsc_data = &rsc_rule_data,
661  .op_data = &op_rule_data
662  };
663 
664  CRM_CHECK(action && action->rsc, return);
665 
666  is_probe = pcmk_is_probe(action->task, interval_ms);
667 
668  // Cluster-wide <op_defaults> <meta_attributes>
670  action->meta, NULL, FALSE, data_set);
671 
672  // Determine probe default timeout differently
673  if (is_probe) {
674  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
675 
676  if (min_interval_mon) {
677  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
678  if (value) {
679  crm_trace("\t%s: Setting default timeout to minimum-interval "
680  "monitor's timeout '%s'", action->uuid, value);
681  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
682  strdup(value));
683  }
684  }
685  }
686 
687  if (xml_obj) {
688  xmlAttrPtr xIter = NULL;
689 
690  // <op> <meta_attributes> take precedence over defaults
691  pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, &rule_data,
692  action->meta, NULL, TRUE, data_set);
693 
694  /* Anything set as an <op> XML property has highest precedence.
695  * This ensures we use the name and interval from the <op> tag.
696  */
697  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
698  const char *prop_name = (const char *)xIter->name;
699  const char *prop_value = crm_element_value(xml_obj, prop_name);
700 
701  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
702  }
703  }
704 
705  g_hash_table_remove(action->meta, "id");
706 
707  // Normalize interval to milliseconds
708  if (interval_ms > 0) {
709  g_hash_table_replace(action->meta, strdup(XML_LRM_ATTR_INTERVAL),
710  crm_strdup_printf("%u", interval_ms));
711  } else {
712  g_hash_table_remove(action->meta, XML_LRM_ATTR_INTERVAL);
713  }
714 
715  /*
716  * Timeout order of precedence:
717  * 1. pcmk_monitor_timeout (if rsc has pcmk_ra_cap_fence_params
718  * and task is start or a probe; pcmk_monitor_timeout works
719  * by default for a recurring monitor)
720  * 2. explicit op timeout on the primitive
721  * 3. default op timeout
722  * a. if probe, then min-interval monitor's timeout
723  * b. else, in XML_CIB_TAG_OPCONFIG
724  * 4. CRM_DEFAULT_OP_TIMEOUT_S
725  *
726  * #1 overrides general rule of <op> XML property having highest
727  * precedence.
728  */
729  if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
731  && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
732  || is_probe)) {
733 
734  GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
735 
736  value = g_hash_table_lookup(params, "pcmk_monitor_timeout");
737 
738  if (value) {
739  crm_trace("\t%s: Setting timeout to pcmk_monitor_timeout '%s', "
740  "overriding default", action->uuid, value);
741  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
742  strdup(value));
743  }
744  }
745 
746  // Normalize timeout to positive milliseconds
747  value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
748  timeout_ms = unpack_timeout(value);
749  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
750  pcmk__itoa(timeout_ms));
751 
752  if (!pcmk__strcase_any_of(action->task, RSC_START, RSC_PROMOTE, NULL)) {
753  action->needs = rsc_req_nothing;
754  value = "nothing (not start or promote)";
755 
756  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
757  action->needs = rsc_req_stonith;
758  value = "fencing";
759 
760  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
761  action->needs = rsc_req_quorum;
762  value = "quorum";
763 
764  } else {
765  action->needs = rsc_req_nothing;
766  value = "nothing";
767  }
768  pe_rsc_trace(action->rsc, "%s requires %s", action->uuid, value);
769 
770  value = unpack_operation_on_fail(action);
771 
772  if (value == NULL) {
773 
774  } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
775  action->on_fail = action_fail_block;
776  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
777  value = "block"; // The above could destroy the original string
778 
779  } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
780  action->on_fail = action_fail_fence;
781  value = "node fencing";
782 
784  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
785  "operation '%s' to 'stop' because 'fence' is not "
786  "valid when fencing is disabled", action->uuid);
787  action->on_fail = action_fail_stop;
788  action->fail_role = RSC_ROLE_STOPPED;
789  value = "stop resource";
790  }
791 
792  } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
793  action->on_fail = action_fail_standby;
794  value = "node standby";
795 
796  } else if (pcmk__strcase_any_of(value, "ignore", PCMK__VALUE_NOTHING,
797  NULL)) {
798  action->on_fail = action_fail_ignore;
799  value = "ignore";
800 
801  } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
802  action->on_fail = action_fail_migrate;
803  value = "force migration";
804 
805  } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
806  action->on_fail = action_fail_stop;
807  action->fail_role = RSC_ROLE_STOPPED;
808  value = "stop resource";
809 
810  } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
811  action->on_fail = action_fail_recover;
812  value = "restart (and possibly migrate)";
813 
814  } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
815  if (container) {
817  value = "restart container (and possibly migrate)";
818 
819  } else {
820  value = NULL;
821  }
822 
823  } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
824  action->on_fail = action_fail_demote;
825  value = "demote instance";
826 
827  } else {
828  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
829  value = NULL;
830  }
831 
832  /* defaults */
833  if (value == NULL && container) {
835  value = "restart container (and possibly migrate) (default)";
836 
837  /* For remote nodes, ensure that any failure that results in dropping an
838  * active connection to the node results in fencing of the node.
839  *
840  * There are only two action failures that don't result in fencing.
841  * 1. probes - probe failures are expected.
842  * 2. start - a start failure indicates that an active connection does not already
843  * exist. The user can set op on-fail=fence if they really want to fence start
844  * failures. */
845  } else if (((value == NULL) || !pcmk_is_set(action->rsc->flags, pe_rsc_managed))
847  && !(pcmk__str_eq(action->task, CRMD_ACTION_STATUS, pcmk__str_casei)
848  && (interval_ms == 0))
849  && !pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
850 
851  if (!pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
852  action->on_fail = action_fail_stop;
853  action->fail_role = RSC_ROLE_STOPPED;
854  value = "stop unmanaged remote node (enforcing default)";
855 
856  } else {
858  value = "fence remote node (default)";
859  } else {
860  value = "recover remote node connection (default)";
861  }
862 
863  if (action->rsc->remote_reconnect_ms) {
864  action->fail_role = RSC_ROLE_STOPPED;
865  }
866  action->on_fail = action_fail_reset_remote;
867  }
868 
869  } else if (value == NULL && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
871  action->on_fail = action_fail_fence;
872  value = "resource fence (default)";
873 
874  } else {
875  action->on_fail = action_fail_block;
876  value = "resource block (default)";
877  }
878 
879  } else if (value == NULL) {
880  action->on_fail = action_fail_recover;
881  value = "restart (and possibly migrate) (default)";
882  }
883 
884  pe_rsc_trace(action->rsc, "%s failure handling: %s",
885  action->uuid, value);
886 
887  value = NULL;
888  if (xml_obj != NULL) {
889  value = g_hash_table_lookup(action->meta, "role_after_failure");
890  if (value) {
892  "Support for role_after_failure is deprecated and will be removed in a future release");
893  }
894  }
895  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
896  action->fail_role = text2role(value);
897  }
898  /* defaults */
899  if (action->fail_role == RSC_ROLE_UNKNOWN) {
900  if (pcmk__str_eq(action->task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
901  action->fail_role = RSC_ROLE_UNPROMOTED;
902  } else {
903  action->fail_role = RSC_ROLE_STARTED;
904  }
905  }
906  pe_rsc_trace(action->rsc, "%s failure results in: %s",
907  action->uuid, role2text(action->fail_role));
908 
909  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
910  if (value) {
911  unpack_start_delay(value, action->meta);
912  } else {
913  long long start_delay = 0;
914 
915  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
916  if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
917  &start_delay)) {
918  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
919  crm_strdup_printf("%lld", start_delay));
920  }
921  }
922 }
923 
941 pe_action_t *
942 custom_action(pe_resource_t *rsc, char *key, const char *task,
943  const pe_node_t *on_node, gboolean optional, gboolean save_action,
945 {
946  pe_action_t *action = NULL;
947 
948  CRM_ASSERT((key != NULL) && (task != NULL) && (data_set != NULL));
949 
950  if (save_action) {
951  action = find_existing_action(key, rsc, on_node, data_set);
952  }
953 
954  if (action == NULL) {
955  action = new_action(key, task, rsc, on_node, optional, save_action,
956  data_set);
957  } else {
958  free(key);
959  }
960 
961  update_action_optional(action, optional);
962 
963  if (rsc != NULL) {
964  if (action->node != NULL) {
965  unpack_action_node_attributes(action, data_set);
966  }
967 
968  update_resource_action_runnable(action, save_action, data_set);
969 
970  if (save_action) {
971  update_resource_flags_for_action(rsc, action);
972  }
973  }
974 
975  return action;
976 }
977 
978 pe_action_t *
980 {
981  pe_action_t *op = lookup_singleton(data_set, name);
982 
983  if (op == NULL) {
984  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
986  }
987  return op;
988 }
989 
990 static GList *
991 find_unfencing_devices(GList *candidates, GList *matches)
992 {
993  for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
994  pe_resource_t *candidate = gIter->data;
995 
996  if (candidate->children != NULL) {
997  matches = find_unfencing_devices(candidate->children, matches);
998 
999  } else if (!pcmk_is_set(candidate->flags, pe_rsc_fence_device)) {
1000  continue;
1001 
1002  } else if (pcmk_is_set(candidate->flags, pe_rsc_needs_unfencing)) {
1003  matches = g_list_prepend(matches, candidate);
1004 
1005  } else if (pcmk__str_eq(g_hash_table_lookup(candidate->meta,
1008  pcmk__str_casei)) {
1009  matches = g_list_prepend(matches, candidate);
1010  }
1011  }
1012  return matches;
1013 }
1014 
1015 static int
1016 node_priority_fencing_delay(const pe_node_t *node,
1017  const pe_working_set_t *data_set)
1018 {
1019  int member_count = 0;
1020  int online_count = 0;
1021  int top_priority = 0;
1022  int lowest_priority = 0;
1023  GList *gIter = NULL;
1024 
1025  // `priority-fencing-delay` is disabled
1026  if (data_set->priority_fencing_delay <= 0) {
1027  return 0;
1028  }
1029 
1030  /* No need to request a delay if the fencing target is not a normal cluster
1031  * member, for example if it's a remote node or a guest node. */
1032  if (node->details->type != node_member) {
1033  return 0;
1034  }
1035 
1036  // No need to request a delay if the fencing target is in our partition
1037  if (node->details->online) {
1038  return 0;
1039  }
1040 
1041  for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1042  pe_node_t *n = gIter->data;
1043 
1044  if (n->details->type != node_member) {
1045  continue;
1046  }
1047 
1048  member_count ++;
1049 
1050  if (n->details->online) {
1051  online_count++;
1052  }
1053 
1054  if (member_count == 1
1055  || n->details->priority > top_priority) {
1056  top_priority = n->details->priority;
1057  }
1058 
1059  if (member_count == 1
1060  || n->details->priority < lowest_priority) {
1061  lowest_priority = n->details->priority;
1062  }
1063  }
1064 
1065  // No need to delay if we have more than half of the cluster members
1066  if (online_count > member_count / 2) {
1067  return 0;
1068  }
1069 
1070  /* All the nodes have equal priority.
1071  * Any configured corresponding `pcmk_delay_base/max` will be applied. */
1072  if (lowest_priority == top_priority) {
1073  return 0;
1074  }
1075 
1076  if (node->details->priority < top_priority) {
1077  return 0;
1078  }
1079 
1081 }
1082 
1083 pe_action_t *
1084 pe_fence_op(pe_node_t *node, const char *op, bool optional,
1085  const char *reason, bool priority_delay, pe_working_set_t *data_set)
1086 {
1087  char *op_key = NULL;
1088  pe_action_t *stonith_op = NULL;
1089 
1090  if(op == NULL) {
1091  op = data_set->stonith_action;
1092  }
1093 
1094  op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
1095 
1096  stonith_op = lookup_singleton(data_set, op_key);
1097  if(stonith_op == NULL) {
1098  stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
1099 
1100  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1101  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
1102  add_hash_param(stonith_op->meta, "stonith_action", op);
1103 
1105  /* Extra work to detect device changes
1106  */
1107  GString *digests_all = g_string_sized_new(1024);
1108  GString *digests_secure = g_string_sized_new(1024);
1109 
1110  GList *matches = find_unfencing_devices(data_set->resources, NULL);
1111 
1112  char *key = NULL;
1113  char *value = NULL;
1114 
1115  for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
1116  pe_resource_t *match = gIter->data;
1117  const char *agent = g_hash_table_lookup(match->meta,
1118  XML_ATTR_TYPE);
1119  op_digest_cache_t *data = NULL;
1120 
1121  data = pe__compare_fencing_digest(match, agent, node, data_set);
1122  if(data->rc == RSC_DIGEST_ALL) {
1123  optional = FALSE;
1124  crm_notice("Unfencing node %s because the definition of "
1125  "%s changed", pe__node_name(node), match->id);
1126  if (!pcmk__is_daemon && data_set->priv != NULL) {
1127  pcmk__output_t *out = data_set->priv;
1128 
1129  out->info(out,
1130  "notice: Unfencing node %s because the "
1131  "definition of %s changed",
1132  pe__node_name(node), match->id);
1133  }
1134  }
1135 
1136  pcmk__g_strcat(digests_all,
1137  match->id, ":", agent, ":",
1138  data->digest_all_calc, ",", NULL);
1139  pcmk__g_strcat(digests_secure,
1140  match->id, ":", agent, ":",
1141  data->digest_secure_calc, ",", NULL);
1142  }
1143  key = strdup(XML_OP_ATTR_DIGESTS_ALL);
1144  value = strdup((const char *) digests_all->str);
1145  CRM_ASSERT((key != NULL) && (value != NULL));
1146  g_hash_table_insert(stonith_op->meta, key, value);
1147  g_string_free(digests_all, TRUE);
1148 
1149  key = strdup(XML_OP_ATTR_DIGESTS_SECURE);
1150  value = strdup((const char *) digests_secure->str);
1151  CRM_ASSERT((key != NULL) && (value != NULL));
1152  g_hash_table_insert(stonith_op->meta, key, value);
1153  g_string_free(digests_secure, TRUE);
1154  }
1155 
1156  } else {
1157  free(op_key);
1158  }
1159 
1161 
1162  /* It's a suitable case where `priority-fencing-delay` applies.
1163  * At least add `priority-fencing-delay` field as an indicator. */
1164  && (priority_delay
1165 
1166  /* The priority delay needs to be recalculated if this function has
1167  * been called by schedule_fencing_and_shutdowns() after node
1168  * priority has already been calculated by native_add_running().
1169  */
1170  || g_hash_table_lookup(stonith_op->meta,
1172 
1173  /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
1174  * the targeting node. So that it takes precedence over any possible
1175  * `pcmk_delay_base/max`.
1176  */
1177  char *delay_s = pcmk__itoa(node_priority_fencing_delay(node, data_set));
1178 
1179  g_hash_table_insert(stonith_op->meta,
1181  delay_s);
1182  }
1183 
1184  if(optional == FALSE && pe_can_fence(data_set, node)) {
1186  pe_action_set_reason(stonith_op, reason, false);
1187 
1188  } else if(reason && stonith_op->reason == NULL) {
1189  stonith_op->reason = strdup(reason);
1190  }
1191 
1192  return stonith_op;
1193 }
1194 
1195 void
1197 {
1198  if (action == NULL) {
1199  return;
1200  }
1201  g_list_free_full(action->actions_before, free); /* pe_action_wrapper_t* */
1202  g_list_free_full(action->actions_after, free); /* pe_action_wrapper_t* */
1203  if (action->extra) {
1204  g_hash_table_destroy(action->extra);
1205  }
1206  if (action->meta) {
1207  g_hash_table_destroy(action->meta);
1208  }
1209  free(action->cancel_task);
1210  free(action->reason);
1211  free(action->task);
1212  free(action->uuid);
1213  free(action->node);
1214  free(action);
1215 }
1216 
1217 int
1219 {
1220  xmlNode *child = NULL;
1221  GHashTable *action_meta = NULL;
1222  const char *timeout_spec = NULL;
1223  int timeout_ms = 0;
1224 
1225  pe_rule_eval_data_t rule_data = {
1226  .node_hash = NULL,
1227  .role = RSC_ROLE_UNKNOWN,
1228  .now = data_set->now,
1229  .match_data = NULL,
1230  .rsc_data = NULL,
1231  .op_data = NULL
1232  };
1233 
1234  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
1235  child != NULL; child = crm_next_same_xml(child)) {
1236  if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
1237  pcmk__str_casei)) {
1238  timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
1239  break;
1240  }
1241  }
1242 
1243  if (timeout_spec == NULL && data_set->op_defaults) {
1244  action_meta = pcmk__strkey_table(free, free);
1246  &rule_data, action_meta, NULL, FALSE, data_set);
1247  timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
1248  }
1249 
1250  // @TODO check meta-attributes
1251  // @TODO maybe use min-interval monitor timeout as default for monitors
1252 
1253  timeout_ms = crm_get_msec(timeout_spec);
1254  if (timeout_ms < 0) {
1255  timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
1256  }
1257 
1258  if (action_meta != NULL) {
1259  g_hash_table_destroy(action_meta);
1260  }
1261  return timeout_ms;
1262 }
1263 
1264 enum action_tasks
1265 get_complex_task(const pe_resource_t *rsc, const char *name)
1266 {
1267  enum action_tasks task = text2task(name);
1268 
1269  if ((rsc != NULL) && (rsc->variant == pe_native)) {
1270  switch (task) {
1271  case stopped_rsc:
1272  case started_rsc:
1273  case action_demoted:
1274  case action_promoted:
1275  crm_trace("Folding %s back into its atomic counterpart for %s",
1276  name, rsc->id);
1277  --task;
1278  break;
1279  default:
1280  break;
1281  }
1282  }
1283  return task;
1284 }
1285 
1297 pe_action_t *
1298 find_first_action(const GList *input, const char *uuid, const char *task,
1299  const pe_node_t *on_node)
1300 {
1301  CRM_CHECK(uuid || task, return NULL);
1302 
1303  for (const GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1304  pe_action_t *action = (pe_action_t *) gIter->data;
1305 
1306  if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1307  continue;
1308 
1309  } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1310  continue;
1311 
1312  } else if (on_node == NULL) {
1313  return action;
1314 
1315  } else if (action->node == NULL) {
1316  continue;
1317 
1318  } else if (on_node->details == action->node->details) {
1319  return action;
1320  }
1321  }
1322 
1323  return NULL;
1324 }
1325 
1326 GList *
1327 find_actions(GList *input, const char *key, const pe_node_t *on_node)
1328 {
1329  GList *gIter = input;
1330  GList *result = NULL;
1331 
1332  CRM_CHECK(key != NULL, return NULL);
1333 
1334  for (; gIter != NULL; gIter = gIter->next) {
1335  pe_action_t *action = (pe_action_t *) gIter->data;
1336 
1337  if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1338  continue;
1339 
1340  } else if (on_node == NULL) {
1341  crm_trace("Action %s matches (ignoring node)", key);
1342  result = g_list_prepend(result, action);
1343 
1344  } else if (action->node == NULL) {
1345  crm_trace("Action %s matches (unallocated, assigning to %s)",
1346  key, pe__node_name(on_node));
1347 
1348  action->node = pe__copy_node(on_node);
1349  result = g_list_prepend(result, action);
1350 
1351  } else if (on_node->details == action->node->details) {
1352  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1353  result = g_list_prepend(result, action);
1354  }
1355  }
1356 
1357  return result;
1358 }
1359 
1360 GList *
1361 find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1362 {
1363  GList *result = NULL;
1364 
1365  CRM_CHECK(key != NULL, return NULL);
1366 
1367  if (on_node == NULL) {
1368  return NULL;
1369  }
1370 
1371  for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1372  pe_action_t *action = (pe_action_t *) gIter->data;
1373 
1374  if ((action->node != NULL)
1375  && pcmk__str_eq(key, action->uuid, pcmk__str_casei)
1376  && pcmk__str_eq(on_node->details->id, action->node->details->id,
1377  pcmk__str_casei)) {
1378 
1379  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1380  result = g_list_prepend(result, action);
1381  }
1382  }
1383 
1384  return result;
1385 }
1386 
1399 GList *
1401  const char *task, bool require_node)
1402 {
1403  GList *result = NULL;
1404  char *key = pcmk__op_key(rsc->id, task, 0);
1405 
1406  if (require_node) {
1407  result = find_actions_exact(rsc->actions, key, node);
1408  } else {
1409  result = find_actions(rsc->actions, key, node);
1410  }
1411  free(key);
1412  return result;
1413 }
1414 
1425 char *
1427 {
1428  const char *change = NULL;
1429 
1430  switch (flag) {
1431  case pe_action_runnable:
1433  change = "unrunnable";
1434  break;
1435  case pe_action_optional:
1436  change = "required";
1437  break;
1438  default:
1439  // Bug: caller passed unsupported flag
1440  CRM_CHECK(change != NULL, change = "");
1441  break;
1442  }
1443  return crm_strdup_printf("%s%s%s %s", change,
1444  (action->rsc == NULL)? "" : " ",
1445  (action->rsc == NULL)? "" : action->rsc->id,
1446  action->task);
1447 }
1448 
1449 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
1450 {
1451  if (action->reason != NULL && overwrite) {
1452  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
1453  action->uuid, action->reason, pcmk__s(reason, "(none)"));
1454  } else if (action->reason == NULL) {
1455  pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
1456  action->uuid, pcmk__s(reason, "(none)"));
1457  } else {
1458  // crm_assert(action->reason != NULL && !overwrite);
1459  return;
1460  }
1461 
1462  pcmk__str_update(&action->reason, reason);
1463 }
1464 
1475 pe_action_t *
1478 {
1479  char *key = NULL;
1480 
1481  CRM_ASSERT(rsc && node);
1482  key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
1483  return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
1484  data_set);
1485 }
1486 
1487 #define sort_return(an_int, why) do { \
1488  free(a_uuid); \
1489  free(b_uuid); \
1490  crm_trace("%s (%d) %c %s (%d) : %s", \
1491  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1492  b_xml_id, b_call_id, why); \
1493  return an_int; \
1494  } while(0)
1495 
1496 int
1497 pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b,
1498  bool same_node_default)
1499 {
1500  int a_call_id = -1;
1501  int b_call_id = -1;
1502 
1503  char *a_uuid = NULL;
1504  char *b_uuid = NULL;
1505 
1506  const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1507  const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1508 
1509  const char *a_node = crm_element_value(xml_a, XML_LRM_ATTR_TARGET);
1510  const char *b_node = crm_element_value(xml_b, XML_LRM_ATTR_TARGET);
1511  bool same_node = true;
1512 
1513  /* @COMPAT The on_node attribute was added to last_failure as of 1.1.13 (via
1514  * 8b3ca1c) and the other entries as of 1.1.12 (via 0b07b5c).
1515  *
1516  * In case that any of the lrm_rsc_op entries doesn't have on_node
1517  * attribute, we need to explicitly tell whether the two operations are on
1518  * the same node.
1519  */
1520  if (a_node == NULL || b_node == NULL) {
1521  same_node = same_node_default;
1522 
1523  } else {
1524  same_node = pcmk__str_eq(a_node, b_node, pcmk__str_casei);
1525  }
1526 
1527  if (same_node && pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_none)) {
1528  /* We have duplicate lrm_rsc_op entries in the status
1529  * section which is unlikely to be a good thing
1530  * - we can handle it easily enough, but we need to get
1531  * to the bottom of why it's happening.
1532  */
1533  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1534  sort_return(0, "duplicate");
1535  }
1536 
1537  crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1538  crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1539 
1540  if (a_call_id == -1 && b_call_id == -1) {
1541  /* both are pending ops so it doesn't matter since
1542  * stops are never pending
1543  */
1544  sort_return(0, "pending");
1545 
1546  } else if (same_node && a_call_id >= 0 && a_call_id < b_call_id) {
1547  sort_return(-1, "call id");
1548 
1549  } else if (same_node && b_call_id >= 0 && a_call_id > b_call_id) {
1550  sort_return(1, "call id");
1551 
1552  } else if (a_call_id >= 0 && b_call_id >= 0
1553  && (!same_node || a_call_id == b_call_id)) {
1554  /*
1555  * The op and last_failed_op are the same
1556  * Order on last-rc-change
1557  */
1558  time_t last_a = -1;
1559  time_t last_b = -1;
1560 
1563 
1564  crm_trace("rc-change: %lld vs %lld",
1565  (long long) last_a, (long long) last_b);
1566  if (last_a >= 0 && last_a < last_b) {
1567  sort_return(-1, "rc-change");
1568 
1569  } else if (last_b >= 0 && last_a > last_b) {
1570  sort_return(1, "rc-change");
1571  }
1572  sort_return(0, "rc-change");
1573 
1574  } else {
1575  /* One of the inputs is a pending operation
1576  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1577  */
1578 
1579  int a_id = -1;
1580  int b_id = -1;
1581 
1582  const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1583  const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1584 
1585  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1586  if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1587  NULL)) {
1588  sort_return(0, "bad magic a");
1589  }
1590  if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1591  NULL)) {
1592  sort_return(0, "bad magic b");
1593  }
1594  /* try to determine the relative age of the operation...
1595  * some pending operations (e.g. a start) may have been superseded
1596  * by a subsequent stop
1597  *
1598  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1599  */
1600  if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1601  /*
1602  * some of the logic in here may be redundant...
1603  *
1604  * if the UUID from the TE doesn't match then one better
1605  * be a pending operation.
1606  * pending operations don't survive between elections and joins
1607  * because we query the LRM directly
1608  */
1609 
1610  if (b_call_id == -1) {
1611  sort_return(-1, "transition + call");
1612 
1613  } else if (a_call_id == -1) {
1614  sort_return(1, "transition + call");
1615  }
1616 
1617  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1618  sort_return(-1, "transition");
1619 
1620  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1621  sort_return(1, "transition");
1622  }
1623  }
1624 
1625  /* we should never end up here */
1626  CRM_CHECK(FALSE, sort_return(0, "default"));
1627 }
1628 
1629 gint
1630 sort_op_by_callid(gconstpointer a, gconstpointer b)
1631 {
1632  const xmlNode *xml_a = a;
1633  const xmlNode *xml_b = b;
1634 
1635  return pe__is_newer_op(xml_a, xml_b, true);
1636 }
1637 
1649 pe_action_t *
1650 pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional,
1651  bool runnable)
1652 {
1653  pe_action_t *action = NULL;
1654 
1655  CRM_ASSERT((rsc != NULL) && (task != NULL));
1656 
1657  action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0), task, NULL,
1658  optional, TRUE, rsc->cluster);
1660  if (runnable) {
1662  }
1663  return action;
1664 }
1665 
1675 void
1677 {
1678  char *name = NULL;
1679 
1680  CRM_ASSERT((action != NULL) && (action->meta != NULL));
1681 
1682  name = strdup(XML_ATTR_TE_TARGET_RC);
1683  CRM_ASSERT (name != NULL);
1684 
1685  g_hash_table_insert(action->meta, name, pcmk__itoa(expected_result));
1686 }
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:273
#define LOG_TRACE
Definition: logging.h:37
#define pe_rsc_starting
Definition: pe_types.h:298
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:335
pe_quorum_policy
Definition: pe_types.h:79
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:172
A dumping ground.
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
Definition: pe_actions.c:1327
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:96
#define crm_notice(fmt, args...)
Definition: logging.h:379
#define CRMD_ACTION_MIGRATED
Definition: crm.h:172
xmlNode * ops_xml
Definition: pe_types.h:351
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:49
char data[0]
Definition: cpg.c:55
#define XML_OP_ATTR_DIGESTS_ALL
Definition: msg_xml.h:275
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:89
#define CRM_OP_FENCE
Definition: crm.h:144
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:360
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:424
#define PCMK_STONITH_PROVIDES
Definition: agents.h:48
pe_resource_t * container
Definition: pe_types.h:412
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:933
#define XML_ATTR_TYPE
Definition: msg_xml.h:151
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition: msg_xml.h:415
struct crm_time_s crm_time_t
Definition: iso8601.h:32
enum rsc_role_e role
Definition: pe_types.h:402
GList * children
Definition: pe_types.h:409
int priority_fencing_delay
Definition: pe_types.h:213
xmlNode * op_defaults
Definition: pe_types.h:189
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2521
enum rsc_role_e next_role
Definition: pe_types.h:403
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1298
#define pcmk__config_err(fmt...)
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:364
GHashTable * meta
Definition: pe_types.h:405
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:309
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:141
bool pcmk_is_probe(const char *task, guint interval)
Definition: operations.c:495
#define CRMD_ACTION_PROMOTE
Definition: crm.h:180
#define PCMK__VALUE_UNFENCING
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:403
#define XML_OP_ATTR_DIGESTS_SECURE
Definition: msg_xml.h:276
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition: common.h:116
enum action_tasks text2task(const char *task)
Definition: common.c:349
GList * actions
Definition: pe_types.h:187
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
Definition: pe_actions.c:1218
#define RSC_START
Definition: crm.h:199
xmlNode * find_rsc_op_entry(const pe_resource_t *rsc, const char *key)
Definition: pe_actions.c:145
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:270
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:532
#define pe_flag_have_quorum
Definition: pe_types.h:111
char * reason
Definition: pe_types.h:440
void pe__add_action_expected_result(pe_action_t *action, int expected_result)
Definition: pe_actions.c:1676
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:77
GList * resources
Definition: pe_types.h:181
GList * nodes
Definition: pe_types.h:180
#define CRMD_ACTION_START
Definition: crm.h:174
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1650
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:222
const char * role2text(enum rsc_role_e role)
Definition: common.c:450
#define CRMD_ACTION_STOP
Definition: crm.h:177
#define CRMD_ACTION_DEMOTE
Definition: crm.h:182
GList * find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
Definition: pe_actions.c:1361
pe_action_flags
Definition: pe_types.h:316
bool pe_can_fence(const pe_working_set_t *data_set, const pe_node_t *node)
Definition: utils.c:36
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, const pe_node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set)
Create or update an action object.
Definition: pe_actions.c:942
#define XML_ATTR_OP
Definition: msg_xml.h:153
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: pe_actions.c:1084
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition: pe_actions.c:1400
#define XML_ATTR_ID
Definition: msg_xml.h:147
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: pe_actions.c:979
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:177
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:98
#define crm_trace(fmt, args...)
Definition: logging.h:383
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:172
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:113
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1217
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * meta
Definition: pe_types.h:447
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
const char * stonith_action
Definition: pe_types.h:166
struct pe_node_shared_s * details
Definition: pe_types.h:268
const char * op_name
Definition: common.h:188
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:283
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:927
#define pe_rsc_needs_fencing
Definition: pe_types.h:312
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Definition: pe_types.h:373
const char * uname
Definition: pe_types.h:232
pe_working_set_t * data_set
#define XML_TAG_META_SETS
Definition: msg_xml.h:223
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1193
Internal state tracking when creating graph.
Definition: pe_types.h:342
char * clone_name
Definition: pe_types.h:348
#define pe_flag_stonith_enabled
Definition: pe_types.h:115
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition: nvpair.c:617
GList * actions
Definition: pe_types.h:391
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:76
char * pe__action2reason(const pe_action_t *action, enum pe_action_flags flag)
Definition: pe_actions.c:1426
enum rsc_role_e text2role(const char *role)
Definition: common.c:479
op_digest_cache_t * pe__compare_fencing_digest(pe_resource_t *rsc, const char *agent, pe_node_t *node, pe_working_set_t *data_set)
Definition: pe_digest.c:533
enum pe_obj_types variant
Definition: pe_types.h:356
long long crm_time_get_seconds(const crm_time_t *dt)
Definition: iso8601.c:316
#define RSC_ROLE_PROMOTED_S
Definition: common.h:114
const char * id
Definition: pe_types.h:231
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:42
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:318
#define pe_rsc_fence_device
Definition: pe_types.h:279
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1449
const char * standard
Definition: common.h:182
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
pcmk__action_result_t result
Definition: pcmk_fence.c:35
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:500
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:213
GHashTable * node_hash
Definition: common.h:193
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:271
#define RSC_PROMOTE
Definition: crm.h:205
xmlNode * input
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1166
This structure contains everything that makes up a single output formatter.
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:436
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:313
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:327
#define CRMD_ACTION_MIGRATE
Definition: crm.h:171
#define pe_rsc_needs_unfencing
Definition: pe_types.h:313
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:83
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Parse a transition magic string into its constituent parts.
Definition: operations.c:209
#define pe_rsc_stopping
Definition: pe_types.h:301
#define PCMK__VALUE_NOTHING
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:271
pe_working_set_t * cluster
Definition: pe_types.h:353
#define sort_return(an_int, why)
Definition: pe_actions.c:1487
#define pe_rsc_needs_quorum
Definition: pe_types.h:311
bool pe__resource_is_remote_conn(const pe_resource_t *rsc, const pe_working_set_t *data_set)
Definition: remote.c:17
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition: utils.c:737
enum action_tasks get_complex_task(const pe_resource_t *rsc, const char *name)
Definition: pe_actions.c:1265
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
Definition: pe_actions.c:1497
#define pe_flag_enable_unfencing
Definition: pe_types.h:117
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:317
void pe_free_action(pe_action_t *action)
Definition: pe_actions.c:1196
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:50
GHashTable * singletons
Definition: pe_types.h:178
#define ID(x)
Definition: msg_xml.h:480
unsigned long long flags
Definition: pe_types.h:169
#define pe_err(fmt...)
Definition: internal.h:52
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Definition: pe_actions.c:1476
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1630
#define CRM_OP_LRM_DELETE
Definition: crm.h:149
enum node_type type
Definition: pe_types.h:233
crm_time_t * now
Definition: pe_types.h:161
#define crm_info(fmt, args...)
Definition: logging.h:380
#define pe_rsc_managed
Definition: pe_types.h:273
gboolean online
Definition: pe_types.h:236
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:428
action_tasks
Definition: common.h:61
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:282
char * id
Definition: pe_types.h:347
#define CRMD_ACTION_STATUS
Definition: crm.h:188
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2547
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150