pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
pcmk_graph_consumer.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 <sys/param.h>
13 #include <sys/stat.h>
14 
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/common/xml.h>
19 #include <crm/lrmd_internal.h>
20 #include <pacemaker-internal.h>
21 
22 
23 /*
24  * Functions for updating graph
25  */
26 
44 static void
45 update_synapse_ready(pcmk__graph_synapse_t *synapse, int action_id)
46 {
47  if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
48  return; // All inputs have already been confirmed
49  }
50 
51  // Presume ready until proven otherwise
53 
54  for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
55  pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
56 
57  if (prereq->id == action_id) {
58  crm_trace("Confirming input %d of synapse %d",
59  action_id, synapse->id);
61 
62  } else if (!pcmk_is_set(prereq->flags, pcmk__graph_action_confirmed)) {
64  crm_trace("Synapse %d still not ready after action %d",
65  synapse->id, action_id);
66  }
67  }
68  if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
69  crm_trace("Synapse %d is now ready to execute", synapse->id);
70  }
71 }
72 
80 static void
81 update_synapse_confirmed(pcmk__graph_synapse_t *synapse, int action_id)
82 {
83  bool all_confirmed = true;
84 
85  for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
87 
88  if (action->id == action_id) {
89  crm_trace("Confirmed action %d of synapse %d",
90  action_id, synapse->id);
92 
93  } else if (all_confirmed &&
95  all_confirmed = false;
96  crm_trace("Synapse %d still not confirmed after action %d",
97  synapse->id, action_id);
98  }
99  }
100 
101  if (all_confirmed
102  && !pcmk_is_set(synapse->flags, pcmk__synapse_confirmed)) {
103  crm_trace("Confirmed synapse %d", synapse->id);
105  }
106 }
107 
115 void
117 {
118  for (GList *lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
119  pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
120 
121  if (pcmk_any_flags_set(synapse->flags,
123  continue; // This synapse already completed
124 
125  } else if (pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
126  update_synapse_confirmed(synapse, action->id);
127 
128  } else if (!pcmk_is_set(action->flags, pcmk__graph_action_failed)
129  || (synapse->priority == INFINITY)) {
130  update_synapse_ready(synapse, action->id);
131  }
132  }
133 }
134 
135 
136 /*
137  * Functions for executing graph
138  */
139 
140 /* A transition graph consists of various types of actions. The library caller
141  * registers execution functions for each action type, which will be stored
142  * here.
143  */
144 static pcmk__graph_functions_t *graph_fns = NULL;
145 
152 void
154 {
155  crm_debug("Setting custom functions for executing transition graphs");
156  graph_fns = fns;
157 
158  CRM_ASSERT(graph_fns != NULL);
159  CRM_ASSERT(graph_fns->rsc != NULL);
160  CRM_ASSERT(graph_fns->cluster != NULL);
161  CRM_ASSERT(graph_fns->pseudo != NULL);
162  CRM_ASSERT(graph_fns->fence != NULL);
163 }
164 
174 static bool
175 should_fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
176 {
177  GList *lpc = NULL;
178 
180  for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
181  pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
182 
184  crm_trace("Input %d for synapse %d not yet confirmed",
185  prereq->id, synapse->id);
187  break;
188 
189  } else if (pcmk_is_set(prereq->flags, pcmk__graph_action_failed)
190  && !pcmk_is_set(prereq->flags,
192  crm_trace("Input %d for synapse %d confirmed but failed",
193  prereq->id, synapse->id);
195  break;
196  }
197  }
198  if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
199  crm_trace("Synapse %d is ready to execute", synapse->id);
200  } else {
201  return false;
202  }
203 
204  for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
205  pcmk__graph_action_t *a = (pcmk__graph_action_t *) lpc->data;
206 
207  if (a->type == pcmk__pseudo_graph_action) {
208  /* None of the below applies to pseudo ops */
209 
210  } else if (synapse->priority < graph->abort_priority) {
211  crm_trace("Skipping synapse %d: priority %d is less than "
212  "abort priority %d",
213  synapse->id, synapse->priority, graph->abort_priority);
214  graph->skipped++;
215  return false;
216 
217  } else if (graph_fns->allowed && !(graph_fns->allowed(graph, a))) {
218  crm_trace("Deferring synapse %d: not allowed", synapse->id);
219  return false;
220  }
221  }
222 
223  return true;
224 }
225 
235 static int
236 initiate_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
237 {
238  const char *id = ID(action->xml);
239 
240  CRM_CHECK(id != NULL, return EINVAL);
242  return pcmk_rc_already);
243 
245  switch (action->type) {
247  crm_trace("Executing pseudo-action %d (%s)", action->id, id);
248  return graph_fns->pseudo(graph, action);
249 
251  crm_trace("Executing resource action %d (%s)", action->id, id);
252  return graph_fns->rsc(graph, action);
253 
255  if (pcmk__str_eq(crm_element_value(action->xml, XML_LRM_ATTR_TASK),
257  crm_trace("Executing fencing action %d (%s)",
258  action->id, id);
259  return graph_fns->fence(graph, action);
260  }
261  crm_trace("Executing cluster action %d (%s)", action->id, id);
262  return graph_fns->cluster(graph, action);
263 
264  default:
265  crm_err("Unsupported graph action type <%s " XML_ATTR_ID "='%s'> "
266  "(bug?)",
267  action->xml->name, id);
268  return EINVAL;
269  }
270 }
271 
281 static int
282 fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
283 {
285  for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
287  int rc = initiate_action(graph, action);
288 
289  if (rc != pcmk_rc_ok) {
290  crm_err("Failed initiating <%s " XML_ATTR_ID "=%d> in synapse %d: "
291  "%s",
292  action->xml->name, action->id, synapse->id,
293  pcmk_rc_str(rc));
298  return pcmk_rc_error;
299  }
300  }
301  return pcmk_rc_ok;
302 }
303 
315 static int
316 pseudo_action_dummy(pcmk__graph_t *graph, pcmk__graph_action_t *action)
317 {
318  static int fail = -1;
319 
320  if (fail < 0) {
321  long long fail_ll;
322 
323  if ((pcmk__scan_ll(getenv("PE_fail"), &fail_ll, 0LL) == pcmk_rc_ok)
324  && (fail_ll > 0LL) && (fail_ll <= INT_MAX)) {
325  fail = (int) fail_ll;
326  } else {
327  fail = 0;
328  }
329  }
330 
331  if (action->id == fail) {
332  crm_err("Dummy event handler: pretending action %d failed", action->id);
334  graph->abort_priority = INFINITY;
335  } else {
336  crm_trace("Dummy event handler: action %d initiated", action->id);
337  }
339  pcmk__update_graph(graph, action);
340  return pcmk_rc_ok;
341 }
342 
343 static pcmk__graph_functions_t default_fns = {
344  pseudo_action_dummy,
345  pseudo_action_dummy,
346  pseudo_action_dummy,
347  pseudo_action_dummy
348 };
349 
360 {
361  GList *lpc = NULL;
362  int log_level = LOG_DEBUG;
363  enum pcmk__graph_status pass_result = pcmk__graph_active;
364  const char *status = "In progress";
365 
366  if (graph_fns == NULL) {
367  graph_fns = &default_fns;
368  }
369  if (graph == NULL) {
370  return pcmk__graph_complete;
371  }
372 
373  graph->fired = 0;
374  graph->pending = 0;
375  graph->skipped = 0;
376  graph->completed = 0;
377  graph->incomplete = 0;
378 
379  // Count completed and in-flight synapses
380  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
381  pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
382 
383  if (pcmk_is_set(synapse->flags, pcmk__synapse_confirmed)) {
384  graph->completed++;
385 
386  } else if (!pcmk_is_set(synapse->flags, pcmk__synapse_failed)
387  && pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
388  graph->pending++;
389  }
390  }
391  crm_trace("Executing graph %d (%d synapses already completed, %d pending)",
392  graph->id, graph->completed, graph->pending);
393 
394  // Execute any synapses that are ready
395  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
396  pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
397 
398  if ((graph->batch_limit > 0)
399  && (graph->pending >= graph->batch_limit)) {
400 
401  crm_debug("Throttling graph execution: batch limit (%d) reached",
402  graph->batch_limit);
403  break;
404 
405  } else if (pcmk_is_set(synapse->flags, pcmk__synapse_failed)) {
406  graph->skipped++;
407  continue;
408 
409  } else if (pcmk_any_flags_set(synapse->flags,
412  continue; // Already handled
413 
414  } else if (should_fire_synapse(graph, synapse)) {
415  graph->fired++;
416  if (fire_synapse(graph, synapse) != pcmk_rc_ok) {
417  crm_err("Synapse %d failed to fire", synapse->id);
418  log_level = LOG_ERR;
419  graph->abort_priority = INFINITY;
420  graph->incomplete++;
421  graph->fired--;
422  }
423 
424  if (!(pcmk_is_set(synapse->flags, pcmk__synapse_confirmed))) {
425  graph->pending++;
426  }
427 
428  } else {
429  crm_trace("Synapse %d cannot fire", synapse->id);
430  graph->incomplete++;
431  }
432  }
433 
434  if ((graph->pending == 0) && (graph->fired == 0)) {
435  graph->complete = true;
436 
437  if ((graph->incomplete != 0) && (graph->abort_priority <= 0)) {
438  log_level = LOG_WARNING;
439  pass_result = pcmk__graph_terminated;
440  status = "Terminated";
441 
442  } else if (graph->skipped != 0) {
443  log_level = LOG_NOTICE;
444  pass_result = pcmk__graph_complete;
445  status = "Stopped";
446 
447  } else {
448  log_level = LOG_NOTICE;
449  pass_result = pcmk__graph_complete;
450  status = "Complete";
451  }
452 
453  } else if (graph->fired == 0) {
454  pass_result = pcmk__graph_pending;
455  }
456 
457  do_crm_log(log_level,
458  "Transition %d (Complete=%d, Pending=%d,"
459  " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
460  graph->id, graph->completed, graph->pending, graph->fired,
461  graph->skipped, graph->incomplete, graph->source, status);
462 
463  return pass_result;
464 }
465 
466 
467 /*
468  * Functions for unpacking transition graph XML into structs
469  */
470 
480 static pcmk__graph_action_t *
481 unpack_action(pcmk__graph_synapse_t *parent, xmlNode *xml_action)
482 {
483  enum pcmk__graph_action_type action_type;
485  const char *value = ID(xml_action);
486 
487  if (value == NULL) {
488  crm_err("Ignoring transition graph action without id (bug?)");
489  crm_log_xml_trace(xml_action, "invalid");
490  return NULL;
491  }
492 
493  if (pcmk__xe_is(xml_action, XML_GRAPH_TAG_RSC_OP)) {
494  action_type = pcmk__rsc_graph_action;
495 
496  } else if (pcmk__xe_is(xml_action, XML_GRAPH_TAG_PSEUDO_EVENT)) {
497  action_type = pcmk__pseudo_graph_action;
498 
499  } else if (pcmk__xe_is(xml_action, XML_GRAPH_TAG_CRM_EVENT)) {
500  action_type = pcmk__cluster_graph_action;
501 
502  } else {
503  crm_err("Ignoring transition graph action of unknown type '%s' (bug?)",
504  xml_action->name);
505  crm_log_xml_trace(xml_action, "invalid");
506  return NULL;
507  }
508 
509  action = calloc(1, sizeof(pcmk__graph_action_t));
510  if (action == NULL) {
511  crm_perror(LOG_CRIT, "Cannot unpack transition graph action");
512  crm_log_xml_trace(xml_action, "lost");
513  return NULL;
514  }
515 
516  pcmk__scan_min_int(value, &(action->id), -1);
518  action->xml = copy_xml(xml_action);
519  action->synapse = parent;
520  action->type = action_type;
521  action->params = xml2list(action->xml);
522 
523  value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
524  pcmk__scan_min_int(value, &(action->timeout), 0);
525 
526  /* Take start-delay into account for the timeout of the action timer */
527  value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
528  {
529  int start_delay;
530 
531  pcmk__scan_min_int(value, &start_delay, 0);
532  action->timeout += start_delay;
533  }
534 
535  if (pcmk__guint_from_hash(action->params,
537  &(action->interval_ms)) != pcmk_rc_ok) {
538  action->interval_ms = 0;
539  }
540 
541  value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
542  if (value != NULL) {
543  int can_fail = 0;
544 
545  if ((crm_str_to_boolean(value, &can_fail) > 0) && (can_fail > 0)) {
547  } else {
549  }
550 
551 #ifndef PCMK__COMPAT_2_0
553  crm_warn("Support for the can_fail meta-attribute is deprecated"
554  " and will be removed in a future release");
555  }
556 #endif
557  }
558 
559  crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
560 
561  return action;
562 }
563 
573 static pcmk__graph_synapse_t *
574 unpack_synapse(pcmk__graph_t *new_graph, const xmlNode *xml_synapse)
575 {
576  const char *value = NULL;
577  xmlNode *action_set = NULL;
578  pcmk__graph_synapse_t *new_synapse = NULL;
579 
580  crm_trace("Unpacking synapse %s", ID(xml_synapse));
581 
582  new_synapse = calloc(1, sizeof(pcmk__graph_synapse_t));
583  if (new_synapse == NULL) {
584  return NULL;
585  }
586 
587  pcmk__scan_min_int(ID(xml_synapse), &(new_synapse->id), 0);
588 
589  value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
590  pcmk__scan_min_int(value, &(new_synapse->priority), 0);
591 
592  CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
593  return NULL);
594 
595  new_graph->num_synapses++;
596 
597  crm_trace("Unpacking synapse %s action sets",
598  crm_element_value(xml_synapse, XML_ATTR_ID));
599 
600  for (action_set = first_named_child(xml_synapse, "action_set");
601  action_set != NULL; action_set = crm_next_same_xml(action_set)) {
602 
603  for (xmlNode *action = pcmk__xml_first_child(action_set);
604  action != NULL; action = pcmk__xml_next(action)) {
605 
606  pcmk__graph_action_t *new_action = unpack_action(new_synapse,
607  action);
608 
609  if (new_action == NULL) {
610  continue;
611  }
612 
613  crm_trace("Adding action %d to synapse %d",
614  new_action->id, new_synapse->id);
615  new_graph->num_actions++;
616  new_synapse->actions = g_list_append(new_synapse->actions,
617  new_action);
618  }
619  }
620 
621  crm_trace("Unpacking synapse %s inputs", ID(xml_synapse));
622 
623  for (xmlNode *inputs = first_named_child(xml_synapse, "inputs");
624  inputs != NULL; inputs = crm_next_same_xml(inputs)) {
625 
626  for (xmlNode *trigger = first_named_child(inputs, "trigger");
627  trigger != NULL; trigger = crm_next_same_xml(trigger)) {
628 
629  for (xmlNode *input = pcmk__xml_first_child(trigger);
630  input != NULL; input = pcmk__xml_next(input)) {
631 
632  pcmk__graph_action_t *new_input = unpack_action(new_synapse,
633  input);
634 
635  if (new_input == NULL) {
636  continue;
637  }
638 
639  crm_trace("Adding input %d to synapse %d",
640  new_input->id, new_synapse->id);
641 
642  new_synapse->inputs = g_list_append(new_synapse->inputs,
643  new_input);
644  }
645  }
646  }
647 
648  return new_synapse;
649 }
650 
677 pcmk__unpack_graph(const xmlNode *xml_graph, const char *reference)
678 {
679  pcmk__graph_t *new_graph = NULL;
680 
681  new_graph = calloc(1, sizeof(pcmk__graph_t));
682  if (new_graph == NULL) {
683  return NULL;
684  }
685 
686  new_graph->source = strdup((reference == NULL)? "unknown" : reference);
687  if (new_graph->source == NULL) {
688  free(new_graph);
689  return NULL;
690  }
691 
692  new_graph->id = -1;
693  new_graph->abort_priority = 0;
694  new_graph->network_delay = 0;
695  new_graph->stonith_timeout = 0;
696  new_graph->completion_action = pcmk__graph_done;
697 
698  // Parse top-level attributes from <transition_graph>
699  if (xml_graph != NULL) {
700  const char *buf = crm_element_value(xml_graph, "transition_id");
701 
702  CRM_CHECK(buf != NULL, free(new_graph);
703  return NULL);
704  pcmk__scan_min_int(buf, &(new_graph->id), -1);
705 
706  buf = crm_element_value(xml_graph, "cluster-delay");
707  CRM_CHECK(buf != NULL, free(new_graph);
708  return NULL);
709  new_graph->network_delay = crm_parse_interval_spec(buf);
710 
711  buf = crm_element_value(xml_graph, "stonith-timeout");
712  if (buf == NULL) {
713  new_graph->stonith_timeout = new_graph->network_delay;
714  } else {
715  new_graph->stonith_timeout = crm_parse_interval_spec(buf);
716  }
717 
718  // Use 0 (dynamic limit) as default/invalid, -1 (no limit) as minimum
719  buf = crm_element_value(xml_graph, "batch-limit");
720  if ((buf == NULL)
721  || (pcmk__scan_min_int(buf, &(new_graph->batch_limit),
722  -1) != pcmk_rc_ok)) {
723  new_graph->batch_limit = 0;
724  }
725 
726  buf = crm_element_value(xml_graph, "migration-limit");
727  pcmk__scan_min_int(buf, &(new_graph->migration_limit), -1);
728 
729  pcmk__str_update(&(new_graph->failed_stop_offset),
730  crm_element_value(xml_graph, "failed-stop-offset"));
732  crm_element_value(xml_graph, "failed-start-offset"));
733 
734  if (crm_element_value_epoch(xml_graph, "recheck-by",
735  &(new_graph->recheck_by)) != pcmk_ok) {
736  new_graph->recheck_by = 0;
737  }
738  }
739 
740  // Unpack each child <synapse> element
741  for (const xmlNode *synapse_xml = first_named_child(xml_graph, "synapse");
742  synapse_xml != NULL; synapse_xml = crm_next_same_xml(synapse_xml)) {
743 
744  pcmk__graph_synapse_t *new_synapse = unpack_synapse(new_graph,
745  synapse_xml);
746 
747  if (new_synapse != NULL) {
748  new_graph->synapses = g_list_append(new_graph->synapses,
749  new_synapse);
750  }
751  }
752 
753  crm_debug("Unpacked transition %d from %s: %d actions in %d synapses",
754  new_graph->id, new_graph->source, new_graph->num_actions,
755  new_graph->num_synapses);
756 
757  return new_graph;
758 }
759 
760 
761 /*
762  * Functions for freeing transition graph objects
763  */
764 
771 static void
772 free_graph_action(gpointer user_data)
773 {
774  pcmk__graph_action_t *action = user_data;
775 
776  if (action->timer != 0) {
777  crm_warn("Cancelling timer for graph action %d", action->id);
778  g_source_remove(action->timer);
779  }
780  if (action->params != NULL) {
781  g_hash_table_destroy(action->params);
782  }
783  free_xml(action->xml);
784  free(action);
785 }
786 
793 static void
794 free_graph_synapse(gpointer user_data)
795 {
796  pcmk__graph_synapse_t *synapse = user_data;
797 
798  g_list_free_full(synapse->actions, free_graph_action);
799  g_list_free_full(synapse->inputs, free_graph_action);
800  free(synapse);
801 }
802 
809 void
811 {
812  if (graph != NULL) {
813  g_list_free_full(graph->synapses, free_graph_synapse);
814  free(graph->source);
815  free(graph->failed_stop_offset);
816  free(graph->failed_start_offset);
817  free(graph);
818  }
819 }
820 
821 
822 /*
823  * Other transition graph utilities
824  */
825 
839 pcmk__event_from_graph_action(const xmlNode *resource,
841  int status, int rc, const char *exit_reason)
842 {
843  lrmd_event_data_t *op = NULL;
844  GHashTableIter iter;
845  const char *name = NULL;
846  const char *value = NULL;
847  xmlNode *action_resource = NULL;
848 
849  CRM_CHECK(action != NULL, return NULL);
850  CRM_CHECK(action->type == pcmk__rsc_graph_action, return NULL);
851 
852  action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
853  CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "invalid");
854  return NULL);
855 
856  op = lrmd_new_event(ID(action_resource),
858  action->interval_ms);
859  lrmd__set_result(op, rc, status, exit_reason);
860  op->t_run = time(NULL);
861  op->t_rcchange = op->t_run;
862  op->params = pcmk__strkey_table(free, free);
863 
864  g_hash_table_iter_init(&iter, action->params);
865  while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
866  g_hash_table_insert(op->params, strdup(name), strdup(value));
867  }
868 
869  for (xmlNode *xop = pcmk__xml_first_child(resource); xop != NULL;
870  xop = pcmk__xml_next(xop)) {
871  int tmp = 0;
872 
874  crm_debug("Got call_id=%d for %s", tmp, ID(resource));
875  if (tmp > op->call_id) {
876  op->call_id = tmp;
877  }
878  }
879 
880  op->call_id++;
881  return op;
882 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
A dumping ground.
#define pcmk__set_synapse_flags(synapse, flags_to_set)
#define INFINITY
Definition: crm.h:98
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
const char * name
Definition: cib.c:26
lrmd_event_data_t * pcmk__event_from_graph_action(const xmlNode *resource, const pcmk__graph_action_t *action, int status, int rc, const char *exit_reason)
void pcmk__free_graph(pcmk__graph_t *graph)
char * failed_start_offset
Failcount after one failed start action.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2484
pcmk__graph_action_type
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:300
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:334
unsigned int t_rcchange
Definition: lrmd_events.h:75
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:336
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:501
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
enum pcmk__graph_action_type type
int(* pseudo)(pcmk__graph_t *graph, pcmk__graph_action_t *action)
const char * action
Definition: pcmk_fence.c:30
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:335
int(* fence)(pcmk__graph_t *graph, pcmk__graph_action_t *action)
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:286
void pcmk__update_graph(pcmk__graph_t *graph, const pcmk__graph_action_t *action)
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:789
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:306
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:97
#define crm_warn(fmt, args...)
Definition: logging.h:382
GHashTable * xml2list(const xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:826
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:311
char * failed_stop_offset
Failcount after one failed stop action.
#define crm_debug(fmt, args...)
Definition: logging.h:386
enum pcmk__graph_next completion_action
pcmk__graph_status
#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
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:235
#define crm_trace(fmt, args...)
Definition: logging.h:387
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:175
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
time_t recheck_by
Time (from epoch) by which the controller should re-run the scheduler.
pcmk__graph_t * pcmk__unpack_graph(const xmlNode *xml_graph, const char *reference)
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1193
Wrappers for and extensions to libxml2.
enum pcmk__graph_status pcmk__execute_graph(pcmk__graph_t *graph)
#define crm_log_xml_warn(xml, text)
Definition: logging.h:391
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_STONITH
Definition: actions.h:73
#define pcmk__clear_graph_action_flags(action, flags_to_clear)
#define pcmk__clear_synapse_flags(synapse, flags_to_clear)
void free_xml(xmlNode *child)
Definition: xml.c:783
bool(* allowed)(pcmk__graph_t *graph, pcmk__graph_action_t *action)
void pcmk__set_graph_functions(pcmk__graph_functions_t *fns)
unsigned int t_run
Definition: lrmd_events.h:72
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:424
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:608
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:323
int(* rsc)(pcmk__graph_t *graph, pcmk__graph_action_t *action)
#define CRM_META
Definition: crm.h:79
#define crm_err(fmt, args...)
Definition: logging.h:381
#define CRM_ASSERT(expr)
Definition: results.h:42
#define pcmk__set_graph_action_flags(action, flags_to_set)
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:271
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
Definition: lrmd_client.c:2506
xmlNode * input
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:318
#define pcmk_ok
Definition: results.h:68
int(* cluster)(pcmk__graph_t *graph, pcmk__graph_action_t *action)
#define crm_log_xml_trace(xml, text)
Definition: logging.h:395
#define ID(x)
Definition: msg_xml.h:474
const char * parent
Definition: cib.c:27
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Create a new lrmd_event_data_t object.
Definition: lrmd_client.c:195
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2510