pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
pe_actions.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2023 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>
18 #include <crm/pengine/internal.h>
20 #include "pe_status_private.h"
21 
22 static void unpack_operation(pcmk_action_t *action, const xmlNode *xml_obj,
23  guint interval_ms);
24 
25 static void
27 {
28  if (scheduler->singletons == NULL) {
30  }
31  g_hash_table_insert(scheduler->singletons, action->uuid, action);
32 }
33 
34 static pcmk_action_t *
35 lookup_singleton(pcmk_scheduler_t *scheduler, const char *action_uuid)
36 {
37  if (scheduler->singletons == NULL) {
38  return NULL;
39  }
40  return g_hash_table_lookup(scheduler->singletons, action_uuid);
41 }
42 
54 static pcmk_action_t *
55 find_existing_action(const char *key, const pcmk_resource_t *rsc,
56  const pcmk_node_t *node, const pcmk_scheduler_t *scheduler)
57 {
58  GList *matches = NULL;
59  pcmk_action_t *action = NULL;
60 
61  /* When rsc is NULL, it would be quicker to check scheduler->singletons,
62  * but checking all scheduler->actions takes the node into account.
63  */
64  matches = find_actions(((rsc == NULL)? scheduler->actions : rsc->actions),
65  key, node);
66  if (matches == NULL) {
67  return NULL;
68  }
69  CRM_LOG_ASSERT(!pcmk__list_of_multiple(matches));
70 
71  action = matches->data;
72  g_list_free(matches);
73  return action;
74 }
75 
86 static xmlNode *
87 find_exact_action_config(const pcmk_resource_t *rsc, const char *action_name,
88  guint interval_ms, bool include_disabled)
89 {
90  for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
91  operation != NULL; operation = crm_next_same_xml(operation)) {
92 
93  bool enabled = false;
94  const char *config_name = NULL;
95  const char *interval_spec = NULL;
96 
97  // @TODO This does not consider rules, defaults, etc.
98  if (!include_disabled
99  && (pcmk__xe_get_bool_attr(operation, "enabled",
100  &enabled) == pcmk_rc_ok) && !enabled) {
101  continue;
102  }
103 
104  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
105  if (crm_parse_interval_spec(interval_spec) != interval_ms) {
106  continue;
107  }
108 
109  config_name = crm_element_value(operation, "name");
110  if (pcmk__str_eq(action_name, config_name, pcmk__str_none)) {
111  return operation;
112  }
113  }
114  return NULL;
115 }
116 
128 xmlNode *
129 pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name,
130  guint interval_ms, bool include_disabled)
131 {
132  xmlNode *action_config = NULL;
133 
134  // Try requested action first
135  action_config = find_exact_action_config(rsc, action_name, interval_ms,
136  include_disabled);
137 
138  // For migrate_to and migrate_from actions, retry with "migrate"
139  // @TODO This should be either documented or deprecated
140  if ((action_config == NULL)
142  PCMK_ACTION_MIGRATE_FROM, NULL)) {
143  action_config = find_exact_action_config(rsc, "migrate", 0,
144  include_disabled);
145  }
146 
147  return action_config;
148 }
149 
165 static pcmk_action_t *
166 new_action(char *key, const char *task, pcmk_resource_t *rsc,
167  const pcmk_node_t *node, bool optional, pcmk_scheduler_t *scheduler)
168 {
169  pcmk_action_t *action = calloc(1, sizeof(pcmk_action_t));
170 
171  CRM_ASSERT(action != NULL);
172 
173  action->rsc = rsc;
174  action->task = strdup(task); CRM_ASSERT(action->task != NULL);
175  action->uuid = key;
176 
177  if (node) {
178  action->node = pe__copy_node(node);
179  }
180 
181  if (pcmk__str_eq(task, PCMK_ACTION_LRM_DELETE, pcmk__str_casei)) {
182  // Resource history deletion for a node can be done on the DC
184  }
185 
187  if (optional) {
189  } else {
191  }
192 
193  if (rsc == NULL) {
194  action->meta = pcmk__strkey_table(free, free);
195  } else {
196  guint interval_ms = 0;
197 
198  parse_op_key(key, NULL, NULL, &interval_ms);
199  action->op_entry = pcmk__find_action_config(rsc, task, interval_ms,
200  true);
201 
202  /* If the given key is for one of the many notification pseudo-actions
203  * (pre_notify_promote, etc.), the actual action name is "notify"
204  */
205  if ((action->op_entry == NULL) && (strstr(key, "_notify_") != NULL)) {
206  action->op_entry = find_exact_action_config(rsc, PCMK_ACTION_NOTIFY,
207  0, true);
208  }
209 
210  unpack_operation(action, action->op_entry, interval_ms);
211  }
212 
213  pe_rsc_trace(rsc, "Created %s action %d (%s): %s for %s on %s",
214  (optional? "optional" : "required"),
215  scheduler->action_id, key, task,
216  ((rsc == NULL)? "no resource" : rsc->id),
217  pe__node_name(node));
218  action->id = scheduler->action_id++;
219 
220  scheduler->actions = g_list_prepend(scheduler->actions, action);
221  if (rsc == NULL) {
222  add_singleton(scheduler, action);
223  } else {
224  rsc->actions = g_list_prepend(rsc->actions, action);
225  }
226  return action;
227 }
228 
239 GHashTable *
240 pcmk__unpack_action_rsc_params(const xmlNode *action_xml,
241  GHashTable *node_attrs,
243 {
244  GHashTable *params = pcmk__strkey_table(free, free);
245 
246  pe_rule_eval_data_t rule_data = {
247  .node_hash = node_attrs,
248  .role = pcmk_role_unknown,
249  .now = scheduler->now,
250  .match_data = NULL,
251  .rsc_data = NULL,
252  .op_data = NULL
253  };
254 
256  &rule_data, params, NULL,
257  FALSE, scheduler);
258  return params;
259 }
260 
268 static void
269 update_action_optional(pcmk_action_t *action, gboolean optional)
270 {
271  // Force a non-recurring action to be optional if its resource is unmanaged
272  if ((action->rsc != NULL) && (action->node != NULL)
274  && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
275  && (g_hash_table_lookup(action->meta,
276  XML_LRM_ATTR_INTERVAL_MS) == NULL)) {
277  pe_rsc_debug(action->rsc, "%s on %s is optional (%s is unmanaged)",
278  action->uuid, pe__node_name(action->node),
279  action->rsc->id);
281  // We shouldn't clear runnable here because ... something
282 
283  // Otherwise require the action if requested
284  } else if (!optional) {
286  }
287 }
288 
289 static enum pe_quorum_policy
290 effective_quorum_policy(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
291 {
293 
295  policy = pcmk_no_quorum_ignore;
296 
298  switch (rsc->role) {
299  case pcmk_role_promoted:
301  if (rsc->next_role > pcmk_role_unpromoted) {
303  "no-quorum-policy=demote");
304  }
305  policy = pcmk_no_quorum_ignore;
306  break;
307  default:
308  policy = pcmk_no_quorum_stop;
309  break;
310  }
311  }
312  return policy;
313 }
314 
324 static void
325 update_resource_action_runnable(pcmk_action_t *action,
327 {
328  if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
329  return;
330  }
331 
332  if (action->node == NULL) {
333  pe_rsc_trace(action->rsc, "%s is unrunnable (unallocated)",
334  action->uuid);
336 
337  } else if (!pcmk_is_set(action->flags, pcmk_action_on_dc)
338  && !(action->node->details->online)
339  && (!pe__is_guest_node(action->node)
340  || action->node->details->remote_requires_reset)) {
342  do_crm_log(LOG_WARNING, "%s on %s is unrunnable (node is offline)",
343  action->uuid, pe__node_name(action->node));
344  if (pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
345  && pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_casei)
346  && !(action->node->details->unclean)) {
347  pe_fence_node(scheduler, action->node, "stop is unrunnable", false);
348  }
349 
350  } else if (!pcmk_is_set(action->flags, pcmk_action_on_dc)
351  && action->node->details->pending) {
353  do_crm_log(LOG_WARNING,
354  "Action %s on %s is unrunnable (node is pending)",
355  action->uuid, pe__node_name(action->node));
356 
357  } else if (action->needs == pcmk_requires_nothing) {
358  pe_action_set_reason(action, NULL, TRUE);
359  if (pe__is_guest_node(action->node)
360  && !pe_can_fence(scheduler, action->node)) {
361  /* An action that requires nothing usually does not require any
362  * fencing in order to be runnable. However, there is an exception:
363  * such an action cannot be completed if it is on a guest node whose
364  * host is unclean and cannot be fenced.
365  */
366  pe_rsc_debug(action->rsc, "%s on %s is unrunnable "
367  "(node's host cannot be fenced)",
368  action->uuid, pe__node_name(action->node));
370  } else {
371  pe_rsc_trace(action->rsc,
372  "%s on %s does not require fencing or quorum",
373  action->uuid, pe__node_name(action->node));
375  }
376 
377  } else {
378  switch (effective_quorum_policy(action->rsc, scheduler)) {
379  case pcmk_no_quorum_stop:
380  pe_rsc_debug(action->rsc, "%s on %s is unrunnable (no quorum)",
381  action->uuid, pe__node_name(action->node));
383  pe_action_set_reason(action, "no quorum", true);
384  break;
385 
387  if (!action->rsc->fns->active(action->rsc, TRUE)
388  || (action->rsc->next_role > action->rsc->role)) {
389  pe_rsc_debug(action->rsc,
390  "%s on %s is unrunnable (no quorum)",
391  action->uuid, pe__node_name(action->node));
393  pe_action_set_reason(action, "quorum freeze", true);
394  }
395  break;
396 
397  default:
398  //pe_action_set_reason(action, NULL, TRUE);
400  break;
401  }
402  }
403 }
404 
412 static void
413 update_resource_flags_for_action(pcmk_resource_t *rsc,
414  const pcmk_action_t *action)
415 {
416  /* @COMPAT pcmk_rsc_starting and pcmk_rsc_stopping are deprecated and unused
417  * within Pacemaker, and will eventually be removed
418  */
419  if (pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_casei)) {
421 
422  } else if (pcmk__str_eq(action->task, PCMK_ACTION_START, pcmk__str_casei)) {
423  if (pcmk_is_set(action->flags, pcmk_action_runnable)) {
425  } else {
427  }
428  }
429 }
430 
431 static bool
432 valid_stop_on_fail(const char *value)
433 {
434  return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
435 }
436 
446 static void
447 validate_on_fail(const pcmk_resource_t *rsc, const char *action_name,
448  const xmlNode *action_config, GHashTable *meta)
449 {
450  const char *name = NULL;
451  const char *role = NULL;
452  const char *interval_spec = NULL;
453  const char *value = g_hash_table_lookup(meta, XML_OP_ATTR_ON_FAIL);
454  char *key = NULL;
455  char *new_value = NULL;
456 
457  // Stop actions can only use certain on-fail values
458  if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)
459  && !valid_stop_on_fail(value)) {
460 
461  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
462  "action to default value because '%s' is not "
463  "allowed for stop", rsc->id, value);
464  g_hash_table_remove(meta, XML_OP_ATTR_ON_FAIL);
465  return;
466  }
467 
468  /* Demote actions default on-fail to the on-fail value for the first
469  * recurring monitor for the promoted role (if any).
470  */
471  if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTE, pcmk__str_none)
472  && (value == NULL)) {
473 
474  /* @TODO This does not consider promote options set in a meta-attribute
475  * block (which may have rules that need to be evaluated) rather than
476  * XML properties.
477  */
478  for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
479  operation != NULL; operation = crm_next_same_xml(operation)) {
480  bool enabled = false;
481  const char *promote_on_fail = NULL;
482 
483  /* We only care about explicit on-fail (if promote uses default, so
484  * can demote)
485  */
486  promote_on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
487  if (promote_on_fail == NULL) {
488  continue;
489  }
490 
491  // We only care about recurring monitors for the promoted role
492  name = crm_element_value(operation, "name");
493  role = crm_element_value(operation, "role");
494  if (!pcmk__str_eq(name, PCMK_ACTION_MONITOR, pcmk__str_none)
497  continue;
498  }
499  interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
500  if (crm_parse_interval_spec(interval_spec) == 0) {
501  continue;
502  }
503 
504  // We only care about enabled monitors
505  if ((pcmk__xe_get_bool_attr(operation, "enabled",
506  &enabled) == pcmk_rc_ok) && !enabled) {
507  continue;
508  }
509 
510  // Demote actions can't default to on-fail="demote"
511  if (pcmk__str_eq(promote_on_fail, "demote", pcmk__str_casei)) {
512  continue;
513  }
514 
515  // Use value from first applicable promote action found
516  key = strdup(XML_OP_ATTR_ON_FAIL);
517  new_value = strdup(promote_on_fail);
518  CRM_ASSERT((key != NULL) && (new_value != NULL));
519  g_hash_table_insert(meta, key, new_value);
520  }
521  return;
522  }
523 
524  if (pcmk__str_eq(action_name, PCMK_ACTION_LRM_DELETE, pcmk__str_none)
525  && !pcmk__str_eq(value, "ignore", pcmk__str_casei)) {
526  key = strdup(XML_OP_ATTR_ON_FAIL);
527  new_value = strdup("ignore");
528  CRM_ASSERT((key != NULL) && (new_value != NULL));
529  g_hash_table_insert(meta, key, new_value);
530  return;
531  }
532 
533  // on-fail="demote" is allowed only for certain actions
534  if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
535  name = crm_element_value(action_config, "name");
536  role = crm_element_value(action_config, "role");
537  interval_spec = crm_element_value(action_config,
539 
540  if (!pcmk__str_eq(name, PCMK_ACTION_PROMOTE, pcmk__str_none)
541  && (!pcmk__str_eq(name, PCMK_ACTION_MONITOR, pcmk__str_none)
544  || (crm_parse_interval_spec(interval_spec) == 0))) {
545  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
546  "action to default value because 'demote' is not "
547  "allowed for it", rsc->id, name);
548  g_hash_table_remove(meta, XML_OP_ATTR_ON_FAIL);
549  return;
550  }
551  }
552 }
553 
554 static int
555 unpack_timeout(const char *value)
556 {
557  int timeout_ms = crm_get_msec(value);
558 
559  if (timeout_ms < 0) {
560  timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
561  }
562  return timeout_ms;
563 }
564 
565 // true if value contains valid, non-NULL interval origin for recurring op
566 static bool
567 unpack_interval_origin(const char *value, const xmlNode *xml_obj,
568  guint interval_ms, const crm_time_t *now,
569  long long *start_delay)
570 {
571  long long result = 0;
572  guint interval_sec = interval_ms / 1000;
573  crm_time_t *origin = NULL;
574 
575  // Ignore unspecified values and non-recurring operations
576  if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
577  return false;
578  }
579 
580  // Parse interval origin from text
581  origin = crm_time_new(value);
582  if (origin == NULL) {
583  pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
584  "'%s' because '%s' is not valid",
585  (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
586  return false;
587  }
588 
589  // Get seconds since origin (negative if origin is in the future)
591  crm_time_free(origin);
592 
593  // Calculate seconds from closest interval to now
594  result = result % interval_sec;
595 
596  // Calculate seconds remaining until next interval
597  result = ((result <= 0)? 0 : interval_sec) - result;
598  crm_info("Calculated a start delay of %llds for operation '%s'",
599  result,
600  (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
601 
602  if (start_delay != NULL) {
603  *start_delay = result * 1000; // milliseconds
604  }
605  return true;
606 }
607 
608 static int
609 unpack_start_delay(const char *value, GHashTable *meta)
610 {
611  int start_delay = 0;
612 
613  if (value != NULL) {
614  start_delay = crm_get_msec(value);
615 
616  if (start_delay < 0) {
617  start_delay = 0;
618  }
619 
620  if (meta) {
621  g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
622  pcmk__itoa(start_delay));
623  }
624  }
625 
626  return start_delay;
627 }
628 
638 static xmlNode *
639 most_frequent_monitor(const pcmk_resource_t *rsc)
640 {
641  guint min_interval_ms = G_MAXUINT;
642  xmlNode *op = NULL;
643 
644  for (xmlNode *operation = first_named_child(rsc->ops_xml, XML_ATTR_OP);
645  operation != NULL; operation = crm_next_same_xml(operation)) {
646  bool enabled = false;
647  guint interval_ms = 0;
648  const char *interval_spec = crm_element_value(operation,
650 
651  // We only care about enabled recurring monitors
652  if (!pcmk__str_eq(crm_element_value(operation, "name"),
654  continue;
655  }
656  interval_ms = crm_parse_interval_spec(interval_spec);
657  if (interval_ms == 0) {
658  continue;
659  }
660 
661  // @TODO This does not account for rules, defaults, etc.
662  if ((pcmk__xe_get_bool_attr(operation, "enabled",
663  &enabled) == pcmk_rc_ok) && !enabled) {
664  continue;
665  }
666 
667  if (interval_ms < min_interval_ms) {
668  min_interval_ms = interval_ms;
669  op = operation;
670  }
671  }
672  return op;
673 }
674 
691 GHashTable *
693  const char *action_name, guint interval_ms,
694  const xmlNode *action_config)
695 {
696  GHashTable *meta = NULL;
697  char *name = NULL;
698  char *value = NULL;
699  const char *timeout_spec = NULL;
700  const char *str = NULL;
701 
702  pe_rsc_eval_data_t rsc_rule_data = {
704  .provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER),
705  .agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE),
706  };
707 
708  pe_op_eval_data_t op_rule_data = {
709  .op_name = action_name,
710  .interval = interval_ms,
711  };
712 
713  pe_rule_eval_data_t rule_data = {
714  .node_hash = (node == NULL)? NULL : node->details->attrs,
715  .role = pcmk_role_unknown,
716  .now = rsc->cluster->now,
717  .match_data = NULL,
718  .rsc_data = &rsc_rule_data,
719  .op_data = &op_rule_data,
720  };
721 
722  meta = pcmk__strkey_table(free, free);
723 
724  // Cluster-wide <op_defaults> <meta_attributes>
726  &rule_data, meta, NULL, FALSE, rsc->cluster);
727 
728  // Derive default timeout for probes from recurring monitor timeouts
729  if (pcmk_is_probe(action_name, interval_ms)) {
730  xmlNode *min_interval_mon = most_frequent_monitor(rsc);
731 
732  if (min_interval_mon != NULL) {
733  /* @TODO This does not consider timeouts set in meta_attributes
734  * blocks (which may also have rules that need to be evaluated).
735  */
736  timeout_spec = crm_element_value(min_interval_mon,
738  if (timeout_spec != NULL) {
739  pe_rsc_trace(rsc,
740  "Setting default timeout for %s probe to "
741  "most frequent monitor's timeout '%s'",
742  rsc->id, timeout_spec);
743  name = strdup(XML_ATTR_TIMEOUT);
744  value = strdup(timeout_spec);
745  CRM_ASSERT((name != NULL) && (value != NULL));
746  g_hash_table_insert(meta, name, value);
747  }
748  }
749  }
750 
751  if (action_config != NULL) {
752  // <op> <meta_attributes> take precedence over defaults
753  pe__unpack_dataset_nvpairs(action_config, XML_TAG_META_SETS, &rule_data,
754  meta, NULL, TRUE, rsc->cluster);
755 
756  /* Anything set as an <op> XML property has highest precedence.
757  * This ensures we use the name and interval from the <op> tag.
758  * (See below for the only exception, fence device start/probe timeout.)
759  */
760  for (xmlAttrPtr attr = action_config->properties;
761  attr != NULL; attr = attr->next) {
762  name = strdup((const char *) attr->name);
763  value = strdup(pcmk__xml_attr_value(attr));
764 
765  CRM_ASSERT((name != NULL) && (value != NULL));
766  g_hash_table_insert(meta, name, value);
767  }
768  }
769 
770  g_hash_table_remove(meta, XML_ATTR_ID);
771 
772  // Normalize interval to milliseconds
773  if (interval_ms > 0) {
774  name = strdup(XML_LRM_ATTR_INTERVAL);
775  CRM_ASSERT(name != NULL);
776  value = crm_strdup_printf("%u", interval_ms);
777  g_hash_table_insert(meta, name, value);
778  } else {
779  g_hash_table_remove(meta, XML_LRM_ATTR_INTERVAL);
780  }
781 
782  /* Timeout order of precedence (highest to lowest):
783  * 1. pcmk_monitor_timeout resource parameter (only for starts and probes
784  * when rsc has pcmk_ra_cap_fence_params; this gets used for recurring
785  * monitors via the executor instead)
786  * 2. timeout configured in <op> (with <op timeout> taking precedence over
787  * <op> <meta_attributes>)
788  * 3. timeout configured in <op_defaults> <meta_attributes>
789  * 4. PCMK_DEFAULT_ACTION_TIMEOUT_MS
790  */
791 
792  // Check for pcmk_monitor_timeout
793  if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
795  && (pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)
796  || pcmk_is_probe(action_name, interval_ms))) {
797 
798  GHashTable *params = pe_rsc_params(rsc, node, rsc->cluster);
799 
800  timeout_spec = g_hash_table_lookup(params, "pcmk_monitor_timeout");
801  if (timeout_spec != NULL) {
802  pe_rsc_trace(rsc,
803  "Setting timeout for %s %s to "
804  "pcmk_monitor_timeout (%s)",
805  rsc->id, action_name, timeout_spec);
806  name = strdup(XML_ATTR_TIMEOUT);
807  value = strdup(timeout_spec);
808  CRM_ASSERT((name != NULL) && (value != NULL));
809  g_hash_table_insert(meta, name, value);
810  }
811  }
812 
813  // Normalize timeout to positive milliseconds
814  name = strdup(XML_ATTR_TIMEOUT);
815  CRM_ASSERT(name != NULL);
816  timeout_spec = g_hash_table_lookup(meta, XML_ATTR_TIMEOUT);
817  g_hash_table_insert(meta, name, pcmk__itoa(unpack_timeout(timeout_spec)));
818 
819  // Ensure on-fail has a valid value
820  validate_on_fail(rsc, action_name, action_config, meta);
821 
822  // Normalize start-delay
823  str = g_hash_table_lookup(meta, XML_OP_ATTR_START_DELAY);
824  if (str != NULL) {
825  unpack_start_delay(str, meta);
826  } else {
827  long long start_delay = 0;
828 
829  str = g_hash_table_lookup(meta, XML_OP_ATTR_ORIGIN);
830  if (unpack_interval_origin(str, action_config, interval_ms,
831  rsc->cluster->now, &start_delay)) {
832  name = strdup(XML_OP_ATTR_START_DELAY);
833  CRM_ASSERT(name != NULL);
834  g_hash_table_insert(meta, name,
835  crm_strdup_printf("%lld", start_delay));
836  }
837  }
838  return meta;
839 }
840 
851 pcmk__action_requires(const pcmk_resource_t *rsc, const char *action_name)
852 {
853  const char *value = NULL;
855 
856  CRM_CHECK((rsc != NULL) && (action_name != NULL), return requires);
857 
858  if (!pcmk__strcase_any_of(action_name, PCMK_ACTION_START,
859  PCMK_ACTION_PROMOTE, NULL)) {
860  value = "nothing (not start or promote)";
861 
862  } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_fencing)) {
863  requires = pcmk_requires_fencing;
864  value = "fencing";
865 
866  } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_quorum)) {
867  requires = pcmk_requires_quorum;
868  value = "quorum";
869 
870  } else {
871  value = "nothing";
872  }
873  pe_rsc_trace(rsc, "%s of %s requires %s", action_name, rsc->id, value);
874  return requires;
875 }
876 
889 pcmk__parse_on_fail(const pcmk_resource_t *rsc, const char *action_name,
890  guint interval_ms, const char *value)
891 {
892  const char *desc = NULL;
893  bool needs_remote_reset = false;
895 
896  if (value == NULL) {
897  // Use default
898 
899  } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
900  on_fail = pcmk_on_fail_block;
901  desc = "block";
902 
903  } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
905  on_fail = pcmk_on_fail_fence_node;
906  desc = "node fencing";
907  } else {
908  pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
909  "%s of %s to 'stop' because 'fence' is not "
910  "valid when fencing is disabled",
911  action_name, rsc->id);
912  on_fail = pcmk_on_fail_stop;
913  desc = "stop resource";
914  }
915 
916  } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
917  on_fail = pcmk_on_fail_standby_node;
918  desc = "node standby";
919 
920  } else if (pcmk__strcase_any_of(value, "ignore", PCMK__VALUE_NOTHING,
921  NULL)) {
922  desc = "ignore";
923 
924  } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
925  on_fail = pcmk_on_fail_ban;
926  desc = "force migration";
927 
928  } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
929  on_fail = pcmk_on_fail_stop;
930  desc = "stop resource";
931 
932  } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
933  on_fail = pcmk_on_fail_restart;
934  desc = "restart (and possibly migrate)";
935 
936  } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
937  if (rsc->container == NULL) {
938  pe_rsc_debug(rsc,
939  "Using default " XML_OP_ATTR_ON_FAIL
940  " for %s of %s because it does not have a container",
941  action_name, rsc->id);
942  } else {
944  desc = "restart container (and possibly migrate)";
945  }
946 
947  } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
948  on_fail = pcmk_on_fail_demote;
949  desc = "demote instance";
950 
951  } else {
952  pcmk__config_err("Using default '" XML_OP_ATTR_ON_FAIL "' for "
953  "%s of %s because '%s' is not valid",
954  action_name, rsc->id, value);
955  }
956 
957  /* Remote node connections are handled specially. Failures that result
958  * in dropping an active connection must result in fencing. The only
959  * failures that don't are probes and starts. The user can explicitly set
960  * on-fail="fence" to fence after start failures.
961  */
963  && !pcmk_is_probe(action_name, interval_ms)
964  && !pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)) {
965  needs_remote_reset = true;
966  if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
967  desc = NULL; // Force default for unmanaged connections
968  }
969  }
970 
971  if (desc != NULL) {
972  // Explicit value used, default not needed
973 
974  } else if (rsc->container != NULL) {
976  desc = "restart container (and possibly migrate) (default)";
977 
978  } else if (needs_remote_reset) {
979  if (pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
980  if (pcmk_is_set(rsc->cluster->flags,
982  desc = "fence remote node (default)";
983  } else {
984  desc = "recover remote node connection (default)";
985  }
986  on_fail = pcmk_on_fail_reset_remote;
987  } else {
988  on_fail = pcmk_on_fail_stop;
989  desc = "stop unmanaged remote node (enforcing default)";
990  }
991 
992  } else if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)) {
994  on_fail = pcmk_on_fail_fence_node;
995  desc = "resource fence (default)";
996  } else {
997  on_fail = pcmk_on_fail_block;
998  desc = "resource block (default)";
999  }
1000 
1001  } else {
1002  on_fail = pcmk_on_fail_restart;
1003  desc = "restart (and possibly migrate) (default)";
1004  }
1005 
1006  pe_rsc_trace(rsc, "Failure handling for %s-interval %s of %s: %s",
1007  pcmk__readable_interval(interval_ms), action_name,
1008  rsc->id, desc);
1009  return on_fail;
1010 }
1011 
1023 enum rsc_role_e
1024 pcmk__role_after_failure(const pcmk_resource_t *rsc, const char *action_name,
1025  enum action_fail_response on_fail, GHashTable *meta)
1026 {
1027  const char *value = NULL;
1028  enum rsc_role_e role = pcmk_role_unknown;
1029 
1030  // Set default for role after failure specially in certain circumstances
1031  switch (on_fail) {
1032  case pcmk_on_fail_stop:
1033  role = pcmk_role_stopped;
1034  break;
1035 
1037  if (rsc->remote_reconnect_ms != 0) {
1038  role = pcmk_role_stopped;
1039  }
1040  break;
1041 
1042  default:
1043  break;
1044  }
1045 
1046  // @COMPAT Check for explicitly configured role (deprecated)
1047  value = g_hash_table_lookup(meta, "role_after_failure");
1048  if (value != NULL) {
1050  "Support for role_after_failure is deprecated "
1051  "and will be removed in a future release");
1052  if (role == pcmk_role_unknown) {
1053  role = text2role(value);
1054  }
1055  }
1056 
1057  if (role == pcmk_role_unknown) {
1058  // Use default
1059  if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
1060  role = pcmk_role_unpromoted;
1061  } else {
1062  role = pcmk_role_started;
1063  }
1064  }
1065  pe_rsc_trace(rsc, "Role after %s %s failure is: %s",
1066  rsc->id, action_name, role2text(role));
1067  return role;
1068 }
1069 
1082 static void
1083 unpack_operation(pcmk_action_t *action, const xmlNode *xml_obj,
1084  guint interval_ms)
1085 {
1086  const char *value = NULL;
1087 
1088  action->meta = pcmk__unpack_action_meta(action->rsc, action->node,
1089  action->task, interval_ms, xml_obj);
1090  action->needs = pcmk__action_requires(action->rsc, action->task);
1091 
1092  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
1093  action->on_fail = pcmk__parse_on_fail(action->rsc, action->task,
1094  interval_ms, value);
1095 
1096  action->fail_role = pcmk__role_after_failure(action->rsc, action->task,
1097  action->on_fail, action->meta);
1098 }
1099 
1116 pcmk_action_t *
1117 custom_action(pcmk_resource_t *rsc, char *key, const char *task,
1118  const pcmk_node_t *on_node, gboolean optional,
1120 {
1121  pcmk_action_t *action = NULL;
1122 
1123  CRM_ASSERT((key != NULL) && (task != NULL) && (scheduler != NULL));
1124 
1125  action = find_existing_action(key, rsc, on_node, scheduler);
1126  if (action == NULL) {
1127  action = new_action(key, task, rsc, on_node, optional, scheduler);
1128  } else {
1129  free(key);
1130  }
1131 
1132  update_action_optional(action, optional);
1133 
1134  if (rsc != NULL) {
1135  if ((action->node != NULL) && (action->op_entry != NULL)
1137 
1138  GHashTable *attrs = action->node->details->attrs;
1139 
1140  if (action->extra != NULL) {
1141  g_hash_table_destroy(action->extra);
1142  }
1143  action->extra = pcmk__unpack_action_rsc_params(action->op_entry,
1144  attrs, scheduler);
1146  }
1147 
1148  update_resource_action_runnable(action, scheduler);
1149  update_resource_flags_for_action(rsc, action);
1150  }
1151 
1152  if (action->extra == NULL) {
1153  action->extra = pcmk__strkey_table(free, free);
1154  }
1155 
1156  return action;
1157 }
1158 
1159 pcmk_action_t *
1161 {
1162  pcmk_action_t *op = lookup_singleton(scheduler, name);
1163 
1164  if (op == NULL) {
1165  op = custom_action(NULL, strdup(name), name, NULL, TRUE, scheduler);
1167  }
1168  return op;
1169 }
1170 
1171 static GList *
1172 find_unfencing_devices(GList *candidates, GList *matches)
1173 {
1174  for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
1175  pcmk_resource_t *candidate = gIter->data;
1176 
1177  if (candidate->children != NULL) {
1178  matches = find_unfencing_devices(candidate->children, matches);
1179 
1180  } else if (!pcmk_is_set(candidate->flags, pcmk_rsc_fence_device)) {
1181  continue;
1182 
1183  } else if (pcmk_is_set(candidate->flags, pcmk_rsc_needs_unfencing)) {
1184  matches = g_list_prepend(matches, candidate);
1185 
1186  } else if (pcmk__str_eq(g_hash_table_lookup(candidate->meta,
1189  pcmk__str_casei)) {
1190  matches = g_list_prepend(matches, candidate);
1191  }
1192  }
1193  return matches;
1194 }
1195 
1196 static int
1197 node_priority_fencing_delay(const pcmk_node_t *node,
1198  const pcmk_scheduler_t *scheduler)
1199 {
1200  int member_count = 0;
1201  int online_count = 0;
1202  int top_priority = 0;
1203  int lowest_priority = 0;
1204  GList *gIter = NULL;
1205 
1206  // `priority-fencing-delay` is disabled
1207  if (scheduler->priority_fencing_delay <= 0) {
1208  return 0;
1209  }
1210 
1211  /* No need to request a delay if the fencing target is not a normal cluster
1212  * member, for example if it's a remote node or a guest node. */
1213  if (node->details->type != pcmk_node_variant_cluster) {
1214  return 0;
1215  }
1216 
1217  // No need to request a delay if the fencing target is in our partition
1218  if (node->details->online) {
1219  return 0;
1220  }
1221 
1222  for (gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
1223  pcmk_node_t *n = gIter->data;
1224 
1225  if (n->details->type != pcmk_node_variant_cluster) {
1226  continue;
1227  }
1228 
1229  member_count ++;
1230 
1231  if (n->details->online) {
1232  online_count++;
1233  }
1234 
1235  if (member_count == 1
1236  || n->details->priority > top_priority) {
1237  top_priority = n->details->priority;
1238  }
1239 
1240  if (member_count == 1
1241  || n->details->priority < lowest_priority) {
1242  lowest_priority = n->details->priority;
1243  }
1244  }
1245 
1246  // No need to delay if we have more than half of the cluster members
1247  if (online_count > member_count / 2) {
1248  return 0;
1249  }
1250 
1251  /* All the nodes have equal priority.
1252  * Any configured corresponding `pcmk_delay_base/max` will be applied. */
1253  if (lowest_priority == top_priority) {
1254  return 0;
1255  }
1256 
1257  if (node->details->priority < top_priority) {
1258  return 0;
1259  }
1260 
1262 }
1263 
1264 pcmk_action_t *
1265 pe_fence_op(pcmk_node_t *node, const char *op, bool optional,
1266  const char *reason, bool priority_delay,
1268 {
1269  char *op_key = NULL;
1270  pcmk_action_t *stonith_op = NULL;
1271 
1272  if(op == NULL) {
1273  op = scheduler->stonith_action;
1274  }
1275 
1276  op_key = crm_strdup_printf("%s-%s-%s",
1277  PCMK_ACTION_STONITH, node->details->uname, op);
1278 
1279  stonith_op = lookup_singleton(scheduler, op_key);
1280  if(stonith_op == NULL) {
1281  stonith_op = custom_action(NULL, op_key, PCMK_ACTION_STONITH, node,
1282  TRUE, scheduler);
1283 
1284  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
1285  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
1286  add_hash_param(stonith_op->meta, "stonith_action", op);
1287 
1289  /* Extra work to detect device changes
1290  */
1291  GString *digests_all = g_string_sized_new(1024);
1292  GString *digests_secure = g_string_sized_new(1024);
1293 
1294  GList *matches = find_unfencing_devices(scheduler->resources, NULL);
1295 
1296  char *key = NULL;
1297  char *value = NULL;
1298 
1299  for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
1300  pcmk_resource_t *match = gIter->data;
1301  const char *agent = g_hash_table_lookup(match->meta,
1302  XML_ATTR_TYPE);
1303  op_digest_cache_t *data = NULL;
1304 
1305  data = pe__compare_fencing_digest(match, agent, node,
1306  scheduler);
1307  if (data->rc == pcmk__digest_mismatch) {
1308  optional = FALSE;
1309  crm_notice("Unfencing node %s because the definition of "
1310  "%s changed", pe__node_name(node), match->id);
1311  if (!pcmk__is_daemon && scheduler->priv != NULL) {
1312  pcmk__output_t *out = scheduler->priv;
1313 
1314  out->info(out,
1315  "notice: Unfencing node %s because the "
1316  "definition of %s changed",
1317  pe__node_name(node), match->id);
1318  }
1319  }
1320 
1321  pcmk__g_strcat(digests_all,
1322  match->id, ":", agent, ":",
1323  data->digest_all_calc, ",", NULL);
1324  pcmk__g_strcat(digests_secure,
1325  match->id, ":", agent, ":",
1326  data->digest_secure_calc, ",", NULL);
1327  }
1328  key = strdup(XML_OP_ATTR_DIGESTS_ALL);
1329  value = strdup((const char *) digests_all->str);
1330  CRM_ASSERT((key != NULL) && (value != NULL));
1331  g_hash_table_insert(stonith_op->meta, key, value);
1332  g_string_free(digests_all, TRUE);
1333 
1334  key = strdup(XML_OP_ATTR_DIGESTS_SECURE);
1335  value = strdup((const char *) digests_secure->str);
1336  CRM_ASSERT((key != NULL) && (value != NULL));
1337  g_hash_table_insert(stonith_op->meta, key, value);
1338  g_string_free(digests_secure, TRUE);
1339  }
1340 
1341  } else {
1342  free(op_key);
1343  }
1344 
1346 
1347  /* It's a suitable case where `priority-fencing-delay` applies.
1348  * At least add `priority-fencing-delay` field as an indicator. */
1349  && (priority_delay
1350 
1351  /* The priority delay needs to be recalculated if this function has
1352  * been called by schedule_fencing_and_shutdowns() after node
1353  * priority has already been calculated by native_add_running().
1354  */
1355  || g_hash_table_lookup(stonith_op->meta,
1357 
1358  /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
1359  * the targeting node. So that it takes precedence over any possible
1360  * `pcmk_delay_base/max`.
1361  */
1362  char *delay_s = pcmk__itoa(node_priority_fencing_delay(node,
1363  scheduler));
1364 
1365  g_hash_table_insert(stonith_op->meta,
1367  delay_s);
1368  }
1369 
1370  if(optional == FALSE && pe_can_fence(scheduler, node)) {
1372  pe_action_set_reason(stonith_op, reason, false);
1373 
1374  } else if(reason && stonith_op->reason == NULL) {
1375  stonith_op->reason = strdup(reason);
1376  }
1377 
1378  return stonith_op;
1379 }
1380 
1381 void
1383 {
1384  if (action == NULL) {
1385  return;
1386  }
1387  g_list_free_full(action->actions_before, free);
1388  g_list_free_full(action->actions_after, free);
1389  if (action->extra) {
1390  g_hash_table_destroy(action->extra);
1391  }
1392  if (action->meta) {
1393  g_hash_table_destroy(action->meta);
1394  }
1395  free(action->cancel_task);
1396  free(action->reason);
1397  free(action->task);
1398  free(action->uuid);
1399  free(action->node);
1400  free(action);
1401 }
1402 
1403 int
1406 {
1407  xmlNode *child = NULL;
1408  GHashTable *action_meta = NULL;
1409  const char *timeout_spec = NULL;
1410  int timeout_ms = 0;
1411 
1412  pe_rule_eval_data_t rule_data = {
1413  .node_hash = NULL,
1414  .role = pcmk_role_unknown,
1415  .now = scheduler->now,
1416  .match_data = NULL,
1417  .rsc_data = NULL,
1418  .op_data = NULL
1419  };
1420 
1421  for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
1422  child != NULL; child = crm_next_same_xml(child)) {
1423  if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
1424  pcmk__str_casei)) {
1425  timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
1426  break;
1427  }
1428  }
1429 
1430  if (timeout_spec == NULL && scheduler->op_defaults) {
1431  action_meta = pcmk__strkey_table(free, free);
1433  &rule_data, action_meta, NULL, FALSE,
1434  scheduler);
1435  timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
1436  }
1437 
1438  // @TODO check meta-attributes
1439  // @TODO maybe use min-interval monitor timeout as default for monitors
1440 
1441  timeout_ms = crm_get_msec(timeout_spec);
1442  if (timeout_ms < 0) {
1443  timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
1444  }
1445 
1446  if (action_meta != NULL) {
1447  g_hash_table_destroy(action_meta);
1448  }
1449  return timeout_ms;
1450 }
1451 
1452 enum action_tasks
1453 get_complex_task(const pcmk_resource_t *rsc, const char *name)
1454 {
1455  enum action_tasks task = text2task(name);
1456 
1457  if ((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_primitive)) {
1458  switch (task) {
1459  case pcmk_action_stopped:
1460  case pcmk_action_started:
1461  case pcmk_action_demoted:
1462  case pcmk_action_promoted:
1463  crm_trace("Folding %s back into its atomic counterpart for %s",
1464  name, rsc->id);
1465  --task;
1466  break;
1467  default:
1468  break;
1469  }
1470  }
1471  return task;
1472 }
1473 
1485 pcmk_action_t *
1486 find_first_action(const GList *input, const char *uuid, const char *task,
1487  const pcmk_node_t *on_node)
1488 {
1489  CRM_CHECK(uuid || task, return NULL);
1490 
1491  for (const GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1492  pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1493 
1494  if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1495  continue;
1496 
1497  } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1498  continue;
1499 
1500  } else if (on_node == NULL) {
1501  return action;
1502 
1503  } else if (action->node == NULL) {
1504  continue;
1505 
1506  } else if (on_node->details == action->node->details) {
1507  return action;
1508  }
1509  }
1510 
1511  return NULL;
1512 }
1513 
1514 GList *
1515 find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
1516 {
1517  GList *gIter = input;
1518  GList *result = NULL;
1519 
1520  CRM_CHECK(key != NULL, return NULL);
1521 
1522  for (; gIter != NULL; gIter = gIter->next) {
1523  pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1524 
1525  if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1526  continue;
1527 
1528  } else if (on_node == NULL) {
1529  crm_trace("Action %s matches (ignoring node)", key);
1530  result = g_list_prepend(result, action);
1531 
1532  } else if (action->node == NULL) {
1533  crm_trace("Action %s matches (unallocated, assigning to %s)",
1534  key, pe__node_name(on_node));
1535 
1536  action->node = pe__copy_node(on_node);
1537  result = g_list_prepend(result, action);
1538 
1539  } else if (on_node->details == action->node->details) {
1540  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1541  result = g_list_prepend(result, action);
1542  }
1543  }
1544 
1545  return result;
1546 }
1547 
1548 GList *
1549 find_actions_exact(GList *input, const char *key, const pcmk_node_t *on_node)
1550 {
1551  GList *result = NULL;
1552 
1553  CRM_CHECK(key != NULL, return NULL);
1554 
1555  if (on_node == NULL) {
1556  return NULL;
1557  }
1558 
1559  for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1560  pcmk_action_t *action = (pcmk_action_t *) gIter->data;
1561 
1562  if ((action->node != NULL)
1563  && pcmk__str_eq(key, action->uuid, pcmk__str_casei)
1564  && pcmk__str_eq(on_node->details->id, action->node->details->id,
1565  pcmk__str_casei)) {
1566 
1567  crm_trace("Action %s on %s matches", key, pe__node_name(on_node));
1568  result = g_list_prepend(result, action);
1569  }
1570  }
1571 
1572  return result;
1573 }
1574 
1587 GList *
1589  const char *task, bool require_node)
1590 {
1591  GList *result = NULL;
1592  char *key = pcmk__op_key(rsc->id, task, 0);
1593 
1594  if (require_node) {
1595  result = find_actions_exact(rsc->actions, key, node);
1596  } else {
1597  result = find_actions(rsc->actions, key, node);
1598  }
1599  free(key);
1600  return result;
1601 }
1602 
1613 char *
1615 {
1616  const char *change = NULL;
1617 
1618  switch (flag) {
1619  case pcmk_action_runnable:
1620  change = "unrunnable";
1621  break;
1623  change = "unmigrateable";
1624  break;
1625  case pcmk_action_optional:
1626  change = "required";
1627  break;
1628  default:
1629  // Bug: caller passed unsupported flag
1630  CRM_CHECK(change != NULL, change = "");
1631  break;
1632  }
1633  return crm_strdup_printf("%s%s%s %s", change,
1634  (action->rsc == NULL)? "" : " ",
1635  (action->rsc == NULL)? "" : action->rsc->id,
1636  action->task);
1637 }
1638 
1639 void pe_action_set_reason(pcmk_action_t *action, const char *reason,
1640  bool overwrite)
1641 {
1642  if (action->reason != NULL && overwrite) {
1643  pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
1644  action->uuid, action->reason, pcmk__s(reason, "(none)"));
1645  } else if (action->reason == NULL) {
1646  pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
1647  action->uuid, pcmk__s(reason, "(none)"));
1648  } else {
1649  // crm_assert(action->reason != NULL && !overwrite);
1650  return;
1651  }
1652 
1653  pcmk__str_update(&action->reason, reason);
1654 }
1655 
1663 void
1665 {
1666  CRM_ASSERT((rsc != NULL) && (node != NULL));
1667 
1669  PCMK_ACTION_LRM_DELETE, node, FALSE, rsc->cluster);
1670 }
1671 
1672 #define sort_return(an_int, why) do { \
1673  free(a_uuid); \
1674  free(b_uuid); \
1675  crm_trace("%s (%d) %c %s (%d) : %s", \
1676  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1677  b_xml_id, b_call_id, why); \
1678  return an_int; \
1679  } while(0)
1680 
1681 int
1682 pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b,
1683  bool same_node_default)
1684 {
1685  int a_call_id = -1;
1686  int b_call_id = -1;
1687 
1688  char *a_uuid = NULL;
1689  char *b_uuid = NULL;
1690 
1691  const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1692  const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1693 
1694  const char *a_node = crm_element_value(xml_a, XML_LRM_ATTR_TARGET);
1695  const char *b_node = crm_element_value(xml_b, XML_LRM_ATTR_TARGET);
1696  bool same_node = true;
1697 
1698  /* @COMPAT The on_node attribute was added to last_failure as of 1.1.13 (via
1699  * 8b3ca1c) and the other entries as of 1.1.12 (via 0b07b5c).
1700  *
1701  * In case that any of the lrm_rsc_op entries doesn't have on_node
1702  * attribute, we need to explicitly tell whether the two operations are on
1703  * the same node.
1704  */
1705  if (a_node == NULL || b_node == NULL) {
1706  same_node = same_node_default;
1707 
1708  } else {
1709  same_node = pcmk__str_eq(a_node, b_node, pcmk__str_casei);
1710  }
1711 
1712  if (same_node && pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_none)) {
1713  /* We have duplicate lrm_rsc_op entries in the status
1714  * section which is unlikely to be a good thing
1715  * - we can handle it easily enough, but we need to get
1716  * to the bottom of why it's happening.
1717  */
1718  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1719  sort_return(0, "duplicate");
1720  }
1721 
1722  crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1723  crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1724 
1725  if (a_call_id == -1 && b_call_id == -1) {
1726  /* both are pending ops so it doesn't matter since
1727  * stops are never pending
1728  */
1729  sort_return(0, "pending");
1730 
1731  } else if (same_node && a_call_id >= 0 && a_call_id < b_call_id) {
1732  sort_return(-1, "call id");
1733 
1734  } else if (same_node && b_call_id >= 0 && a_call_id > b_call_id) {
1735  sort_return(1, "call id");
1736 
1737  } else if (a_call_id >= 0 && b_call_id >= 0
1738  && (!same_node || a_call_id == b_call_id)) {
1739  /*
1740  * The op and last_failed_op are the same
1741  * Order on last-rc-change
1742  */
1743  time_t last_a = -1;
1744  time_t last_b = -1;
1745 
1748 
1749  crm_trace("rc-change: %lld vs %lld",
1750  (long long) last_a, (long long) last_b);
1751  if (last_a >= 0 && last_a < last_b) {
1752  sort_return(-1, "rc-change");
1753 
1754  } else if (last_b >= 0 && last_a > last_b) {
1755  sort_return(1, "rc-change");
1756  }
1757  sort_return(0, "rc-change");
1758 
1759  } else {
1760  /* One of the inputs is a pending operation
1761  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1762  */
1763 
1764  int a_id = -1;
1765  int b_id = -1;
1766 
1767  const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1768  const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1769 
1770  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1771  if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1772  NULL)) {
1773  sort_return(0, "bad magic a");
1774  }
1775  if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1776  NULL)) {
1777  sort_return(0, "bad magic b");
1778  }
1779  /* try to determine the relative age of the operation...
1780  * some pending operations (e.g. a start) may have been superseded
1781  * by a subsequent stop
1782  *
1783  * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1784  */
1785  if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1786  /*
1787  * some of the logic in here may be redundant...
1788  *
1789  * if the UUID from the TE doesn't match then one better
1790  * be a pending operation.
1791  * pending operations don't survive between elections and joins
1792  * because we query the LRM directly
1793  */
1794 
1795  if (b_call_id == -1) {
1796  sort_return(-1, "transition + call");
1797 
1798  } else if (a_call_id == -1) {
1799  sort_return(1, "transition + call");
1800  }
1801 
1802  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1803  sort_return(-1, "transition");
1804 
1805  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1806  sort_return(1, "transition");
1807  }
1808  }
1809 
1810  /* we should never end up here */
1811  CRM_CHECK(FALSE, sort_return(0, "default"));
1812 }
1813 
1814 gint
1815 sort_op_by_callid(gconstpointer a, gconstpointer b)
1816 {
1817  const xmlNode *xml_a = a;
1818  const xmlNode *xml_b = b;
1819 
1820  return pe__is_newer_op(xml_a, xml_b, true);
1821 }
1822 
1834 pcmk_action_t *
1835 pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional,
1836  bool runnable)
1837 {
1838  pcmk_action_t *action = NULL;
1839 
1840  CRM_ASSERT((rsc != NULL) && (task != NULL));
1841 
1842  action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0), task, NULL,
1843  optional, rsc->cluster);
1845  if (runnable) {
1847  }
1848  return action;
1849 }
1850 
1860 void
1862 {
1863  char *name = NULL;
1864 
1865  CRM_ASSERT((action != NULL) && (action->meta != NULL));
1866 
1867  name = strdup(XML_ATTR_TE_TARGET_RC);
1868  CRM_ASSERT (name != NULL);
1869 
1870  g_hash_table_insert(action->meta, name, pcmk__itoa(expected_result));
1871 }
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:271
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
bool pe_can_fence(const pcmk_scheduler_t *scheduler, const pcmk_node_t *node)
Definition: utils.c:36
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:326
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
Definition: pe_actions.c:1117
Demoted.
Definition: actions.h:98
enum pe_quorum_policy no_quorum_policy
Response to loss of quorum.
Definition: scheduler.h:186
A dumping ground.
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition: utils.c:89
Resource can be recovered after fencing.
Definition: resources.h:61
#define crm_notice(fmt, args...)
Definition: logging.h:383
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
xmlNode * ops_xml
Configuration of resource operations (possibly expanded from template)
Definition: resources.h:410
GHashTable * attrs
Node attributes.
Definition: nodes.h:115
Resource can be recovered immediately.
Definition: resources.h:59
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:36
char data[0]
Definition: cpg.c:55
#define XML_OP_ATTR_DIGESTS_ALL
Definition: msg_xml.h:273
Whether action should not be executed.
Definition: actions.h:244
void pe__add_action_expected_result(pcmk_action_t *action, int expected_result)
Definition: pe_actions.c:1861
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:76
enum rsc_start_requirement pcmk__action_requires(const pcmk_resource_t *rsc, const char *action_name)
Definition: pe_actions.c:851
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:350
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:415
GList * find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
Definition: pe_actions.c:1515
Stopped.
Definition: roles.h:29
#define PCMK_STONITH_PROVIDES
Definition: agents.h:48
const char * name
Definition: cib.c:26
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:933
#define XML_ATTR_TYPE
Definition: msg_xml.h:160
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition: msg_xml.h:405
struct crm_time_s crm_time_t
Definition: iso8601.h:32
enum rsc_role_e role
Resource&#39;s current role.
Definition: resources.h:468
Whether partition has quorum (via have-quorum property)
Definition: scheduler.h:71
Ban resource from current node.
Definition: actions.h:169
GList * children
Resource&#39;s child resources, if any.
Definition: resources.h:475
Whether resource can be started or promoted only on quorate nodes.
Definition: resources.h:187
int priority_fencing_delay
Priority fencing delay.
Definition: scheduler.h:226
xmlNode * op_defaults
Configured operation defaults.
Definition: scheduler.h:206
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2484
xmlNode * xml
Resource configuration (possibly expanded from template)
Definition: resources.h:404
enum rsc_role_e next_role
Resource&#39;s scheduled next role.
Definition: resources.h:469
Fence resource&#39;s node.
Definition: actions.h:181
bool pcmk_is_probe(const char *task, guint interval)
Definition: actions.c:496
Implementation of pcmk_action_t.
Definition: actions.h:390
#define pcmk__config_err(fmt...)
#define PCMK_ACTION_MONITOR
Definition: actions.h:59
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:364
GHashTable * meta
Resource&#39;s meta-attributes.
Definition: resources.h:471
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:300
pcmk_action_t * pe_fence_op(pcmk_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pcmk_scheduler_t *scheduler)
Definition: pe_actions.c:1265
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:150
#define PCMK__VALUE_UNFENCING
#define PCMK_ACTION_MIGRATE_TO
Definition: actions.h:58
bool pe__resource_is_remote_conn(const pcmk_resource_t *rsc)
Definition: remote.c:18
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:393
Promoted.
Definition: roles.h:32
#define XML_OP_ATTR_DIGESTS_SECURE
Definition: msg_xml.h:274
enum action_fail_response pcmk__parse_on_fail(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, const char *value)
Definition: pe_actions.c:889
action_tasks
Possible actions (including some pseudo-actions)
Definition: actions.h:79
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: actions.c:209
void pe_fence_node(pcmk_scheduler_t *scheduler, pcmk_node_t *node, const char *reason, bool priority_delay)
Schedule a fence action for a node.
Definition: unpack.c:110
enum action_tasks text2task(const char *task)
Definition: common.c:360
GList * actions
Scheduled actions.
Definition: scheduler.h:204
action_fail_response
Possible responses to a resource action failure.
Definition: actions.h:149
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:222
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
char * pe__action2reason(const pcmk_action_t *action, enum pe_action_flags flag)
Definition: pe_actions.c:1614
Cluster layer node.
Definition: nodes.h:34
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:268
pcmk_resource_t * container
Resource containing this one, if any.
Definition: resources.h:480
Demote if promotable, else stop.
Definition: actions.h:197
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:483
Implementation of pcmk_scheduler_t.
Definition: scheduler.h:172
pcmk_action_t * get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler)
Definition: pe_actions.c:1160
char * reason
Readable description of why action is needed.
Definition: actions.h:406
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:64
pe_quorum_policy
Possible responses to loss of quorum.
Definition: scheduler.h:38
GList * resources
Resources in cluster.
Definition: scheduler.h:196
#define PCMK__ROLE_PROMOTED
rsc_start_requirement
What resource needs before it can be recovered from a failed node.
Definition: resources.h:58
GList * nodes
Nodes in cluster.
Definition: scheduler.h:195
enum action_tasks get_complex_task(const pcmk_resource_t *rsc, const char *name)
Definition: pe_actions.c:1453
Stop resource and leave stopped.
Definition: actions.h:175
#define PCMK__ROLE_PROMOTED_LEGACY
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:227
const char * role2text(enum rsc_role_e role)
Definition: common.c:458
op_digest_cache_t * pe__compare_fencing_digest(pcmk_resource_t *rsc, const char *agent, pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Definition: pe_digest.c:541
#define PCMK_DEFAULT_ACTION_TIMEOUT_MS
Default timeout (in milliseconds) for non-metadata actions.
Definition: actions.h:38
int pe_get_configured_timeout(pcmk_resource_t *rsc, const char *action, pcmk_scheduler_t *scheduler)
Definition: pe_actions.c:1404
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
Whether any resource provides or requires unfencing (via CIB resources)
Definition: scheduler.h:86
guint remote_reconnect_ms
Retry interval for remote connections.
Definition: resources.h:427
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1184
Put resource&#39;s node in standby.
Definition: actions.h:178
#define XML_ATTR_OP
Definition: msg_xml.h:161
Restart resource&#39;s container.
Definition: actions.h:186
Implementation of pcmk_resource_t.
Definition: resources.h:399
void pe__clear_resource_history(pcmk_resource_t *rsc, const pcmk_node_t *node)
Definition: pe_actions.c:1664
Primitive resource.
Definition: resources.h:34
#define XML_ATTR_ID
Definition: msg_xml.h:156
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
enum rsc_role_e pcmk__role_after_failure(const pcmk_resource_t *rsc, const char *action_name, enum action_fail_response on_fail, GHashTable *meta)
Definition: pe_actions.c:1024
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:142
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:85
#define crm_trace(fmt, args...)
Definition: logging.h:387
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:175
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1217
void * priv
For Pacemaker use only.
Definition: scheduler.h:229
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * meta
Meta-attributes relevant to action.
Definition: actions.h:414
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
int action_id
ID to use for next created action.
Definition: scheduler.h:211
const char * stonith_action
Default fencing action.
Definition: scheduler.h:179
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
Definition: pe_actions.c:1486
#define PCMK_ACTION_START
Definition: actions.h:71
const char * op_name
Definition: common.h:75
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:281
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:878
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition: resources.h:429
const char * uname
Node name in cluster.
Definition: nodes.h:68
Unpromoted.
Definition: roles.h:31
#define XML_TAG_META_SETS
Definition: msg_xml.h:228
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1193
rsc_role_e
Definition: roles.h:27
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, pcmk_scheduler_t *scheduler)
Definition: utils.c:707
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:568
#define PCMK_ACTION_STOP
Definition: actions.h:74
GList * actions
Definition: resources.h:447
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1835
#define PCMK_ACTION_STONITH
Definition: actions.h:73
pe_action_flags
Action scheduling flags.
Definition: actions.h:233
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: actions.c:42
Implementation of pcmk_node_t.
Definition: nodes.h:130
enum rsc_role_e text2role(const char *role)
Definition: common.c:487
enum pe_obj_types variant
Resource variant.
Definition: resources.h:414
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:957
long long crm_time_get_seconds(const crm_time_t *dt)
Definition: iso8601.c:316
void pe_action_set_reason(pcmk_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1639
Resource can be recovered if quorate.
Definition: resources.h:60
const char * id
Node ID at the cluster layer.
Definition: nodes.h:67
xmlNode * pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, bool include_disabled)
Definition: pe_actions.c:129
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:309
GList * pe__resource_actions(const pcmk_resource_t *rsc, const pcmk_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition: pe_actions.c:1588
#define PCMK_ACTION_LRM_DELETE
Definition: actions.h:53
bool pe__is_guest_node(const pcmk_node_t *node)
Definition: remote.c:33
Whether resource requires fencing before recovery if on unclean node.
Definition: resources.h:190
const char * standard
Definition: common.h:69
Whether resource&#39;s class is "stonith".
Definition: resources.h:121
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:608
pcmk__action_result_t result
Definition: pcmk_fence.c:35
Whether action is runnable.
Definition: actions.h:241
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:508
GHashTable * pcmk__unpack_action_meta(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *action_name, guint interval_ms, const xmlNode *action_config)
Definition: pe_actions.c:692
Whether fencing is enabled (via stonith-enabled property)
Definition: scheduler.h:80
pcmk_scheduler_t * scheduler
Whether action does not require invoking an agent.
Definition: actions.h:238
#define CRM_ASSERT(expr)
Definition: results.h:42
GHashTable * node_hash
Definition: common.h:80
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:271
xmlNode * input
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:57
Started.
Definition: roles.h:30
GList * find_actions_exact(GList *input, const char *key, const pcmk_node_t *on_node)
Definition: pe_actions.c:1549
This structure contains everything that makes up a single output formatter.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: actions.c:96
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:304
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:318
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:70
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
Whether operation-specific instance attributes have been unpacked yet.
Definition: actions.h:250
#define PCMK__VALUE_NOTHING
Start completed.
Definition: actions.h:89
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:269
GHashTable * pcmk__unpack_action_rsc_params(const xmlNode *action_xml, GHashTable *node_attrs, pcmk_scheduler_t *scheduler)
Definition: pe_actions.c:240
Whether action is allowed to be part of a live migration.
Definition: actions.h:253
#define sort_return(an_int, why)
Definition: pe_actions.c:1672
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:1926
void pe_free_action(pcmk_action_t *action)
Definition: pe_actions.c:1382
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
Stop completed.
Definition: actions.h:86
Treat resource as unmanaged.
Definition: actions.h:172
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
Definition: pe_actions.c:1682
Resource role is unknown.
Definition: roles.h:28
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:308
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition: complex.c:446
GHashTable * singletons
Actions for which there can be only one (such as "fence node X")
Definition: scheduler.h:193
#define ID(x)
Definition: msg_xml.h:474
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition: scheduler.h:183
#define pe_err(fmt...)
Definition: internal.h:39
Whether action can be executed on DC rather than own node.
Definition: actions.h:278
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1815
Whether resource is managed.
Definition: resources.h:106
Whether resource can be started or promoted only on unfenced nodes.
Definition: resources.h:193
Promoted.
Definition: actions.h:95
Restart resource.
Definition: actions.h:166
enum node_type type
Node variant.
Definition: nodes.h:69
crm_time_t * now
Current time for evaluation purposes.
Definition: scheduler.h:176
#define crm_info(fmt, args...)
Definition: logging.h:384
gboolean online
Whether online.
Definition: nodes.h:72
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:419
Act as if failure didn&#39;t happen.
Definition: actions.h:163
#define PCMK_ACTION_NOTIFY
Definition: actions.h:61
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:280
char * id
Resource ID in configuration.
Definition: resources.h:400
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2510
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150