pacemaker  2.1.5-b7adf64e51
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, xmlNode *xml_obj,
21  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, pe_resource_t *rsc, const pe_node_t *node,
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, 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, xmlNode *xml_obj, guint interval_ms,
521  crm_time_t *now, long long *start_delay)
522 {
523  long long result = 0;
524  guint interval_sec = interval_ms / 1000;
525  crm_time_t *origin = NULL;
526 
527  // Ignore unspecified values and non-recurring operations
528  if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
529  return false;
530  }
531 
532  // Parse interval origin from text
533  origin = crm_time_new(value);
534  if (origin == NULL) {
535  pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
536  "'%s' because '%s' is not valid",
537  (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
538  return false;
539  }
540 
541  // Get seconds since origin (negative if origin is in the future)
543  crm_time_free(origin);
544 
545  // Calculate seconds from closest interval to now
546  result = result % interval_sec;
547 
548  // Calculate seconds remaining until next interval
549  result = ((result <= 0)? 0 : interval_sec) - result;
550  crm_info("Calculated a start delay of %llds for operation '%s'",
551  result,
552  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
553 
554  if (start_delay != NULL) {
555  *start_delay = result * 1000; // milliseconds
556  }
557  return true;
558 }
559 
560 static int
561 unpack_start_delay(const char *value, GHashTable *meta)
562 {
563  int start_delay = 0;
564 
565  if (value != NULL) {
566  start_delay = crm_get_msec(value);
567 
568  if (start_delay < 0) {
569  start_delay = 0;
570  }
571 
572  if (meta) {
573  g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
574  pcmk__itoa(start_delay));
575  }
576  }
577 
578  return start_delay;
579 }
580 
581 static xmlNode *
582 find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
583 {
584  guint interval_ms = 0;
585  guint min_interval_ms = G_MAXUINT;
586  const char *name = NULL;
587  const char *interval_spec = NULL;
588  xmlNode *op = NULL;
589  xmlNode *operation = NULL;
590 
591  for (operation = pcmk__xe_first_child(rsc->ops_xml);
592  operation != NULL;
593  operation = pcmk__xe_next(operation)) {
594 
595  if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
596  bool enabled = false;
597 
598  name = crm_element_value(operation, "name");
599  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
600  if (!include_disabled && pcmk__xe_get_bool_attr(operation, "enabled", &enabled) == pcmk_rc_ok &&
601  !enabled) {
602  continue;
603  }
604 
605  if (!pcmk__str_eq(name, RSC_STATUS, pcmk__str_casei)) {
606  continue;
607  }
608 
609  interval_ms = crm_parse_interval_spec(interval_spec);
610 
611  if (interval_ms && (interval_ms < min_interval_ms)) {
612  min_interval_ms = interval_ms;
613  op = operation;
614  }
615  }
616  }
617 
618  return op;
619 }
620 
634 static void
635 unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
636  pe_working_set_t * data_set, guint interval_ms)
637 {
638  int timeout_ms = 0;
639  const char *value = NULL;
640  bool is_probe = false;
641 
642  pe_rsc_eval_data_t rsc_rule_data = {
644  .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER),
645  .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE)
646  };
647 
648  pe_op_eval_data_t op_rule_data = {
649  .op_name = action->task,
650  .interval = interval_ms
651  };
652 
653  pe_rule_eval_data_t rule_data = {
654  .node_hash = NULL,
655  .role = RSC_ROLE_UNKNOWN,
656  .now = data_set->now,
657  .match_data = NULL,
658  .rsc_data = &rsc_rule_data,
659  .op_data = &op_rule_data
660  };
661 
662  CRM_CHECK(action && action->rsc, return);
663 
664  is_probe = pcmk_is_probe(action->task, interval_ms);
665 
666  // Cluster-wide <op_defaults> <meta_attributes>
668  action->meta, NULL, FALSE, data_set);
669 
670  // Determine probe default timeout differently
671  if (is_probe) {
672  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
673 
674  if (min_interval_mon) {
675  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
676  if (value) {
677  crm_trace("\t%s: Setting default timeout to minimum-interval "
678  "monitor's timeout '%s'", action->uuid, value);
679  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
680  strdup(value));
681  }
682  }
683  }
684 
685  if (xml_obj) {
686  xmlAttrPtr xIter = NULL;
687 
688  // <op> <meta_attributes> take precedence over defaults
689  pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, &rule_data,
690  action->meta, NULL, TRUE, data_set);
691 
692  /* Anything set as an <op> XML property has highest precedence.
693  * This ensures we use the name and interval from the <op> tag.
694  */
695  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
696  const char *prop_name = (const char *)xIter->name;
697  const char *prop_value = crm_element_value(xml_obj, prop_name);
698 
699  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
700  }
701  }
702 
703  g_hash_table_remove(action->meta, "id");
704 
705  // Normalize interval to milliseconds
706  if (interval_ms > 0) {
707  g_hash_table_replace(action->meta, strdup(XML_LRM_ATTR_INTERVAL),
708  crm_strdup_printf("%u", interval_ms));
709  } else {
710  g_hash_table_remove(action->meta, XML_LRM_ATTR_INTERVAL);
711  }
712 
713  /*
714  * Timeout order of precedence:
715  * 1. pcmk_monitor_timeout (if rsc has pcmk_ra_cap_fence_params
716  * and task is start or a probe; pcmk_monitor_timeout works
717  * by default for a recurring monitor)
718  * 2. explicit op timeout on the primitive
719  * 3. default op timeout
720  * a. if probe, then min-interval monitor's timeout
721  * b. else, in XML_CIB_TAG_OPCONFIG
722  * 4. CRM_DEFAULT_OP_TIMEOUT_S
723  *
724  * #1 overrides general rule of <op> XML property having highest
725  * precedence.
726  */
727  if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
729  && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
730  || is_probe)) {
731 
732  GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
733 
734  value = g_hash_table_lookup(params, "pcmk_monitor_timeout");
735 
736  if (value) {
737  crm_trace("\t%s: Setting timeout to pcmk_monitor_timeout '%s', "
738  "overriding default", action->uuid, value);
739  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
740  strdup(value));
741  }
742  }
743 
744  // Normalize timeout to positive milliseconds
745  value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
746  timeout_ms = unpack_timeout(value);
747  g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
748  pcmk__itoa(timeout_ms));
749 
750  if (!pcmk__strcase_any_of(action->task, RSC_START, RSC_PROMOTE, NULL)) {
751  action->needs = rsc_req_nothing;
752  value = "nothing (not start or promote)";
753 
754  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
755  action->needs = rsc_req_stonith;
756  value = "fencing";
757 
758  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
759  action->needs = rsc_req_quorum;
760  value = "quorum";
761 
762  } else {
763  action->needs = rsc_req_nothing;
764  value = "nothing";
765  }
766  pe_rsc_trace(action->rsc, "%s requires %s", action->uuid, value);
767 
768  value = unpack_operation_on_fail(action);
769 
770  if (value == NULL) {
771 
772  } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
773  action->on_fail = action_fail_block;
774  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
775  value = "block"; // The above could destroy the original string
776 
777  } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
778  action->on_fail = action_fail_fence;
779  value = "node fencing";
780 
782  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
783  "operation '%s' to 'stop' because 'fence' is not "
784  "valid when fencing is disabled", action->uuid);
785  action->on_fail = action_fail_stop;
786  action->fail_role = RSC_ROLE_STOPPED;
787  value = "stop resource";
788  }
789 
790  } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
791  action->on_fail = action_fail_standby;
792  value = "node standby";
793 
794  } else if (pcmk__strcase_any_of(value, "ignore", PCMK__VALUE_NOTHING,
795  NULL)) {
796  action->on_fail = action_fail_ignore;
797  value = "ignore";
798 
799  } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
800  action->on_fail = action_fail_migrate;
801  value = "force migration";
802 
803  } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
804  action->on_fail = action_fail_stop;
805  action->fail_role = RSC_ROLE_STOPPED;
806  value = "stop resource";
807 
808  } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
809  action->on_fail = action_fail_recover;
810  value = "restart (and possibly migrate)";
811 
812  } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
813  if (container) {
815  value = "restart container (and possibly migrate)";
816 
817  } else {
818  value = NULL;
819  }
820 
821  } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
822  action->on_fail = action_fail_demote;
823  value = "demote instance";
824 
825  } else {
826  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
827  value = NULL;
828  }
829 
830  /* defaults */
831  if (value == NULL && container) {
833  value = "restart container (and possibly migrate) (default)";
834 
835  /* For remote nodes, ensure that any failure that results in dropping an
836  * active connection to the node results in fencing of the node.
837  *
838  * There are only two action failures that don't result in fencing.
839  * 1. probes - probe failures are expected.
840  * 2. start - a start failure indicates that an active connection does not already
841  * exist. The user can set op on-fail=fence if they really want to fence start
842  * failures. */
843  } else if (((value == NULL) || !pcmk_is_set(action->rsc->flags, pe_rsc_managed))
845  && !(pcmk__str_eq(action->task, CRMD_ACTION_STATUS, pcmk__str_casei)
846  && (interval_ms == 0))
847  && !pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
848 
849  if (!pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
850  action->on_fail = action_fail_stop;
851  action->fail_role = RSC_ROLE_STOPPED;
852  value = "stop unmanaged remote node (enforcing default)";
853 
854  } else {
856  value = "fence remote node (default)";
857  } else {
858  value = "recover remote node connection (default)";
859  }
860 
861  if (action->rsc->remote_reconnect_ms) {
862  action->fail_role = RSC_ROLE_STOPPED;
863  }
864  action->on_fail = action_fail_reset_remote;
865  }
866 
867  } else if (value == NULL && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
869  action->on_fail = action_fail_fence;
870  value = "resource fence (default)";
871 
872  } else {
873  action->on_fail = action_fail_block;
874  value = "resource block (default)";
875  }
876 
877  } else if (value == NULL) {
878  action->on_fail = action_fail_recover;
879  value = "restart (and possibly migrate) (default)";
880  }
881 
882  pe_rsc_trace(action->rsc, "%s failure handling: %s",
883  action->uuid, value);
884 
885  value = NULL;
886  if (xml_obj != NULL) {
887  value = g_hash_table_lookup(action->meta, "role_after_failure");
888  if (value) {
890  "Support for role_after_failure is deprecated and will be removed in a future release");
891  }
892  }
893  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
894  action->fail_role = text2role(value);
895  }
896  /* defaults */
897  if (action->fail_role == RSC_ROLE_UNKNOWN) {
898  if (pcmk__str_eq(action->task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
899  action->fail_role = RSC_ROLE_UNPROMOTED;
900  } else {
901  action->fail_role = RSC_ROLE_STARTED;
902  }
903  }
904  pe_rsc_trace(action->rsc, "%s failure results in: %s",
905  action->uuid, role2text(action->fail_role));
906 
907  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
908  if (value) {
909  unpack_start_delay(value, action->meta);
910  } else {
911  long long start_delay = 0;
912 
913  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
914  if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
915  &start_delay)) {
916  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
917  crm_strdup_printf("%lld", start_delay));
918  }
919  }
920 }
921 
939 pe_action_t *
940 custom_action(pe_resource_t *rsc, char *key, const char *task,
941  const pe_node_t *on_node, gboolean optional, gboolean save_action,
943 {
944  pe_action_t *action = NULL;
945 
946  CRM_ASSERT((key != NULL) && (task != NULL) && (data_set != NULL));
947 
948  if (save_action) {
949  action = find_existing_action(key, rsc, on_node, data_set);
950  }
951 
952  if (action == NULL) {
953  action = new_action(key, task, rsc, on_node, optional, save_action,
954  data_set);
955  } else {
956  free(key);
957  }
958 
959  update_action_optional(action, optional);
960 
961  if (rsc != NULL) {
962  if (action->node != NULL) {
963  unpack_action_node_attributes(action, data_set);
964  }
965 
966  update_resource_action_runnable(action, save_action, data_set);
967 
968  if (save_action) {
969  update_resource_flags_for_action(rsc, action);
970  }
971  }
972 
973  return action;
974 }
975 
976 pe_action_t *
978 {
979  pe_action_t *op = lookup_singleton(data_set, name);
980 
981  if (op == NULL) {
982  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
984  }
985  return op;
986 }
987 
988 static GList *
989 find_unfencing_devices(GList *candidates, GList *matches)
990 {
991  for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
992  pe_resource_t *candidate = gIter->data;
993 
994  if (candidate->children != NULL) {
995  matches = find_unfencing_devices(candidate->children, matches);
996 
997  } else if (!pcmk_is_set(candidate->flags, pe_rsc_fence_device)) {
998  continue;
999 
1000  } else if (pcmk_is_set(candidate->flags, pe_rsc_needs_unfencing)) {
1001  matches = g_list_prepend(matches, candidate);
1002 
1003  } else if (pcmk__str_eq(g_hash_table_lookup(candidate->meta,
1006  pcmk__str_casei)) {
1007  matches = g_list_prepend(matches, candidate);
1008  }
1009  }
1010  return matches;
1011 }
1012 
1013 static int
1014 node_priority_fencing_delay(pe_node_t * node, pe_working_set_t * data_set)
1015 {
1016  int member_count = 0;
1017  int online_count = 0;
1018  int top_priority = 0;
1019  int lowest_priority = 0;
1020  GList *gIter = NULL;
1021 
1022  // `priority-fencing-delay` is disabled
1023  if (data_set->priority_fencing_delay <= 0) {
1024  return 0;
1025  }
1026 
1027  /* No need to request a delay if the fencing target is not a normal cluster
1028  * member, for example if it's a remote node or a guest node. */
1029  if (node->details->type != node_member) {
1030  return 0;
1031  }
1032 
1033  // No need to request a delay if the fencing target is in our partition
1034  if (node->details->online) {
1035  return 0;
1036  }
1037 
1038  for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1039  pe_node_t *n = gIter->data;
1040 
1041  if (n->details->type != node_member) {
1042  continue;
1043  }
1044 
1045  member_count ++;
1046 
1047  if (n->details->online) {
1048  online_count++;
1049  }
1050 
1051  if (member_count == 1
1052  || n->details->priority > top_priority) {
1053  top_priority = n->details->priority;
1054  }
1055 
1056  if (member_count == 1
1057  || n->details->priority < lowest_priority) {
1058  lowest_priority = n->details->priority;
1059  }
1060  }
1061 
1062  // No need to delay if we have more than half of the cluster members
1063  if (online_count > member_count / 2) {
1064  return 0;
1065  }
1066 
1067  /* All the nodes have equal priority.
1068  * Any configured corresponding `pcmk_delay_base/max` will be applied. */
1069  if (lowest_priority == top_priority) {
1070  return 0;
1071  }
1072 
1073  if (node->details->priority < top_priority) {
1074  return 0;
1075  }
1076 
1078 }
1079 
1080 pe_action_t *
1081 pe_fence_op(pe_node_t * node, const char *op, bool optional, const char *reason,
1082  bool priority_delay, pe_working_set_t * data_set)
1083 {
1084  char *op_key = NULL;
1085  pe_action_t *stonith_op = NULL;
1086 
1087  if(op == NULL) {
1088  op = data_set->stonith_action;
1089  }
1090 
1091  op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
1092 
1093  stonith_op = lookup_singleton(data_set, op_key);
1094  if(stonith_op == NULL) {
1095  stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
1096 
1097  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1098  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
1099  add_hash_param(stonith_op->meta, "stonith_action", op);
1100 
1102  /* Extra work to detect device changes
1103  */
1104  GString *digests_all = g_string_sized_new(1024);
1105  GString *digests_secure = g_string_sized_new(1024);
1106 
1107  GList *matches = find_unfencing_devices(data_set->resources, NULL);
1108 
1109  char *key = NULL;
1110  char *value = NULL;
1111 
1112  for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
1113  pe_resource_t *match = gIter->data;
1114  const char *agent = g_hash_table_lookup(match->meta,
1115  XML_ATTR_TYPE);
1116  op_digest_cache_t *data = NULL;
1117 
1118  data = pe__compare_fencing_digest(match, agent, node, data_set);
1119  if(data->rc == RSC_DIGEST_ALL) {
1120  optional = FALSE;
1121  crm_notice("Unfencing Pacemaker Remote node %s "
1122  "because the definition of %s changed",
1123  pe__node_name(node), match->id);
1124  if (!pcmk__is_daemon && data_set->priv != NULL) {
1125  pcmk__output_t *out = data_set->priv;
1126  out->info(out,
1127  "notice: Unfencing Pacemaker Remote node %s "
1128  "because the definition of %s changed",
1129  pe__node_name(node), match->id);
1130  }
1131  }
1132 
1133  pcmk__g_strcat(digests_all,
1134  match->id, ":", agent, ":",
1135  data->digest_all_calc, ",", NULL);
1136  pcmk__g_strcat(digests_secure,
1137  match->id, ":", agent, ":",
1138  data->digest_secure_calc, ",", NULL);
1139  }
1140  key = strdup(XML_OP_ATTR_DIGESTS_ALL);
1141  value = strdup((const char *) digests_all->str);
1142  CRM_ASSERT((key != NULL) && (value != NULL));
1143  g_hash_table_insert(stonith_op->meta, key, value);
1144  g_string_free(digests_all, TRUE);
1145 
1146  key = strdup(XML_OP_ATTR_DIGESTS_SECURE);
1147  value = strdup((const char *) digests_secure->str);
1148  CRM_ASSERT((key != NULL) && (value != NULL));
1149  g_hash_table_insert(stonith_op->meta, key, value);
1150  g_string_free(digests_secure, TRUE);
1151  }
1152 
1153  } else {
1154  free(op_key);
1155  }
1156 
1158 
1159  /* It's a suitable case where `priority-fencing-delay` applies.
1160  * At least add `priority-fencing-delay` field as an indicator. */
1161  && (priority_delay
1162 
1163  /* The priority delay needs to be recalculated if this function has
1164  * been called by schedule_fencing_and_shutdowns() after node
1165  * priority has already been calculated by native_add_running().
1166  */
1167  || g_hash_table_lookup(stonith_op->meta,
1169 
1170  /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
1171  * the targeting node. So that it takes precedence over any possible
1172  * `pcmk_delay_base/max`.
1173  */
1174  char *delay_s = pcmk__itoa(node_priority_fencing_delay(node, data_set));
1175 
1176  g_hash_table_insert(stonith_op->meta,
1178  delay_s);
1179  }
1180 
1181  if(optional == FALSE && pe_can_fence(data_set, node)) {
1183  pe_action_set_reason(stonith_op, reason, false);
1184 
1185  } else if(reason && stonith_op->reason == NULL) {
1186  stonith_op->reason = strdup(reason);
1187  }
1188 
1189  return stonith_op;
1190 }
1191 
1192 void
1194 {
1195  if (action == NULL) {
1196  return;
1197  }
1198  g_list_free_full(action->actions_before, free); /* pe_action_wrapper_t* */
1199  g_list_free_full(action->actions_after, free); /* pe_action_wrapper_t* */
1200  if (action->extra) {
1201  g_hash_table_destroy(action->extra);
1202  }
1203  if (action->meta) {
1204  g_hash_table_destroy(action->meta);
1205  }
1206  free(action->cancel_task);
1207  free(action->reason);
1208  free(action->task);
1209  free(action->uuid);
1210  free(action->node);
1211  free(action);
1212 }
1213 
1214 int
1216 {
1217  xmlNode *child = NULL;
1218  GHashTable *action_meta = NULL;
1219  const char *timeout_spec = NULL;
1220  int timeout_ms = 0;
1221 
1222  pe_rule_eval_data_t rule_data = {
1223  .node_hash = NULL,
1224  .role = RSC_ROLE_UNKNOWN,
1225  .now = data_set->now,
1226  .match_data = NULL,
1227  .rsc_data = NULL,
1228  .op_data = NULL
1229  };
1230 
1231  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
1232  child != NULL; child = crm_next_same_xml(child)) {
1233  if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
1234  pcmk__str_casei)) {
1235  timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
1236  break;
1237  }
1238  }
1239 
1240  if (timeout_spec == NULL && data_set->op_defaults) {
1241  action_meta = pcmk__strkey_table(free, free);
1243  &rule_data, action_meta, NULL, FALSE, data_set);
1244  timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
1245  }
1246 
1247  // @TODO check meta-attributes
1248  // @TODO maybe use min-interval monitor timeout as default for monitors
1249 
1250  timeout_ms = crm_get_msec(timeout_spec);
1251  if (timeout_ms < 0) {
1252  timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
1253  }
1254 
1255  if (action_meta != NULL) {
1256  g_hash_table_destroy(action_meta);
1257  }
1258  return timeout_ms;
1259 }
1260 
1261 enum action_tasks
1262 get_complex_task(pe_resource_t * rsc, const char *name, gboolean allow_non_atomic)
1263 {
1264  enum action_tasks task = text2task(name);
1265 
1266  if (rsc == NULL) {
1267  return task;
1268 
1269  } else if (allow_non_atomic == FALSE || 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", name, rsc->id);
1276  return task - 1;
1277  default:
1278  break;
1279  }
1280  }
1281  return task;
1282 }
1283 
1295 pe_action_t *
1296 find_first_action(const GList *input, const char *uuid, const char *task,
1297  const pe_node_t *on_node)
1298 {
1299  CRM_CHECK(uuid || task, return NULL);
1300 
1301  for (const GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1302  pe_action_t *action = (pe_action_t *) gIter->data;
1303 
1304  if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1305  continue;
1306 
1307  } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1308  continue;
1309 
1310  } else if (on_node == NULL) {
1311  return action;
1312 
1313  } else if (action->node == NULL) {
1314  continue;
1315 
1316  } else if (on_node->details == action->node->details) {
1317  return action;
1318  }
1319  }
1320 
1321  return NULL;
1322 }
1323 
1324 GList *
1325 find_actions(GList *input, const char *key, const pe_node_t *on_node)
1326 {
1327  GList *gIter = input;
1328  GList *result = NULL;
1329 
1330  CRM_CHECK(key != NULL, return NULL);
1331 
1332  for (; gIter != NULL; gIter = gIter->next) {
1333  pe_action_t *action = (pe_action_t *) gIter->data;
1334 
1335  if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1336  continue;
1337 
1338  } else if (on_node == NULL) {
1339  crm_trace("Action %s matches (ignoring node)", key);
1340  result = g_list_prepend(result, action);
1341 
1342  } else if (action->node == NULL) {
1343  crm_trace("Action %s matches (unallocated, assigning to %s)",
1344  key, pe__node_name(on_node));
1345 
1346  action->node = pe__copy_node(on_node);
1347  result = g_list_prepend(result, action);
1348 
1349  } else if (on_node->details == action->node->details) {
1350  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1351  result = g_list_prepend(result, action);
1352  }
1353  }
1354 
1355  return result;
1356 }
1357 
1358 GList *
1359 find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
1360 {
1361  GList *result = NULL;
1362 
1363  CRM_CHECK(key != NULL, return NULL);
1364 
1365  if (on_node == NULL) {
1366  return NULL;
1367  }
1368 
1369  for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1370  pe_action_t *action = (pe_action_t *) gIter->data;
1371 
1372  if ((action->node != NULL)
1373  && pcmk__str_eq(key, action->uuid, pcmk__str_casei)
1374  && pcmk__str_eq(on_node->details->id, action->node->details->id,
1375  pcmk__str_casei)) {
1376 
1377  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1378  result = g_list_prepend(result, action);
1379  }
1380  }
1381 
1382  return result;
1383 }
1384 
1397 GList *
1399  const char *task, bool require_node)
1400 {
1401  GList *result = NULL;
1402  char *key = pcmk__op_key(rsc->id, task, 0);
1403 
1404  if (require_node) {
1405  result = find_actions_exact(rsc->actions, key, node);
1406  } else {
1407  result = find_actions(rsc->actions, key, node);
1408  }
1409  free(key);
1410  return result;
1411 }
1412 
1423 char *
1425 {
1426  const char *change = NULL;
1427 
1428  switch (flag) {
1429  case pe_action_runnable:
1431  change = "unrunnable";
1432  break;
1433  case pe_action_optional:
1434  change = "required";
1435  break;
1436  default:
1437  // Bug: caller passed unsupported flag
1438  CRM_CHECK(change != NULL, change = "");
1439  break;
1440  }
1441  return crm_strdup_printf("%s%s%s %s", change,
1442  (action->rsc == NULL)? "" : " ",
1443  (action->rsc == NULL)? "" : action->rsc->id,
1444  action->task);
1445 }
1446 
1447 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
1448 {
1449  if (action->reason != NULL && overwrite) {
1450  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
1451  action->uuid, action->reason, pcmk__s(reason, "(none)"));
1452  } else if (action->reason == NULL) {
1453  pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
1454  action->uuid, pcmk__s(reason, "(none)"));
1455  } else {
1456  // crm_assert(action->reason != NULL && !overwrite);
1457  return;
1458  }
1459 
1460  pcmk__str_update(&action->reason, reason);
1461 }
1462 
1472 pe_action_t *
1475 {
1476  char *key = NULL;
1477 
1478  CRM_ASSERT(rsc && node);
1479  key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
1480  return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
1481  data_set);
1482 }
1483 
1484 #define sort_return(an_int, why) do { \
1485  free(a_uuid); \
1486  free(b_uuid); \
1487  crm_trace("%s (%d) %c %s (%d) : %s", \
1488  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1489  b_xml_id, b_call_id, why); \
1490  return an_int; \
1491  } while(0)
1492 
1493 int
1494 pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b,
1495  bool same_node_default)
1496 {
1497  int a_call_id = -1;
1498  int b_call_id = -1;
1499 
1500  char *a_uuid = NULL;
1501  char *b_uuid = NULL;
1502 
1503  const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1504  const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1505 
1506  const char *a_node = crm_element_value(xml_a, XML_LRM_ATTR_TARGET);
1507  const char *b_node = crm_element_value(xml_b, XML_LRM_ATTR_TARGET);
1508  bool same_node = true;
1509 
1510  /* @COMPAT The on_node attribute was added to last_failure as of 1.1.13 (via
1511  * 8b3ca1c) and the other entries as of 1.1.12 (via 0b07b5c).
1512  *
1513  * In case that any of the lrm_rsc_op entries doesn't have on_node
1514  * attribute, we need to explicitly tell whether the two operations are on
1515  * the same node.
1516  */
1517  if (a_node == NULL || b_node == NULL) {
1518  same_node = same_node_default;
1519 
1520  } else {
1521  same_node = pcmk__str_eq(a_node, b_node, pcmk__str_casei);
1522  }
1523 
1524  if (same_node && pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_none)) {
1525  /* We have duplicate lrm_rsc_op entries in the status
1526  * section which is unlikely to be a good thing
1527  * - we can handle it easily enough, but we need to get
1528  * to the bottom of why it's happening.
1529  */
1530  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1531  sort_return(0, "duplicate");
1532  }
1533 
1534  crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1535  crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1536 
1537  if (a_call_id == -1 && b_call_id == -1) {
1538  /* both are pending ops so it doesn't matter since
1539  * stops are never pending
1540  */
1541  sort_return(0, "pending");
1542 
1543  } else if (same_node && a_call_id >= 0 && a_call_id < b_call_id) {
1544  sort_return(-1, "call id");
1545 
1546  } else if (same_node && b_call_id >= 0 && a_call_id > b_call_id) {
1547  sort_return(1, "call id");
1548 
1549  } else if (a_call_id >= 0 && b_call_id >= 0
1550  && (!same_node || a_call_id == b_call_id)) {
1551  /*
1552  * The op and last_failed_op are the same
1553  * Order on last-rc-change
1554  */
1555  time_t last_a = -1;
1556  time_t last_b = -1;
1557 
1560 
1561  crm_trace("rc-change: %lld vs %lld",
1562  (long long) last_a, (long long) last_b);
1563  if (last_a >= 0 && last_a < last_b) {
1564  sort_return(-1, "rc-change");
1565 
1566  } else if (last_b >= 0 && last_a > last_b) {
1567  sort_return(1, "rc-change");
1568  }
1569  sort_return(0, "rc-change");
1570 
1571  } else {
1572  /* One of the inputs is a pending operation
1573  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1574  */
1575 
1576  int a_id = -1;
1577  int b_id = -1;
1578 
1579  const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1580  const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1581 
1582  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1583  if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1584  NULL)) {
1585  sort_return(0, "bad magic a");
1586  }
1587  if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1588  NULL)) {
1589  sort_return(0, "bad magic b");
1590  }
1591  /* try to determine the relative age of the operation...
1592  * some pending operations (e.g. a start) may have been superseded
1593  * by a subsequent stop
1594  *
1595  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1596  */
1597  if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1598  /*
1599  * some of the logic in here may be redundant...
1600  *
1601  * if the UUID from the TE doesn't match then one better
1602  * be a pending operation.
1603  * pending operations don't survive between elections and joins
1604  * because we query the LRM directly
1605  */
1606 
1607  if (b_call_id == -1) {
1608  sort_return(-1, "transition + call");
1609 
1610  } else if (a_call_id == -1) {
1611  sort_return(1, "transition + call");
1612  }
1613 
1614  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1615  sort_return(-1, "transition");
1616 
1617  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1618  sort_return(1, "transition");
1619  }
1620  }
1621 
1622  /* we should never end up here */
1623  CRM_CHECK(FALSE, sort_return(0, "default"));
1624 }
1625 
1626 gint
1627 sort_op_by_callid(gconstpointer a, gconstpointer b)
1628 {
1629  const xmlNode *xml_a = a;
1630  const xmlNode *xml_b = b;
1631 
1632  return pe__is_newer_op(xml_a, xml_b, true);
1633 }
1634 
1646 pe_action_t *
1647 pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional,
1648  bool runnable)
1649 {
1650  pe_action_t *action = NULL;
1651 
1652  CRM_ASSERT((rsc != NULL) && (task != NULL));
1653 
1654  action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0), task, NULL,
1655  optional, TRUE, rsc->cluster);
1657  if (runnable) {
1659  }
1660  return action;
1661 }
1662 
1672 void
1674 {
1675  char *name = NULL;
1676 
1677  CRM_ASSERT((action != NULL) && (action->meta != NULL));
1678 
1679  name = strdup(XML_ATTR_TE_TARGET_RC);
1680  CRM_ASSERT (name != NULL);
1681 
1682  g_hash_table_insert(action->meta, name, pcmk__itoa(expected_result));
1683 }
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:260
#define LOG_TRACE
Definition: logging.h:37
#define pe_rsc_starting
Definition: pe_types.h:281
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:320
pe_quorum_policy
Definition: pe_types.h:63
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:156
A dumping ground.
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
Definition: pe_actions.c:1325
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define CRMD_ACTION_MIGRATED
Definition: crm.h:172
xmlNode * ops_xml
Definition: pe_types.h:333
char * pe__action2reason(pe_action_t *action, enum pe_action_flags flag)
Definition: pe_actions.c:1424
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:46
char data[0]
Definition: cpg.c:55
#define XML_OP_ATTR_DIGESTS_ALL
Definition: msg_xml.h:262
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: pe_actions.c:1473
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
#define CRM_OP_FENCE
Definition: crm.h:144
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:348
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:412
#define PCMK_STONITH_PROVIDES
Definition: agents.h:46
pe_resource_t * container
Definition: pe_types.h:387
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
#define XML_ATTR_TYPE
Definition: msg_xml.h:138
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition: msg_xml.h:403
struct crm_time_s crm_time_t
Definition: iso8601.h:32
enum rsc_role_e role
Definition: pe_types.h:377
GList * children
Definition: pe_types.h:384
int priority_fencing_delay
Definition: pe_types.h:197
xmlNode * op_defaults
Definition: pe_types.h:173
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
enum rsc_role_e next_role
Definition: pe_types.h:378
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:1296
#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:380
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:294
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:128
bool pcmk_is_probe(const char *task, guint interval)
Definition: operations.c:541
#define CRMD_ACTION_PROMOTE
Definition: crm.h:180
#define PCMK__VALUE_UNFENCING
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:391
#define XML_OP_ATTR_DIGESTS_SECURE
Definition: msg_xml.h:263
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition: common.h:116
enum action_tasks text2task(const char *task)
Definition: common.c:353
GList * actions
Definition: pe_types.h:171
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
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:1215
#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:257
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:553
#define pe_flag_have_quorum
Definition: pe_types.h:95
char * reason
Definition: pe_types.h:413
void pe__add_action_expected_result(pe_action_t *action, int expected_result)
Definition: pe_actions.c:1673
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
GList * resources
Definition: pe_types.h:165
GList * nodes
Definition: pe_types.h:164
#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:1647
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:209
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
#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:1359
pe_action_flags
Definition: pe_types.h:298
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:940
#define XML_ATTR_OP
Definition: msg_xml.h:140
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:1081
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:1398
#define XML_ATTR_ID
Definition: msg_xml.h:134
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
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:977
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:172
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:168
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:95
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1214
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * meta
Definition: pe_types.h:420
#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:150
struct pe_node_shared_s * details
Definition: pe_types.h:252
const char * op_name
Definition: common.h:189
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:270
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:948
#define pe_rsc_needs_fencing
Definition: pe_types.h:294
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
pe_working_set_t * data_set
#define XML_TAG_META_SETS
Definition: msg_xml.h:210
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1190
Internal state tracking when creating graph.
Definition: pe_types.h:324
char * clone_name
Definition: pe_types.h:330
#define pe_flag_stonith_enabled
Definition: pe_types.h:99
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:638
GList * actions
Definition: pe_types.h:366
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:76
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: pe_actions.c:1262
enum rsc_role_e text2role(const char *role)
Definition: common.c:483
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:532
enum pe_obj_types variant
Definition: pe_types.h:338
long long crm_time_get_seconds(const crm_time_t *dt)
Definition: iso8601.c:309
#define RSC_ROLE_PROMOTED_S
Definition: common.h:114
const char * id
Definition: pe_types.h:215
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:45
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:303
#define pe_rsc_fence_device
Definition: pe_types.h:263
bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
Definition: utils.c:36
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1447
const char * standard
Definition: common.h:183
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:504
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:213
GHashTable * node_hash
Definition: common.h:194
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:92
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1120
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:429
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:312
#define CRMD_ACTION_MIGRATE
Definition: crm.h:171
#define pe_rsc_needs_unfencing
Definition: pe_types.h:295
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
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:255
#define pe_rsc_stopping
Definition: pe_types.h:284
#define PCMK__VALUE_NOTHING
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:258
pe_working_set_t * cluster
Definition: pe_types.h:335
#define sort_return(an_int, why)
Definition: pe_actions.c:1484
#define pe_rsc_needs_quorum
Definition: pe_types.h:293
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
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
Definition: pe_actions.c:1494
#define pe_flag_enable_unfencing
Definition: pe_types.h:101
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:302
void pe_free_action(pe_action_t *action)
Definition: pe_actions.c:1193
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
GHashTable * singletons
Definition: pe_types.h:162
#define ID(x)
Definition: msg_xml.h:468
unsigned long long flags
Definition: pe_types.h:153
#define pe_err(fmt...)
Definition: internal.h:49
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1627
#define CRM_OP_LRM_DELETE
Definition: crm.h:149
enum node_type type
Definition: pe_types.h:217
crm_time_t * now
Definition: pe_types.h:145
#define crm_info(fmt, args...)
Definition: logging.h:362
#define pe_rsc_managed
Definition: pe_types.h:257
gboolean online
Definition: pe_types.h:220
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:416
action_tasks
Definition: common.h:61
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:269
char * id
Definition: pe_types.h:329
#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:2956
void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition: utils.c:717
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140