pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk_sched_recurring.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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 General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdbool.h>
13 
14 #include <crm/common/xml.h>
16 #include <pacemaker-internal.h>
17 
18 #include "libpacemaker_private.h"
19 
20 // Information parsed from an operation history entry in the CIB
21 struct op_history {
22  // XML attributes
23  const char *id; // ID of history entry
24  const char *name; // Action name
25 
26  // Parsed information
27  char *key; // Operation key for action
28  enum rsc_role_e role; // Action role (or pcmk_role_unknown for default)
29  guint interval_ms; // Action interval
30 };
31 
40 static guint
41 xe_interval(const xmlNode *xml)
42 {
43  guint interval_ms = 0U;
44 
46  &interval_ms);
47  return interval_ms;
48 }
49 
61 static bool
62 is_op_dup(const pcmk_resource_t *rsc, const char *name, guint interval_ms)
63 {
64  const char *id = NULL;
65 
66  for (xmlNode *op = pcmk__xe_first_child(rsc->priv->ops_xml, PCMK_XE_OP,
67  NULL, NULL);
68  op != NULL; op = pcmk__xe_next(op, PCMK_XE_OP)) {
69 
70  // Check whether action name and interval match
71  if (!pcmk__str_eq(crm_element_value(op, PCMK_XA_NAME), name,
73  || (xe_interval(op) != interval_ms)) {
74  continue;
75  }
76 
77  if (pcmk__xe_id(op) == NULL) {
78  continue; // Shouldn't be possible
79  }
80 
81  if (id == NULL) {
82  id = pcmk__xe_id(op); // First matching op
83  } else {
84  pcmk__config_err("Operation %s is duplicate of %s (do not use "
85  "same name and interval combination more "
86  "than once per resource)", pcmk__xe_id(op), id);
87  return true;
88  }
89  }
90  return false;
91 }
92 
109 static bool
110 op_cannot_recur(const char *name)
111 {
116  NULL);
117 }
118 
129 static bool
130 is_recurring_history(const pcmk_resource_t *rsc, const xmlNode *xml,
131  struct op_history *op)
132 {
133  const char *role = NULL;
134 
135  op->interval_ms = xe_interval(xml);
136  if (op->interval_ms == 0) {
137  return false; // Not recurring
138  }
139 
140  op->id = pcmk__xe_id(xml);
141  if (pcmk__str_empty(op->id)) {
142  pcmk__config_err("Ignoring resource history entry without ID");
143  return false; // Shouldn't be possible (unless CIB was manually edited)
144  }
145 
146  op->name = crm_element_value(xml, PCMK_XA_NAME);
147  if (op_cannot_recur(op->name)) {
148  pcmk__config_err("Ignoring %s because %s action cannot be recurring",
149  op->id, pcmk__s(op->name, "unnamed"));
150  return false;
151  }
152 
153  // There should only be one recurring operation per action/interval
154  if (is_op_dup(rsc, op->name, op->interval_ms)) {
155  return false;
156  }
157 
158  // Ensure role is valid if specified
159  role = crm_element_value(xml, PCMK_XA_ROLE);
160  if (role == NULL) {
161  op->role = pcmk_role_unknown;
162  } else {
163  op->role = pcmk_parse_role(role);
164  if (op->role == pcmk_role_unknown) {
165  pcmk__config_err("Ignoring %s role because %s is not a valid role",
166  op->id, role);
167  return false;
168  }
169  }
170 
171  // Only actions that are still configured and enabled matter
172  if (pcmk__find_action_config(rsc, op->name, op->interval_ms,
173  false) == NULL) {
174  pcmk__rsc_trace(rsc,
175  "Ignoring %s (%s-interval %s for %s) because it is "
176  "disabled or no longer in configuration",
177  op->id, pcmk__readable_interval(op->interval_ms),
178  op->name, rsc->id);
179  return false;
180  }
181 
182  op->key = pcmk__op_key(rsc->id, op->name, op->interval_ms);
183  return true;
184 }
185 
197 static bool
198 active_recurring_should_be_optional(const pcmk_resource_t *rsc,
199  const pcmk_node_t *node, const char *key,
200  pcmk_action_t *start)
201 {
202  GList *possible_matches = NULL;
203 
204  if (node == NULL) { // Should only be possible if unmanaged and stopped
205  pcmk__rsc_trace(rsc,
206  "%s will be mandatory because resource is unmanaged",
207  key);
208  return false;
209  }
210 
211  if (!pcmk_is_set(rsc->priv->cmds->action_flags(start, NULL),
213  pcmk__rsc_trace(rsc, "%s will be mandatory because %s is",
214  key, start->uuid);
215  return false;
216  }
217 
218  possible_matches = find_actions_exact(rsc->priv->actions, key, node);
219  if (possible_matches == NULL) {
220  pcmk__rsc_trace(rsc,
221  "%s will be mandatory because it is not active on %s",
222  key, pcmk__node_name(node));
223  return false;
224  }
225 
226  for (const GList *iter = possible_matches;
227  iter != NULL; iter = iter->next) {
228 
229  const pcmk_action_t *op = (const pcmk_action_t *) iter->data;
230 
232  pcmk__rsc_trace(rsc,
233  "%s will be mandatory because "
234  "it needs to be rescheduled", key);
235  g_list_free(possible_matches);
236  return false;
237  }
238  }
239 
240  g_list_free(possible_matches);
241  return true;
242 }
243 
253 static void
254 recurring_op_for_active(pcmk_resource_t *rsc, pcmk_action_t *start,
255  const pcmk_node_t *node, const struct op_history *op)
256 {
257  pcmk_action_t *mon = NULL;
258  bool is_optional = true;
259  bool role_match = false;
260  enum rsc_role_e monitor_role = op->role;
261 
262  // We're only interested in recurring actions for active roles
263  if (monitor_role == pcmk_role_stopped) {
264  return;
265  }
266 
267  is_optional = active_recurring_should_be_optional(rsc, node, op->key,
268  start);
269 
270  // Check whether monitor's role matches role resource will have
271  if (monitor_role == pcmk_role_unknown) {
272  monitor_role = pcmk_role_unpromoted;
273  role_match = (rsc->priv->next_role != pcmk_role_promoted);
274  } else {
275  role_match = (rsc->priv->next_role == monitor_role);
276  }
277 
278  if (!role_match) {
279  if (is_optional) { // It's running, so cancel it
280  char *after_key = NULL;
281  pcmk_action_t *cancel_op = pcmk__new_cancel_action(rsc, op->name,
282  op->interval_ms,
283  node);
284 
285  switch (rsc->priv->orig_role) {
287  case pcmk_role_started:
288  if (rsc->priv->next_role == pcmk_role_promoted) {
289  after_key = promote_key(rsc);
290 
291  } else if (rsc->priv->next_role == pcmk_role_stopped) {
292  after_key = stop_key(rsc);
293  }
294 
295  break;
296  case pcmk_role_promoted:
297  after_key = demote_key(rsc);
298  break;
299  default:
300  break;
301  }
302 
303  if (after_key) {
304  pcmk__new_ordering(rsc, NULL, cancel_op, rsc, after_key, NULL,
306  rsc->priv->scheduler);
307  }
308  }
309 
310  do_crm_log((is_optional? LOG_INFO : LOG_TRACE),
311  "%s recurring action %s because %s configured for %s role "
312  "(not %s)",
313  (is_optional? "Cancelling" : "Ignoring"), op->key, op->id,
314  pcmk_role_text(monitor_role),
315  pcmk_role_text(rsc->priv->next_role));
316  return;
317  }
318 
319  pcmk__rsc_trace(rsc,
320  "Creating %s recurring action %s for %s (%s %s on %s)",
321  (is_optional? "optional" : "mandatory"), op->key,
322  op->id, rsc->id, pcmk_role_text(rsc->priv->next_role),
323  pcmk__node_name(node));
324 
325  mon = custom_action(rsc, strdup(op->key), op->name, node, is_optional,
326  rsc->priv->scheduler);
327 
328  if (!pcmk_is_set(start->flags, pcmk__action_runnable)) {
329  pcmk__rsc_trace(rsc, "%s is unrunnable because start is", mon->uuid);
331 
332  } else if ((node == NULL) || !node->details->online
333  || node->details->unclean) {
334  pcmk__rsc_trace(rsc, "%s is unrunnable because no node is available",
335  mon->uuid);
337 
338  } else if (!pcmk_is_set(mon->flags, pcmk__action_optional)) {
339  pcmk__rsc_info(rsc, "Start %s-interval %s for %s on %s",
340  pcmk__readable_interval(op->interval_ms), mon->task,
341  rsc->id, pcmk__node_name(node));
342  }
343 
344  if (rsc->priv->next_role == pcmk_role_promoted) {
346  }
347 
348  // Order monitor relative to other actions
349  if ((node == NULL) || pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
350  pcmk__new_ordering(rsc, start_key(rsc), NULL,
351  NULL, strdup(mon->uuid), mon,
354  rsc->priv->scheduler);
355 
356  pcmk__new_ordering(rsc, reload_key(rsc), NULL,
357  NULL, strdup(mon->uuid), mon,
360  rsc->priv->scheduler);
361 
362  if (rsc->priv->next_role == pcmk_role_promoted) {
363  pcmk__new_ordering(rsc, promote_key(rsc), NULL,
364  rsc, NULL, mon,
367  rsc->priv->scheduler);
368 
369  } else if (rsc->priv->orig_role == pcmk_role_promoted) {
370  pcmk__new_ordering(rsc, demote_key(rsc), NULL,
371  rsc, NULL, mon,
374  rsc->priv->scheduler);
375  }
376  }
377 }
378 
389 static void
390 cancel_if_running(pcmk_resource_t *rsc, const pcmk_node_t *node,
391  const char *key, const char *name, guint interval_ms)
392 {
393  GList *possible_matches = find_actions_exact(rsc->priv->actions, key,
394  node);
395  pcmk_action_t *cancel_op = NULL;
396 
397  if (possible_matches == NULL) {
398  return; // Recurring action isn't running on this node
399  }
400  g_list_free(possible_matches);
401 
402  cancel_op = pcmk__new_cancel_action(rsc, name, interval_ms, node);
403 
404  switch (rsc->priv->next_role) {
405  case pcmk_role_started:
407  /* Order starts after cancel. If the current role is
408  * stopped, this cancels the monitor before the resource
409  * starts; if the current role is started, then this cancels
410  * the monitor on a migration target before starting there.
411  */
412  pcmk__new_ordering(rsc, NULL, cancel_op,
413  rsc, start_key(rsc), NULL,
415  rsc->priv->scheduler);
416  break;
417  default:
418  break;
419  }
420  pcmk__rsc_info(rsc,
421  "Cancelling %s-interval %s action for %s on %s because "
422  "configured for " PCMK_ROLE_STOPPED " role (not %s)",
423  pcmk__readable_interval(interval_ms), name, rsc->id,
424  pcmk__node_name(node),
425  pcmk_role_text(rsc->priv->next_role));
426 }
427 
436 static void
437 order_after_probes(pcmk_resource_t *rsc, const pcmk_node_t *node,
439 {
440  GList *probes = pe__resource_actions(rsc, node, PCMK_ACTION_MONITOR, FALSE);
441 
442  for (GList *iter = probes; iter != NULL; iter = iter->next) {
443  order_actions((pcmk_action_t *) iter->data, action,
445  }
446  g_list_free(probes);
447 }
448 
457 static void
458 order_after_stops(pcmk_resource_t *rsc, const pcmk_node_t *node,
460 {
461  GList *stop_ops = pe__resource_actions(rsc, node, PCMK_ACTION_STOP, TRUE);
462 
463  for (GList *iter = stop_ops; iter != NULL; iter = iter->next) {
464  pcmk_action_t *stop = (pcmk_action_t *) iter->data;
465 
468  && !pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
469  pcmk__rsc_trace(rsc, "%s optional on %s: unmanaged",
470  action->uuid, pcmk__node_name(node));
472  }
473 
474  if (!pcmk_is_set(stop->flags, pcmk__action_runnable)) {
475  crm_debug("%s unrunnable on %s: stop is unrunnable",
476  action->uuid, pcmk__node_name(node));
478  }
479 
480  if (pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
481  pcmk__new_ordering(rsc, stop_key(rsc), stop,
482  NULL, NULL, action,
485  rsc->priv->scheduler);
486  }
487  }
488  g_list_free(stop_ops);
489 }
490 
499 static void
500 recurring_op_for_inactive(pcmk_resource_t *rsc, const pcmk_node_t *node,
501  const struct op_history *op)
502 {
503  GList *possible_matches = NULL;
504 
505  // We're only interested in recurring actions for the inactive role
506  if (op->role != pcmk_role_stopped) {
507  return;
508  }
509 
510  if (!pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
511  crm_notice("Ignoring %s (recurring monitors for " PCMK_ROLE_STOPPED
512  " role are not supported for anonymous clones)", op->id);
513  return; // @TODO add support
514  }
515 
516  pcmk__rsc_trace(rsc,
517  "Creating recurring action %s for %s on nodes "
518  "where it should not be running", op->id, rsc->id);
519 
520  for (GList *iter = rsc->priv->scheduler->nodes;
521  iter != NULL; iter = iter->next) {
522 
523  pcmk_node_t *stop_node = (pcmk_node_t *) iter->data;
524 
525  bool is_optional = true;
526  pcmk_action_t *stopped_mon = NULL;
527 
528  // Cancel action on node where resource will be active
529  if ((node != NULL)
530  && pcmk__str_eq(stop_node->priv->name, node->priv->name,
531  pcmk__str_casei)) {
532  cancel_if_running(rsc, node, op->key, op->name, op->interval_ms);
533  continue;
534  }
535 
536  // Recurring action on this node is optional if it's already active here
537  possible_matches = find_actions_exact(rsc->priv->actions, op->key,
538  stop_node);
539  is_optional = (possible_matches != NULL);
540  g_list_free(possible_matches);
541 
542  pcmk__rsc_trace(rsc,
543  "Creating %s recurring action %s for %s (%s "
544  PCMK_ROLE_STOPPED " on %s)",
545  (is_optional? "optional" : "mandatory"),
546  op->key, op->id, rsc->id, pcmk__node_name(stop_node));
547 
548  stopped_mon = custom_action(rsc, strdup(op->key), op->name, stop_node,
549  is_optional, rsc->priv->scheduler);
550 
552 
553  if (pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
554  order_after_probes(rsc, stop_node, stopped_mon);
555  }
556 
557  /* The recurring action is for the inactive role, so it shouldn't be
558  * performed until the resource is inactive.
559  */
560  order_after_stops(rsc, stop_node, stopped_mon);
561 
562  if (!stop_node->details->online || stop_node->details->unclean) {
563  pcmk__rsc_debug(rsc, "%s unrunnable on %s: node unavailable)",
564  stopped_mon->uuid, pcmk__node_name(stop_node));
566  }
567 
568  if (pcmk_is_set(stopped_mon->flags, pcmk__action_runnable)
569  && !pcmk_is_set(stopped_mon->flags, pcmk__action_optional)) {
570  crm_notice("Start recurring %s-interval %s for "
571  PCMK_ROLE_STOPPED " %s on %s",
572  pcmk__readable_interval(op->interval_ms),
573  stopped_mon->task, rsc->id, pcmk__node_name(stop_node));
574  }
575  }
576 }
577 
584 void
586 {
587  pcmk_action_t *start = NULL;
588 
589  if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
590  pcmk__rsc_trace(rsc,
591  "Skipping recurring actions for blocked resource %s",
592  rsc->id);
593  return;
594  }
595 
597  pcmk__rsc_trace(rsc,
598  "Skipping recurring actions for %s "
599  "in maintenance mode", rsc->id);
600  return;
601  }
602 
603  if (rsc->priv->assigned_node == NULL) {
604  // Recurring actions for active roles not needed
605 
606  } else if (rsc->priv->assigned_node->details->maintenance) {
607  pcmk__rsc_trace(rsc,
608  "Skipping recurring actions for %s on %s "
609  "in maintenance mode",
610  rsc->id, pcmk__node_name(rsc->priv->assigned_node));
611 
612  } else if ((rsc->priv->next_role != pcmk_role_stopped)
613  || !pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
614  // Recurring actions for active roles needed
615  start = start_action(rsc, rsc->priv->assigned_node, TRUE);
616  }
617 
618  pcmk__rsc_trace(rsc, "Creating any recurring actions needed for %s",
619  rsc->id);
620 
621  for (xmlNode *op = pcmk__xe_first_child(rsc->priv->ops_xml, PCMK_XE_OP,
622  NULL, NULL);
623  op != NULL; op = pcmk__xe_next(op, PCMK_XE_OP)) {
624 
625  struct op_history op_history = { NULL, };
626 
627  if (!is_recurring_history(rsc, op, &op_history)) {
628  continue;
629  }
630 
631  if (start != NULL) {
632  recurring_op_for_active(rsc, start, rsc->priv->assigned_node,
633  &op_history);
634  }
635  recurring_op_for_inactive(rsc, rsc->priv->assigned_node,
636  &op_history);
637 
638  free(op_history.key);
639  }
640 }
641 
655  guint interval_ms, const pcmk_node_t *node)
656 {
657  pcmk_action_t *cancel_op = NULL;
658  char *key = NULL;
659  char *interval_ms_s = NULL;
660 
661  pcmk__assert((rsc != NULL) && (task != NULL) && (node != NULL));
662 
663  key = pcmk__op_key(rsc->id, task, interval_ms);
664 
665  /* This finds an existing action by key, so custom_action() does not change
666  * cancel_op->task.
667  */
668  cancel_op = custom_action(rsc, key, PCMK_ACTION_CANCEL, node, FALSE,
669  rsc->priv->scheduler);
670 
671  pcmk__str_update(&(cancel_op->task), PCMK_ACTION_CANCEL);
672  pcmk__str_update(&(cancel_op->cancel_task), task);
673 
674  interval_ms_s = crm_strdup_printf("%u", interval_ms);
675  pcmk__insert_meta(cancel_op, PCMK_XA_OPERATION, task);
676  pcmk__insert_meta(cancel_op, PCMK_META_INTERVAL, interval_ms_s);
677  free(interval_ms_s);
678 
679  return cancel_op;
680 }
681 
693 void
694 pcmk__schedule_cancel(pcmk_resource_t *rsc, const char *call_id,
695  const char *task, guint interval_ms,
696  const pcmk_node_t *node, const char *reason)
697 {
698  pcmk_action_t *cancel = NULL;
699 
700  CRM_CHECK((rsc != NULL) && (task != NULL)
701  && (node != NULL) && (reason != NULL),
702  return);
703 
704  crm_info("Recurring %s-interval %s for %s will be stopped on %s: %s",
705  pcmk__readable_interval(interval_ms), task, rsc->id,
706  pcmk__node_name(node), reason);
707  cancel = pcmk__new_cancel_action(rsc, task, interval_ms, node);
708  pcmk__insert_meta(cancel, PCMK__XA_CALL_ID, call_id);
709 
710  // Cancellations happen after stops
711  pcmk__new_ordering(rsc, stop_key(rsc), NULL, rsc, NULL, cancel,
713 }
714 
724 void
726  guint interval_ms, pcmk_node_t *node)
727 {
728  pcmk_action_t *op = NULL;
729 
730  trigger_unfencing(rsc, node, "Device parameters changed (reschedule)",
731  NULL, rsc->priv->scheduler);
732  op = custom_action(rsc, pcmk__op_key(rsc->id, task, interval_ms),
733  task, node, TRUE, rsc->priv->scheduler);
735 }
736 
745 bool
747 {
748  guint interval_ms = 0;
749 
751  &interval_ms) != pcmk_rc_ok) {
752  return false;
753  }
754  return (interval_ms > 0);
755 }
#define LOG_TRACE
Definition: logging.h:38
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
void trigger_unfencing(pcmk_resource_t *rsc, pcmk_node_t *node, const char *reason, pcmk_action_t *dependency, pcmk_scheduler_t *scheduler)
Definition: utils.c:610
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
#define crm_notice(fmt, args...)
Definition: logging.h:365
&#39;then&#39; is runnable (and migratable) only if &#39;first&#39; is runnable
#define PCMK_XA_NAME
Definition: xml_names.h:330
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition: roles.c:23
G_GNUC_INTERNAL void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
Stopped.
Definition: roles.h:36
const char * name
Definition: cib.c:26
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_info(rsc, fmt, args...)
Service active and promoted.
Definition: results.h:241
#define reload_key(rsc)
Definition: internal.h:197
#define pcmk__insert_meta(obj, name, value)
#define pcmk__config_err(fmt...)
#define PCMK_ACTION_MONITOR
Definition: actions.h:51
#define PCMK_ACTION_MIGRATE_TO
Definition: actions.h:50
Promoted.
Definition: roles.h:39
gboolean unclean
Definition: nodes.h:58
#define demote_key(rsc)
Definition: internal.h:200
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:1517
#define PCMK_XA_OPERATION
Definition: xml_names.h:349
const char * action
Definition: pcmk_fence.c:32
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition: roles.c:51
#define pcmk__rsc_debug(rsc, fmt, args...)
#define PCMK_ACTION_RELOAD_AGENT
Definition: actions.h:61
pcmk__node_private_t * priv
Definition: nodes.h:85
GList * find_actions_exact(GList *input, const char *key, const pcmk_node_t *on_node)
Definition: pe_actions.c:1479
#define PCMK_ACTION_DEMOTE
Definition: actions.h:40
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:303
bool pcmk__action_is_recurring(const pcmk_action_t *action)
#define crm_debug(fmt, args...)
Definition: logging.h:370
pcmk_scheduler_t * scheduler
Actions are ordered (optionally, if no other flags are set)
#define pcmk__clear_action_flags(action, flags_to_clear)
#define stop_key(rsc)
Definition: internal.h:196
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
Definition: strings.c:452
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define PCMK_ROLE_STOPPED
Definition: roles.h:25
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:149
#define promote_key(rsc)
Definition: internal.h:199
gboolean maintenance
Definition: nodes.h:66
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
Unpromoted.
Definition: roles.h:38
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1278
Wrappers for and extensions to libxml2.
rsc_role_e
Definition: roles.h:34
#define PCMK_ACTION_STOP
Definition: actions.h:66
void pcmk__create_recurring_actions(pcmk_resource_t *rsc)
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:195
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1051
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition: utils.c:465
uint32_t id
Definition: cpg.c:48
Service safely stopped.
Definition: results.h:240
#define PCMK_ACTION_CANCEL
Definition: actions.h:36
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:1093
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
#define pcmk__assert(expr)
void pe__add_action_expected_result(pcmk_action_t *action, int expected_result)
Definition: pe_actions.c:1776
#define PCMK_XE_OP
Definition: xml_names.h:146
xmlNode * pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, bool include_disabled)
Definition: pe_actions.c:137
uint32_t(* action_flags)(pcmk_action_t *action, const pcmk_node_t *node)
#define PCMK_META_INTERVAL
Definition: options.h:91
GList * nodes
Definition: scheduler.h:97
#define start_action(rsc, node, optional)
Definition: internal.h:210
void pcmk__schedule_cancel(pcmk_resource_t *rsc, const char *call_id, const char *task, guint interval_ms, const pcmk_node_t *node, const char *reason)
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:49
Started.
Definition: roles.h:37
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
#define PCMK__XA_CALL_ID
#define pcmk__set_action_flags(action, flags_to_set)
unsigned long long flags
Definition: resources.h:69
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:2206
gboolean online
Definition: nodes.h:50
void pcmk__reschedule_recurring(pcmk_resource_t *rsc, const char *task, guint interval_ms, pcmk_node_t *node)
Resource role is unknown.
Definition: roles.h:35
#define start_key(rsc)
Definition: internal.h:198
pcmk_action_t * pcmk__new_cancel_action(pcmk_resource_t *rsc, const char *task, guint interval_ms, const pcmk_node_t *node)
struct pcmk__node_details * details
Definition: nodes.h:82
#define PCMK_XA_ROLE
Definition: xml_names.h:387
#define crm_info(fmt, args...)
Definition: logging.h:367
const pcmk__assignment_methods_t * cmds
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1