pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
pcmk_sched_graph.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 <sys/param.h>
13 #include <crm/crm.h>
14 #include <crm/cib.h>
15 #include <crm/msg_xml.h>
16 #include <crm/common/xml.h>
17 
18 #include <glib.h>
19 
20 #include <pacemaker-internal.h>
21 
23 gboolean rsc_update_action(pe_action_t * first, pe_action_t * then, enum pe_ordering type);
24 
25 static enum pe_action_flags
26 get_action_flags(pe_action_t * action, pe_node_t * node)
27 {
28  enum pe_action_flags flags = action->flags;
29 
30  if (action->rsc) {
31  flags = action->rsc->cmds->action_flags(action, NULL);
32 
33  if (pe_rsc_is_clone(action->rsc) && node) {
34 
35  /* We only care about activity on $node */
36  enum pe_action_flags clone_flags = action->rsc->cmds->action_flags(action, node);
37 
38  /* Go to great lengths to ensure the correct value for pe_action_runnable...
39  *
40  * If we are a clone, then for _ordering_ constraints, it's only relevant
41  * if we are runnable _anywhere_.
42  *
43  * This only applies to _runnable_ though, and only for ordering constraints.
44  * If this function is ever used during colocation, then we'll need additional logic
45  *
46  * Not very satisfying, but it's logical and appears to work well.
47  */
48  if (!pcmk_is_set(clone_flags, pe_action_runnable)
50 
51  pe__set_raw_action_flags(clone_flags, action->rsc->id,
53  }
54  flags = clone_flags;
55  }
56  }
57  return flags;
58 }
59 
60 static char *
61 convert_non_atomic_uuid(char *old_uuid, pe_resource_t * rsc, gboolean allow_notify,
62  gboolean free_original)
63 {
64  guint interval_ms = 0;
65  char *uuid = NULL;
66  char *rid = NULL;
67  char *raw_task = NULL;
68  int task = no_action;
69 
70  CRM_ASSERT(rsc);
71  pe_rsc_trace(rsc, "Processing %s", old_uuid);
72  if (old_uuid == NULL) {
73  return NULL;
74 
75  } else if (strstr(old_uuid, "notify") != NULL) {
76  goto done; /* no conversion */
77 
78  } else if (rsc->variant < pe_group) {
79  goto done; /* no conversion */
80  }
81 
82  CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval_ms));
83  if (interval_ms > 0) {
84  goto done; /* no conversion */
85  }
86 
87  task = text2task(raw_task);
88  switch (task) {
89  case stop_rsc:
90  case start_rsc:
91  case action_notify:
92  case action_promote:
93  case action_demote:
94  break;
95  case stopped_rsc:
96  case started_rsc:
97  case action_notified:
98  case action_promoted:
99  case action_demoted:
100  task--;
101  break;
102  case monitor_rsc:
103  case shutdown_crm:
104  case stonith_node:
105  task = no_action;
106  break;
107  default:
108  crm_err("Unknown action: %s", raw_task);
109  task = no_action;
110  break;
111  }
112 
113  if (task != no_action) {
114  if (pcmk_is_set(rsc->flags, pe_rsc_notify) && allow_notify) {
115  uuid = pcmk__notify_key(rid, "confirmed-post", task2text(task + 1));
116 
117  } else {
118  uuid = pcmk__op_key(rid, task2text(task + 1), 0);
119  }
120  pe_rsc_trace(rsc, "Converted %s -> %s", old_uuid, uuid);
121  }
122 
123  done:
124  if (uuid == NULL) {
125  uuid = strdup(old_uuid);
126  }
127 
128  if (free_original) {
129  free(old_uuid);
130  }
131 
132  free(raw_task);
133  free(rid);
134  return uuid;
135 }
136 
137 static pe_action_t *
138 rsc_expand_action(pe_action_t * action)
139 {
140  gboolean notify = FALSE;
141  pe_action_t *result = action;
142  pe_resource_t *rsc = action->rsc;
143 
144  if (rsc == NULL) {
145  return action;
146  }
147 
148  if ((rsc->parent == NULL)
149  || (pe_rsc_is_clone(rsc) && (rsc->parent->variant == pe_container))) {
150  /* Only outermost resources have notification actions.
151  * The exception is those in bundles.
152  */
153  notify = pcmk_is_set(rsc->flags, pe_rsc_notify);
154  }
155 
156  if (rsc->variant >= pe_group) {
157  /* Expand 'start' -> 'started' */
158  char *uuid = NULL;
159 
160  uuid = convert_non_atomic_uuid(action->uuid, rsc, notify, FALSE);
161  if (uuid) {
162  pe_rsc_trace(rsc, "Converting %s to %s %d", action->uuid, uuid,
164  result = find_first_action(rsc->actions, uuid, NULL, NULL);
165  if (result == NULL) {
166  crm_err("Couldn't expand %s to %s in %s", action->uuid, uuid, rsc->id);
167  result = action;
168  }
169  free(uuid);
170  }
171  }
172  return result;
173 }
174 
175 static enum pe_graph_flags
176 graph_update_action(pe_action_t * first, pe_action_t * then, pe_node_t * node,
177  enum pe_action_flags first_flags, enum pe_action_flags then_flags,
178  pe_action_wrapper_t *order, pe_working_set_t *data_set)
179 {
180  enum pe_graph_flags changed = pe_graph_none;
181  enum pe_ordering type = order->type;
182  gboolean processed = FALSE;
183 
184  /* TODO: Do as many of these in parallel as possible */
185 
187  /* Normally we want the _whole_ 'then' clone to
188  * restart if 'first' is restarted, so then->node is
189  * needed.
190  *
191  * However for unfencing, we want to limit this to
192  * instances on the same node as 'first' (the
193  * unfencing operation), so first->node is supplied.
194  *
195  * Swap the node, from then on we can can treat it
196  * like any other 'pe_order_implies_then'
197  */
198 
201  node = first->node;
202  }
203 
204  pe__clear_raw_action_flags(first_flags, "first action update",
206 
207  if (type & pe_order_implies_then) {
208  processed = TRUE;
209  if (then->rsc) {
210  changed |= then->rsc->cmds->update_actions(first, then, node,
211  first_flags & pe_action_optional, pe_action_optional,
212  pe_order_implies_then, data_set);
213 
214  } else if (!pcmk_is_set(first_flags, pe_action_optional)) {
215  if (update_action_flags(then, pe_action_optional | pe_action_clear, __func__, __LINE__)) {
217  }
218  }
219  if (changed) {
220  pe_rsc_trace(then->rsc, "implies right: %s then %s: changed", first->uuid, then->uuid);
221  } else {
222  crm_trace("implies right: %s then %s %p", first->uuid, then->uuid, then->rsc);
223  }
224  }
225 
226  if ((type & pe_order_restart) && then->rsc) {
228 
229  processed = TRUE;
230  changed |= then->rsc->cmds->update_actions(first, then, node,
231  first_flags, restart,
232  pe_order_restart, data_set);
233  if (changed) {
234  pe_rsc_trace(then->rsc, "restart: %s then %s: changed", first->uuid, then->uuid);
235  } else {
236  crm_trace("restart: %s then %s", first->uuid, then->uuid);
237  }
238  }
239 
241  processed = TRUE;
242  if (first->rsc) {
243  changed |= first->rsc->cmds->update_actions(first, then, node,
245  data_set);
246 
247  } else if (!pcmk_is_set(first_flags, pe_action_optional)) {
248  pe_rsc_trace(first->rsc, "first unrunnable: %s (%d) then %s (%d)",
249  first->uuid, pcmk_is_set(first_flags, pe_action_optional),
250  then->uuid, pcmk_is_set(then_flags, pe_action_optional));
251  if (update_action_flags(first, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
253  }
254  }
255 
256  if (changed) {
257  pe_rsc_trace(then->rsc, "implies left: %s then %s: changed", first->uuid, then->uuid);
258  } else {
259  crm_trace("implies left: %s (%d) then %s (%d)",
260  first->uuid, pcmk_is_set(first_flags, pe_action_optional),
261  then->uuid, pcmk_is_set(then_flags, pe_action_optional));
262  }
263  }
264 
266  processed = TRUE;
267  if (then->rsc) {
268  changed |= then->rsc->cmds->update_actions(first, then, node,
269  first_flags & pe_action_optional, pe_action_optional,
271  }
272 
273  if (changed) {
274  pe_rsc_trace(then->rsc,
275  "implies left when right rsc is Master role: %s then %s: changed",
276  first->uuid, then->uuid);
277  } else {
278  crm_trace("implies left when right rsc is Master role: %s then %s", first->uuid,
279  then->uuid);
280  }
281  }
282 
283  if (type & pe_order_one_or_more) {
284  processed = TRUE;
285  if (then->rsc) {
286  changed |= then->rsc->cmds->update_actions(first, then, node,
288  data_set);
289 
290  } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
291  /* alright. a "first" action is considered runnable, incremente
292  * the 'runnable_before' counter */
293  then->runnable_before++;
294 
295  /* if the runnable before count for then exceeds the required number
296  * of "before" runnable actions... mark then as runnable */
297  if (then->runnable_before >= then->required_runnable_before) {
298  if (update_action_flags(then, pe_action_runnable, __func__, __LINE__)) {
300  }
301  }
302  }
303  if (changed) {
304  pe_rsc_trace(then->rsc, "runnable_one_or_more: %s then %s: changed", first->uuid,
305  then->uuid);
306  } else {
307  crm_trace("runnable_one_or_more: %s then %s", first->uuid, then->uuid);
308  }
309  }
310 
311  if (then->rsc && pcmk_is_set(type, pe_order_probe)) {
312  processed = TRUE;
313 
314  if (!pcmk_is_set(first_flags, pe_action_runnable)
315  && (first->rsc->running_on != NULL)) {
316 
317  pe_rsc_trace(then->rsc, "Ignoring %s then %s - %s is about to be stopped",
318  first->uuid, then->uuid, first->rsc->id);
320  order->type = pe_order_none;
321 
322  } else {
323  pe_rsc_trace(then->rsc, "Enforcing %s then %s", first->uuid, then->uuid);
324  changed |= then->rsc->cmds->update_actions(first, then, node,
326  data_set);
327  }
328 
329  if (changed) {
330  pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
331  } else {
332  crm_trace("runnable: %s then %s", first->uuid, then->uuid);
333  }
334  }
335 
337  processed = TRUE;
338  if (then->rsc) {
339  changed |= then->rsc->cmds->update_actions(first, then, node,
341  data_set);
342 
343  } else if (!pcmk_is_set(first_flags, pe_action_runnable)) {
344  pe_rsc_trace(then->rsc, "then unrunnable: %s then %s", first->uuid, then->uuid);
345  if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
347  }
348  }
349  if (changed) {
350  pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
351  } else {
352  crm_trace("runnable: %s then %s", first->uuid, then->uuid);
353  }
354  }
355 
357  processed = TRUE;
358  if (then->rsc) {
359  changed |= then->rsc->cmds->update_actions(first, then, node,
360  first_flags, pe_action_optional,
362  }
363  if (changed) {
364  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
365  } else {
366  crm_trace("optional: %s then %s", first->uuid, then->uuid);
367  }
368  }
369 
370  if (type & pe_order_pseudo_left) {
371  processed = TRUE;
372  if (then->rsc) {
373  changed |= then->rsc->cmds->update_actions(first, then, node,
375  data_set);
376  }
377  if (changed) {
378  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
379  } else {
380  crm_trace("optional: %s then %s", first->uuid, then->uuid);
381  }
382  }
383 
384  if (type & pe_order_optional) {
385  processed = TRUE;
386  if (then->rsc) {
387  changed |= then->rsc->cmds->update_actions(first, then, node,
388  first_flags, pe_action_runnable, pe_order_optional, data_set);
389  }
390  if (changed) {
391  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
392  } else {
393  crm_trace("optional: %s then %s", first->uuid, then->uuid);
394  }
395  }
396 
397  if (type & pe_order_asymmetrical) {
398  processed = TRUE;
399  if (then->rsc) {
400  changed |= then->rsc->cmds->update_actions(first, then, node,
402  data_set);
403  }
404 
405  if (changed) {
406  pe_rsc_trace(then->rsc, "asymmetrical: %s then %s: changed", first->uuid, then->uuid);
407  } else {
408  crm_trace("asymmetrical: %s then %s", first->uuid, then->uuid);
409  }
410 
411  }
412 
414  && (first_flags & pe_action_optional) == 0) {
415  processed = TRUE;
416  crm_trace("%s implies %s printed", first->uuid, then->uuid);
417  update_action_flags(then, pe_action_print_always, __func__, __LINE__); /* don't care about changed */
418  }
419 
421  && !pcmk_is_set(then_flags, pe_action_optional)) {
422 
423  processed = TRUE;
424  crm_trace("%s implies %s printed", then->uuid, first->uuid);
425  update_action_flags(first, pe_action_print_always, __func__, __LINE__); /* don't care about changed */
426  }
427 
430  || type & pe_order_restart)
431  && first->rsc
432  && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)
433  && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
434  && pcmk_is_set(first->rsc->flags, pe_rsc_block)
435  && !pcmk_is_set(first->flags, pe_action_runnable)) {
436 
437  if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
439  }
440 
441  if (changed) {
442  pe_rsc_trace(then->rsc, "unmanaged left: %s then %s: changed", first->uuid, then->uuid);
443  } else {
444  crm_trace("unmanaged left: %s then %s", first->uuid, then->uuid);
445  }
446  }
447 
448  if (processed == FALSE) {
449  crm_trace("Constraint 0x%.6x not applicable", type);
450  }
451 
452  return changed;
453 }
454 
455 static void
456 mark_start_blocked(pe_resource_t *rsc, pe_resource_t *reason,
457  pe_working_set_t *data_set)
458 {
459  GListPtr gIter = rsc->actions;
460  char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
461 
462  for (; gIter != NULL; gIter = gIter->next) {
463  pe_action_t *action = (pe_action_t *) gIter->data;
464 
465  if (!pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
466  continue;
467  }
468  if (pcmk_is_set(action->flags, pe_action_runnable)) {
469  pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
470  reason_text, pe_action_runnable, FALSE);
471  update_colo_start_chain(action, data_set);
472  update_action(action, data_set);
473  }
474  }
475  free(reason_text);
476 }
477 
478 void
480 {
481  GListPtr gIter = NULL;
482  pe_resource_t *rsc = NULL;
483 
485  && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
486 
487  rsc = uber_parent(action->rsc);
488  if (rsc->parent) {
489  /* For bundles, uber_parent() returns the clone/master, not the
490  * bundle, so the existence of rsc->parent implies this is a bundle.
491  * In this case, we need the bundle resource, so that we can check
492  * if all containers are stopped/stopping.
493  */
494  rsc = rsc->parent;
495  }
496  }
497 
498  if (rsc == NULL || rsc->rsc_cons_lhs == NULL) {
499  return;
500  }
501 
502  /* if rsc has children, all the children need to have start set to
503  * unrunnable before we follow the colo chain for the parent. */
504  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
505  pe_resource_t *child = (pe_resource_t *)gIter->data;
506  pe_action_t *start = find_first_action(child->actions, NULL, RSC_START, NULL);
507  if ((start == NULL) || pcmk_is_set(start->flags, pe_action_runnable)) {
508  return;
509  }
510  }
511 
512  for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
513  rsc_colocation_t *colocate_with = (rsc_colocation_t *)gIter->data;
514  if (colocate_with->score == INFINITY) {
515  mark_start_blocked(colocate_with->rsc_lh, action->rsc, data_set);
516  }
517  }
518 }
519 
520 gboolean
522 {
523  GListPtr lpc = NULL;
524  enum pe_graph_flags changed = pe_graph_none;
525  int last_flags = then->flags;
526 
527  crm_trace("Processing %s (%s %s %s)",
528  then->uuid,
529  pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
530  pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
531  pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
532  : (then->node? then->node->details->uname : ""));
533 
535  /* initialize current known runnable before actions to 0
536  * from here as graph_update_action is called for each of
537  * then's before actions, this number will increment as
538  * runnable 'first' actions are encountered */
539  then->runnable_before = 0;
540 
541  /* for backwards compatibility with previous options that use
542  * the 'requires_any' flag, initialize required to 1 if it is
543  * not set. */
544  if (then->required_runnable_before == 0) {
545  then->required_runnable_before = 1;
546  }
548  /* We are relying on the pe_order_one_or_more clause of
549  * graph_update_action(), called as part of the:
550  *
551  * 'if (first == other->action)'
552  *
553  * block below, to set this back if appropriate
554  */
555  }
556 
557  for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
558  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
559  pe_action_t *first = other->action;
560 
561  pe_node_t *then_node = then->node;
562  pe_node_t *first_node = first->node;
563 
564  enum pe_action_flags then_flags = 0;
565  enum pe_action_flags first_flags = 0;
566 
567  if (first->rsc && first->rsc->variant == pe_group && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
568  first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
569  if (first_node) {
570  crm_trace("First: Found node %s for %s", first_node->details->uname, first->uuid);
571  }
572  }
573 
574  if (then->rsc && then->rsc->variant == pe_group && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
575  then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
576  if (then_node) {
577  crm_trace("Then: Found node %s for %s", then_node->details->uname, then->uuid);
578  }
579  }
580  /* Disable constraint if it only applies when on same node, but isn't */
581  if (pcmk_is_set(other->type, pe_order_same_node)
582  && (first_node != NULL) && (then_node != NULL)
583  && (first_node->details != then_node->details)) {
584 
585  crm_trace("Disabled constraint %s on %s -> %s on %s",
586  other->action->uuid, first_node->details->uname,
587  then->uuid, then_node->details->uname);
588  other->type = pe_order_none;
589  continue;
590  }
591 
593 
594  if (first->rsc && pcmk_is_set(other->type, pe_order_then_cancels_first)
595  && !pcmk_is_set(then->flags, pe_action_optional)) {
596 
597  /* 'then' is required, so we must abandon 'first'
598  * (e.g. a required stop cancels any reload).
599  */
601  if (!strcmp(first->task, CRMD_ACTION_RELOAD)) {
603  }
604  }
605 
606  if (first->rsc && then->rsc && (first->rsc != then->rsc)
607  && (is_parent(then->rsc, first->rsc) == FALSE)) {
608  first = rsc_expand_action(first);
609  }
610  if (first != other->action) {
611  crm_trace("Ordering %s after %s instead of %s", then->uuid, first->uuid,
612  other->action->uuid);
613  }
614 
615  first_flags = get_action_flags(first, then_node);
616  then_flags = get_action_flags(then, first_node);
617 
618  crm_trace("Checking %s (%s %s %s) against %s (%s %s %s) filter=0x%.6x type=0x%.6x",
619  then->uuid,
620  pcmk_is_set(then_flags, pe_action_optional)? "optional" : "required",
621  pcmk_is_set(then_flags, pe_action_runnable)? "runnable" : "unrunnable",
622  pcmk_is_set(then_flags, pe_action_pseudo)? "pseudo"
623  : (then->node? then->node->details->uname : ""),
624  first->uuid,
625  pcmk_is_set(first_flags, pe_action_optional)? "optional" : "required",
626  pcmk_is_set(first_flags, pe_action_runnable)? "runnable" : "unrunnable",
627  pcmk_is_set(first_flags, pe_action_pseudo)? "pseudo"
628  : (first->node? first->node->details->uname : ""),
629  first_flags, other->type);
630 
631  if (first == other->action) {
632  /*
633  * 'first' was not expanded (e.g. from 'start' to 'running'), which could mean it:
634  * - has no associated resource,
635  * - was a primitive,
636  * - was pre-expanded (e.g. 'running' instead of 'start')
637  *
638  * The third argument here to graph_update_action() is a node which is used under two conditions:
639  * - Interleaving, in which case first->node and
640  * then->node are equal (and NULL)
641  * - If 'then' is a clone, to limit the scope of the
642  * constraint to instances on the supplied node
643  *
644  */
645  pe_node_t *node = then->node;
646  changed |= graph_update_action(first, then, node, first_flags,
647  then_flags, other, data_set);
648 
649  /* 'first' was for a complex resource (clone, group, etc),
650  * create a new dependency if necessary
651  */
652  } else if (order_actions(first, then, other->type)) {
653  /* This was the first time 'first' and 'then' were associated,
654  * start again to get the new actions_before list
655  */
656  pe__set_graph_flags(changed, then,
658  }
659 
660  if (changed & pe_graph_disable) {
661  crm_trace("Disabled constraint %s -> %s in favor of %s -> %s",
662  other->action->uuid, then->uuid, first->uuid, then->uuid);
663  pe__clear_graph_flags(changed, then, pe_graph_disable);
664  other->type = pe_order_none;
665  }
666 
667  if (changed & pe_graph_updated_first) {
668  GListPtr lpc2 = NULL;
669 
670  crm_trace("Updated %s (first %s %s %s), processing dependents ",
671  first->uuid,
672  pcmk_is_set(first->flags, pe_action_optional)? "optional" : "required",
673  pcmk_is_set(first->flags, pe_action_runnable)? "runnable" : "unrunnable",
674  pcmk_is_set(first->flags, pe_action_pseudo)? "pseudo"
675  : (first->node? first->node->details->uname : ""));
676  for (lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) {
677  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
678 
679  update_action(other->action, data_set);
680  }
681  update_action(first, data_set);
682  }
683  }
684 
686  if (last_flags != then->flags) {
688  } else {
690  }
691  }
692 
693  if (changed & pe_graph_updated_then) {
694  crm_trace("Updated %s (then %s %s %s), processing dependents ",
695  then->uuid,
696  pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
697  pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
698  pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
699  : (then->node? then->node->details-> uname : ""));
700 
701  if (pcmk_is_set(last_flags, pe_action_runnable)
702  && !pcmk_is_set(then->flags, pe_action_runnable)) {
703  update_colo_start_chain(then, data_set);
704  }
705  update_action(then, data_set);
706  for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
707  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
708 
709  update_action(other->action, data_set);
710  }
711  }
712 
713  return FALSE;
714 }
715 
716 gboolean
717 shutdown_constraints(pe_node_t * node, pe_action_t * shutdown_op, pe_working_set_t * data_set)
718 {
719  /* add the stop to the before lists so it counts as a pre-req
720  * for the shutdown
721  */
722  GListPtr lpc = NULL;
723 
724  for (lpc = data_set->actions; lpc != NULL; lpc = lpc->next) {
725  pe_action_t *action = (pe_action_t *) lpc->data;
726 
727  if (action->rsc == NULL || action->node == NULL) {
728  continue;
729  } else if (action->node->details != node->details) {
730  continue;
731  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)) {
732  pe_rsc_trace(action->rsc, "Skipping %s: maintenance mode", action->uuid);
733  continue;
734  } else if (node->details->maintenance) {
735  pe_rsc_trace(action->rsc, "Skipping %s: node %s is in maintenance mode",
736  action->uuid, node->details->uname);
737  continue;
738  } else if (!pcmk__str_eq(action->task, RSC_STOP, pcmk__str_casei)) {
739  continue;
740  } else if (!pcmk_any_flags_set(action->rsc->flags,
742  /*
743  * If another action depends on this one, we may still end up blocking
744  */
745  pe_rsc_trace(action->rsc, "Skipping %s: unmanaged", action->uuid);
746  continue;
747  }
748 
749  pe_rsc_trace(action->rsc, "Ordering %s before shutdown on %s", action->uuid,
750  node->details->uname);
752  custom_action_order(action->rsc, NULL, action,
753  NULL, strdup(CRM_OP_SHUTDOWN), shutdown_op,
755  }
756 
757  return TRUE;
758 }
759 
771 void
773 {
774  CRM_CHECK(stonith_op && data_set, return);
775  for (GList *r = data_set->resources; r != NULL; r = r->next) {
776  rsc_stonith_ordering((pe_resource_t *) r->data, stonith_op, data_set);
777  }
778 }
779 
780 static pe_node_t *
781 get_router_node(pe_action_t *action)
782 {
783  pe_node_t *began_on = NULL;
784  pe_node_t *ended_on = NULL;
785  pe_node_t *router_node = NULL;
786  bool partial_migration = FALSE;
787  const char *task = action->task;
788 
789  if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)
790  || !pe__is_guest_or_remote_node(action->node)) {
791  return NULL;
792  }
793 
794  CRM_ASSERT(action->node->details->remote_rsc != NULL);
795 
796  began_on = pe__current_node(action->node->details->remote_rsc);
797  ended_on = action->node->details->remote_rsc->allocated_to;
798  if (action->node->details->remote_rsc
799  && (action->node->details->remote_rsc->container == NULL)
800  && action->node->details->remote_rsc->partial_migration_target) {
801  partial_migration = TRUE;
802  }
803 
804  /* if there is only one location to choose from,
805  * this is easy. Check for those conditions first */
806  if (!began_on || !ended_on) {
807  /* remote rsc is either shutting down or starting up */
808  return began_on ? began_on : ended_on;
809  } else if (began_on->details == ended_on->details) {
810  /* remote rsc didn't move nodes. */
811  return began_on;
812  }
813 
814  /* If we have get here, we know the remote resource
815  * began on one node and is moving to another node.
816  *
817  * This means some actions will get routed through the cluster
818  * node the connection rsc began on, and others are routed through
819  * the cluster node the connection rsc ends up on.
820  *
821  * 1. stop, demote, migrate actions of resources living in the remote
822  * node _MUST_ occur _BEFORE_ the connection can move (these actions
823  * are all required before the remote rsc stop action can occur.) In
824  * this case, we know these actions have to be routed through the initial
825  * cluster node the connection resource lived on before the move takes place.
826  * The exception is a partial migration of a (non-guest) remote
827  * connection resource; in that case, all actions (even these) will be
828  * ordered after the connection's pseudo-start on the migration target,
829  * so the target is the router node.
830  *
831  * 2. Everything else (start, promote, monitor, probe, refresh, clear failcount
832  * delete ....) must occur after the resource starts on the node it is
833  * moving to.
834  */
835 
836  if (pcmk__str_eq(task, "notify", pcmk__str_casei)) {
837  task = g_hash_table_lookup(action->meta, "notify_operation");
838  }
839 
840  /* 1. before connection rsc moves. */
841  if (pcmk__strcase_any_of(task, "stop", "demote", "migrate_from", "migrate_to",
842  NULL) && !partial_migration) {
843  router_node = began_on;
844 
845  /* 2. after connection rsc moves. */
846  } else {
847  router_node = ended_on;
848  }
849  return router_node;
850 }
851 
859 static xmlNode*
860 add_node_to_xml_by_id(const char *id, xmlNode *xml)
861 {
862  xmlNode *node_xml;
863 
864  node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
865  crm_xml_add(node_xml, XML_ATTR_UUID, id);
866 
867  return node_xml;
868 }
869 
877 static void
878 add_node_to_xml(const pe_node_t *node, void *xml)
879 {
880  add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
881 }
882 
890 static int
891 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
892 {
893  GListPtr gIter = NULL;
894  xmlNode *maintenance =
896  int count = 0;
897 
898  for (gIter = data_set->nodes; gIter != NULL;
899  gIter = gIter->next) {
900  pe_node_t *node = (pe_node_t *) gIter->data;
901  struct pe_node_shared_s *details = node->details;
902 
903  if (!pe__is_guest_or_remote_node(node)) {
904  continue; /* just remote nodes need to know atm */
905  }
906 
907  if (details->maintenance != details->remote_maintenance) {
908  if (maintenance) {
909  crm_xml_add(
910  add_node_to_xml_by_id(node->details->id, maintenance),
911  XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
912  }
913  count++;
914  }
915  }
916  crm_trace("%s %d nodes to adjust maintenance-mode "
917  "to transition", maintenance?"Added":"Counted", count);
918  return count;
919 }
920 
927 void
929 {
930  pe_action_t *action = NULL;
931 
932  if (add_maintenance_nodes(NULL, data_set)) {
933  crm_trace("adding maintenance state update pseudo action");
936  }
937 }
938 
951 static void
952 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
953  const pe_working_set_t *data_set)
954 {
955  CRM_CHECK(xml && action && action->node && data_set, return);
956 
957  if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
958 
959  /* Shutdown makes the action's node down */
960  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
961  add_node_to_xml_by_id(action->node->details->id, downed);
962 
963  } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
964 
965  /* Fencing makes the action's node and any hosted guest nodes down */
966  const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
967 
968  if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
969  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
970  add_node_to_xml_by_id(action->node->details->id, downed);
971  pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
972  }
973 
974  } else if (action->rsc && action->rsc->is_remote_node
975  && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
976 
977  /* Stopping a remote connection resource makes connected node down,
978  * unless it's part of a migration
979  */
980  GListPtr iter;
981  pe_action_t *input;
982  gboolean migrating = FALSE;
983 
984  for (iter = action->actions_before; iter != NULL; iter = iter->next) {
985  input = ((pe_action_wrapper_t *) iter->data)->action;
986  if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
987  && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
988  migrating = TRUE;
989  break;
990  }
991  }
992  if (!migrating) {
993  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
994  add_node_to_xml_by_id(action->rsc->id, downed);
995  }
996  }
997 }
998 
999 static bool
1000 should_lock_action(pe_action_t *action)
1001 {
1002  // Only actions taking place on resource's lock node are locked
1003  if ((action->rsc->lock_node == NULL) || (action->node == NULL)
1004  || (action->node->details != action->rsc->lock_node->details)) {
1005  return false;
1006  }
1007 
1008  /* During shutdown, only stops are locked (otherwise, another action such as
1009  * a demote would cause the controller to clear the lock)
1010  */
1011  if (action->node->details->shutdown && action->task
1012  && strcmp(action->task, RSC_STOP)) {
1013  return false;
1014  }
1015 
1016  return true;
1017 }
1018 
1019 static xmlNode *
1020 action2xml(pe_action_t * action, gboolean as_input, pe_working_set_t *data_set)
1021 {
1022  gboolean needs_node_info = TRUE;
1023  gboolean needs_maintenance_info = FALSE;
1024  xmlNode *action_xml = NULL;
1025  xmlNode *args_xml = NULL;
1026 #if ENABLE_VERSIONED_ATTRS
1027  pe_rsc_action_details_t *rsc_details = NULL;
1028 #endif
1029 
1030  if (action == NULL) {
1031  return NULL;
1032  }
1033 
1034  if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1035  /* All fences need node info; guest node fences are pseudo-events */
1036  action_xml = create_xml_node(NULL,
1040 
1041  } else if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1042  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1043 
1044  } else if (pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
1045  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1046 
1047  } else if (pcmk__str_eq(action->task, CRM_OP_LRM_REFRESH, pcmk__str_casei)) {
1048  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1049 
1050  } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
1051  // CIB-only clean-up for shutdown locks
1052  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1053  crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
1054 
1055 /* } else if(pcmk__str_eq(action->task, RSC_PROBED, pcmk__str_casei)) { */
1056 /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */
1057 
1058  } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
1059  if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
1060  needs_maintenance_info = TRUE;
1061  }
1062  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
1063  needs_node_info = FALSE;
1064 
1065  } else {
1066  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
1067 
1068 #if ENABLE_VERSIONED_ATTRS
1069  rsc_details = pe_rsc_action_details(action);
1070 #endif
1071  }
1072 
1073  crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
1074  crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
1075  if (action->rsc != NULL && action->rsc->clone_name != NULL) {
1076  char *clone_key = NULL;
1077  guint interval_ms;
1078 
1079  if (pcmk__guint_from_hash(action->meta,
1081  &interval_ms) != pcmk_rc_ok) {
1082  interval_ms = 0;
1083  }
1084 
1085  if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_casei)) {
1086  const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
1087  const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1088 
1089  CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid));
1090  CRM_CHECK(n_task != NULL,
1091  crm_err("No notify operation value found for %s", action->uuid));
1092  clone_key = pcmk__notify_key(action->rsc->clone_name,
1093  n_type, n_task);
1094 
1095  } else if(action->cancel_task) {
1096  clone_key = pcmk__op_key(action->rsc->clone_name,
1097  action->cancel_task, interval_ms);
1098  } else {
1099  clone_key = pcmk__op_key(action->rsc->clone_name,
1100  action->task, interval_ms);
1101  }
1102 
1103  CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid));
1104  crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
1105  crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
1106  free(clone_key);
1107 
1108  } else {
1109  crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
1110  }
1111 
1112  if (needs_node_info && action->node != NULL) {
1113  pe_node_t *router_node = get_router_node(action);
1114 
1115  crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
1116  crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
1117  if (router_node) {
1118  crm_xml_add(action_xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
1119  }
1120 
1121  g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET), strdup(action->node->details->uname));
1122  g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID), strdup(action->node->details->id));
1123  }
1124 
1125  /* No details if this action is only being listed in the inputs section */
1126  if (as_input) {
1127  return action_xml;
1128  }
1129 
1130  if (action->rsc && !pcmk_is_set(action->flags, pe_action_pseudo)) {
1131  int lpc = 0;
1132  xmlNode *rsc_xml = NULL;
1133  const char *attr_list[] = {
1137  };
1138 
1139  /* If a resource is locked to a node via shutdown-lock, mark its actions
1140  * so the controller can preserve the lock when the action completes.
1141  */
1142  if (should_lock_action(action)) {
1144  (long long) action->rsc->lock_time);
1145  }
1146 
1147  // List affected resource
1148 
1149  rsc_xml = create_xml_node(action_xml,
1150  crm_element_name(action->rsc->xml));
1151  if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
1152  && action->rsc->clone_name) {
1153  /* Do not use the 'instance free' name here as that
1154  * might interfere with the instance we plan to keep.
1155  * Ie. if there are more than two named /anonymous/
1156  * instances on a given node, we need to make sure the
1157  * command goes to the right one.
1158  *
1159  * Keep this block, even when everyone is using
1160  * 'instance free' anonymous clone names - it means
1161  * we'll do the right thing if anyone toggles the
1162  * unique flag to 'off'
1163  */
1164  crm_debug("Using orphan clone name %s instead of %s", action->rsc->id,
1165  action->rsc->clone_name);
1166  crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
1167  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1168 
1169  } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
1170  const char *xml_id = ID(action->rsc->xml);
1171 
1172  crm_debug("Using anonymous clone name %s for %s (aka. %s)", xml_id, action->rsc->id,
1173  action->rsc->clone_name);
1174 
1175  /* ID is what we'd like client to use
1176  * ID_LONG is what they might know it as instead
1177  *
1178  * ID_LONG is only strictly needed /here/ during the
1179  * transition period until all nodes in the cluster
1180  * are running the new software /and/ have rebooted
1181  * once (meaning that they've only ever spoken to a DC
1182  * supporting this feature).
1183  *
1184  * If anyone toggles the unique flag to 'on', the
1185  * 'instance free' name will correspond to an orphan
1186  * and fall into the clause above instead
1187  */
1188  crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
1189  if (action->rsc->clone_name && !pcmk__str_eq(xml_id, action->rsc->clone_name, pcmk__str_casei)) {
1190  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
1191  } else {
1192  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1193  }
1194 
1195  } else {
1196  CRM_ASSERT(action->rsc->clone_name == NULL);
1197  crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
1198  }
1199 
1200  for (lpc = 0; lpc < DIMOF(attr_list); lpc++) {
1201  crm_xml_add(rsc_xml, attr_list[lpc],
1202  g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
1203  }
1204  }
1205 
1206  /* List any attributes in effect */
1207  args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
1209 
1210  g_hash_table_foreach(action->extra, hash2field, args_xml);
1211  if (action->rsc != NULL && action->node) {
1212  GHashTable *p = crm_str_table_new();
1213 
1214  get_rsc_attributes(p, action->rsc, action->node, data_set);
1215  g_hash_table_foreach(p, hash2smartfield, args_xml);
1216  g_hash_table_destroy(p);
1217 
1218 #if ENABLE_VERSIONED_ATTRS
1219  {
1220  xmlNode *versioned_parameters = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1221 
1222  pe_get_versioned_attributes(versioned_parameters, action->rsc,
1223  action->node, data_set);
1224  if (xml_has_children(versioned_parameters)) {
1225  add_node_copy(action_xml, versioned_parameters);
1226  }
1227  free_xml(versioned_parameters);
1228  }
1229 #endif
1230 
1231  } else if(action->rsc && action->rsc->variant <= pe_native) {
1232  g_hash_table_foreach(action->rsc->parameters, hash2smartfield, args_xml);
1233 
1234 #if ENABLE_VERSIONED_ATTRS
1235  if (xml_has_children(action->rsc->versioned_parameters)) {
1236  add_node_copy(action_xml, action->rsc->versioned_parameters);
1237  }
1238 #endif
1239  }
1240 
1241 #if ENABLE_VERSIONED_ATTRS
1242  if (rsc_details) {
1243  if (xml_has_children(rsc_details->versioned_parameters)) {
1244  add_node_copy(action_xml, rsc_details->versioned_parameters);
1245  }
1246 
1247  if (xml_has_children(rsc_details->versioned_meta)) {
1248  add_node_copy(action_xml, rsc_details->versioned_meta);
1249  }
1250  }
1251 #endif
1252 
1253  g_hash_table_foreach(action->meta, hash2metafield, args_xml);
1254  if (action->rsc != NULL) {
1255  const char *value = g_hash_table_lookup(action->rsc->meta, "external-ip");
1256  pe_resource_t *parent = action->rsc;
1257 
1258  while (parent != NULL) {
1259  parent->cmds->append_meta(parent, args_xml);
1260  parent = parent->parent;
1261  }
1262 
1263  if(value) {
1264  hash2smartfield((gpointer)"pcmk_external_ip", (gpointer)value, (gpointer)args_xml);
1265  }
1266 
1267  if (action->node && /* make clang analyzer happy */
1268  pe__is_guest_node(action->node)) {
1269  pe_node_t *host = NULL;
1270  enum action_tasks task = text2task(action->task);
1271 
1272  if(task == action_notify || task == action_notified) {
1273  const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1274  task = text2task(n_task);
1275  }
1276 
1277  // Differentiate between up and down actions
1278  switch (task) {
1279  case stop_rsc:
1280  case stopped_rsc:
1281  case action_demote:
1282  case action_demoted:
1283  host = pe__current_node(action->node->details->remote_rsc->container);
1284  break;
1285  case start_rsc:
1286  case started_rsc:
1287  case monitor_rsc:
1288  case action_promote:
1289  case action_promoted:
1290  host = action->node->details->remote_rsc->container->allocated_to;
1291  break;
1292  default:
1293  break;
1294  }
1295 
1296  if(host) {
1298  (gpointer)g_hash_table_lookup(action->rsc->meta, XML_RSC_ATTR_TARGET), (gpointer)args_xml);
1300  (gpointer)host->details->uname,
1301  (gpointer)args_xml);
1302  }
1303  }
1304 
1305  } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei) && action->node) {
1306  /* Pass the node's attributes as meta-attributes.
1307  *
1308  * @TODO: Determine whether it is still necessary to do this. It was
1309  * added in 33d99707, probably for the libfence-based implementation in
1310  * c9a90bd, which is no longer used.
1311  */
1312  g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
1313  }
1314 
1315  sorted_xml(args_xml, action_xml, FALSE);
1316  free_xml(args_xml);
1317 
1318  /* List any nodes this action is expected to make down */
1319  if (needs_node_info && (action->node != NULL)) {
1320  add_downed_nodes(action_xml, action, data_set);
1321  }
1322 
1323  if (needs_maintenance_info) {
1324  add_maintenance_nodes(action_xml, data_set);
1325  }
1326 
1327  crm_log_xml_trace(action_xml, "dumped action");
1328  return action_xml;
1329 }
1330 
1331 static bool
1332 should_dump_action(pe_action_t *action)
1333 {
1334  CRM_CHECK(action != NULL, return false);
1335 
1336  if (pcmk_is_set(action->flags, pe_action_dumped)) {
1337  crm_trace("Action %s (%d) already dumped", action->uuid, action->id);
1338  return false;
1339 
1340  } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1341  && pcmk__str_eq(action->task, CRM_OP_PROBED, pcmk__str_casei)) {
1342  GListPtr lpc = NULL;
1343 
1344  /* This is a horrible but convenient hack
1345  *
1346  * It mimimizes the number of actions with unsatisfied inputs
1347  * (i.e. not included in the graph)
1348  *
1349  * This in turn, means we can be more concise when printing
1350  * aborted/incomplete graphs.
1351  *
1352  * It also makes it obvious which node is preventing
1353  * probe_complete from running (presumably because it is only
1354  * partially up)
1355  *
1356  * For these reasons we tolerate such perversions
1357  */
1358 
1359  for (lpc = action->actions_after; lpc != NULL; lpc = lpc->next) {
1360  pe_action_wrapper_t *wrapper = (pe_action_wrapper_t *) lpc->data;
1361 
1362  if (!pcmk_is_set(wrapper->action->flags, pe_action_runnable)) {
1363  /* Only interested in runnable operations */
1364  } else if (!pcmk__str_eq(wrapper->action->task, RSC_START, pcmk__str_casei)) {
1365  /* Only interested in start operations */
1366  } else if (pcmk_is_set(wrapper->action->flags, pe_action_dumped)
1367  || should_dump_action(wrapper->action)) {
1368  crm_trace("Action %s (%d) should be dumped: "
1369  "dependency of %s (%d)",
1370  action->uuid, action->id,
1371  wrapper->action->uuid, wrapper->action->id);
1372  return true;
1373  }
1374  }
1375  }
1376 
1377  if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1378  crm_trace("Ignoring action %s (%d): unrunnable",
1379  action->uuid, action->id);
1380  return false;
1381 
1382  } else if (pcmk_is_set(action->flags, pe_action_optional)
1383  && !pcmk_is_set(action->flags, pe_action_print_always)) {
1384  crm_trace("Ignoring action %s (%d): optional",
1385  action->uuid, action->id);
1386  return false;
1387 
1388  // Monitors should be dumped even for unmanaged resources
1389  } else if (action->rsc && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
1390  && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)) {
1391 
1392  const char *interval_ms_s = g_hash_table_lookup(action->meta,
1394 
1395  // Cancellation of recurring monitors should still be dumped
1396  if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
1397  crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
1398  action->uuid, action->id, action->rsc->id);
1399  return false;
1400  }
1401  }
1402 
1403  if (pcmk_is_set(action->flags, pe_action_pseudo) ||
1405  /* skip the next checks */
1406  return true;
1407  }
1408 
1409  if (action->node == NULL) {
1410  pe_err("Skipping action %s (%d) "
1411  "because it was not allocated to a node (bug?)",
1412  action->uuid, action->id);
1413  log_action(LOG_DEBUG, "Unallocated action", action, false);
1414  return false;
1415 
1416  } else if (pcmk_is_set(action->flags, pe_action_dc)) {
1417  crm_trace("Action %s (%d) should be dumped: "
1418  "can run on DC instead of %s",
1419  action->uuid, action->id, action->node->details->uname);
1420 
1421  } else if (pe__is_guest_node(action->node)
1422  && !action->node->details->remote_requires_reset) {
1423  crm_trace("Action %s (%d) should be dumped: "
1424  "assuming will be runnable on guest node %s",
1425  action->uuid, action->id, action->node->details->uname);
1426 
1427  } else if (action->node->details->online == false) {
1428  pe_err("Skipping action %s (%d) "
1429  "because it was scheduled for offline node (bug?)",
1430  action->uuid, action->id);
1431  log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
1432  return false;
1433 #if 0
1434  /* but this would also affect resources that can be safely
1435  * migrated before a fencing op
1436  */
1437  } else if (action->node->details->unclean == false) {
1438  pe_err("Skipping action %s (%d) "
1439  "because it was scheduled for unclean node (bug?)",
1440  action->uuid, action->id);
1441  log_action(LOG_DEBUG, "Action for unclean node", action, false);
1442  return false;
1443 #endif
1444  }
1445  return true;
1446 }
1447 
1448 /* lowest to highest */
1449 static gint
1450 sort_action_id(gconstpointer a, gconstpointer b)
1451 {
1452  const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1453  const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1454 
1455  if (a == NULL) {
1456  return 1;
1457  }
1458  if (b == NULL) {
1459  return -1;
1460  }
1461 
1462  if (action_wrapper1->action->id > action_wrapper2->action->id) {
1463  return -1;
1464  }
1465 
1466  if (action_wrapper1->action->id < action_wrapper2->action->id) {
1467  return 1;
1468  }
1469  return 0;
1470 }
1471 
1483 static bool
1484 check_dump_input(pe_action_t *action, pe_action_wrapper_t *input)
1485 {
1486  int type = input->type;
1487 
1488  if (input->state == pe_link_dumped) {
1489  return true;
1490  }
1491 
1495 
1496  if (input->type == pe_order_none) {
1497  crm_trace("Ignoring %s (%d) input %s (%d): "
1498  "ordering disabled",
1499  action->uuid, action->id,
1500  input->action->uuid, input->action->id);
1501  return false;
1502 
1503  } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1504  && (type == pe_order_none)
1505  && !pcmk__str_eq(input->action->uuid, CRM_OP_PROBED, pcmk__str_casei)) {
1506  crm_trace("Ignoring %s (%d) input %s (%d): "
1507  "optional and input unrunnable",
1508  action->uuid, action->id,
1509  input->action->uuid, input->action->id);
1510  return false;
1511 
1512  } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1513  && pcmk_is_set(input->type, pe_order_one_or_more)) {
1514  crm_trace("Ignoring %s (%d) input %s (%d): "
1515  "one-or-more and input unrunnable",
1516  action->uuid, action->id,
1517  input->action->uuid, input->action->id);
1518  return false;
1519 
1520  } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1521  && pcmk_is_set(input->type, pe_order_stonith_stop)) {
1522  crm_trace("Ignoring %s (%d) input %s (%d): "
1523  "stonith stop but action is pseudo",
1524  action->uuid, action->id,
1525  input->action->uuid, input->action->id);
1526  return false;
1527 
1529  && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
1530  crm_trace("Ignoring %s (%d) input %s (%d): "
1531  "implies input migratable but input unrunnable",
1532  action->uuid, action->id,
1533  input->action->uuid, input->action->id);
1534  return false;
1535 
1538  crm_trace("Ignoring %s (%d) input %s (%d): "
1539  "only if input unmigratable but input unrunnable",
1540  action->uuid, action->id,
1541  input->action->uuid, input->action->id);
1542  return false;
1543 
1544  } else if ((input->type == pe_order_optional)
1546  && pcmk__ends_with(input->action->uuid, "_stop_0")) {
1547  crm_trace("Ignoring %s (%d) input %s (%d): "
1548  "optional but stop in migration",
1549  action->uuid, action->id,
1550  input->action->uuid, input->action->id);
1551  return false;
1552 
1553  } else if (input->type == pe_order_load) {
1554  pe_node_t *input_node = input->action->node;
1555 
1556  // load orderings are relevant only if actions are for same node
1557 
1558  if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
1559  pe_node_t *allocated = action->rsc->allocated_to;
1560 
1561  /* For load_stopped -> migrate_to orderings, we care about where it
1562  * has been allocated to, not where it will be executed.
1563  */
1564  if ((input_node == NULL) || (allocated == NULL)
1565  || (input_node->details != allocated->details)) {
1566  crm_trace("Ignoring %s (%d) input %s (%d): "
1567  "load ordering node mismatch %s vs %s",
1568  action->uuid, action->id,
1569  input->action->uuid, input->action->id,
1570  (allocated? allocated->details->uname : "<none>"),
1571  (input_node? input_node->details->uname : "<none>"));
1572  input->type = pe_order_none;
1573  return false;
1574  }
1575 
1576  } else if ((input_node == NULL) || (action->node == NULL)
1577  || (input_node->details != action->node->details)) {
1578  crm_trace("Ignoring %s (%d) input %s (%d): "
1579  "load ordering node mismatch %s vs %s",
1580  action->uuid, action->id,
1581  input->action->uuid, input->action->id,
1582  (action->node? action->node->details->uname : "<none>"),
1583  (input_node? input_node->details->uname : "<none>"));
1584  input->type = pe_order_none;
1585  return false;
1586 
1587  } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1588  crm_trace("Ignoring %s (%d) input %s (%d): "
1589  "load ordering input optional",
1590  action->uuid, action->id,
1591  input->action->uuid, input->action->id);
1592  input->type = pe_order_none;
1593  return false;
1594  }
1595 
1596  } else if (input->type == pe_order_anti_colocation) {
1597  if (input->action->node && action->node
1598  && (input->action->node->details != action->node->details)) {
1599  crm_trace("Ignoring %s (%d) input %s (%d): "
1600  "anti-colocation node mismatch %s vs %s",
1601  action->uuid, action->id,
1602  input->action->uuid, input->action->id,
1603  action->node->details->uname,
1604  input->action->node->details->uname);
1605  input->type = pe_order_none;
1606  return false;
1607 
1608  } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1609  crm_trace("Ignoring %s (%d) input %s (%d): "
1610  "anti-colocation input optional",
1611  action->uuid, action->id,
1612  input->action->uuid, input->action->id);
1613  input->type = pe_order_none;
1614  return false;
1615  }
1616 
1617  } else if (input->action->rsc
1618  && input->action->rsc != action->rsc
1619  && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
1620  && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
1621  && pcmk__ends_with(input->action->uuid, "_stop_0")
1622  && action->rsc && pe_rsc_is_clone(action->rsc)) {
1623  crm_warn("Ignoring requirement that %s complete before %s:"
1624  " unmanaged failed resources cannot prevent clone shutdown",
1625  input->action->uuid, action->uuid);
1626  return false;
1627 
1628  } else if (pcmk_is_set(input->action->flags, pe_action_optional)
1629  && !pcmk_any_flags_set(input->action->flags,
1631  && !should_dump_action(input->action)) {
1632  crm_trace("Ignoring %s (%d) input %s (%d): "
1633  "input optional",
1634  action->uuid, action->id,
1635  input->action->uuid, input->action->id);
1636  return false;
1637  }
1638 
1639  crm_trace("%s (%d) input %s (%d) @ %s should be dumped: %s, %s, %s, 0x%.6x",
1640  action->uuid, action->id,
1641  input->action->uuid, input->action->id,
1642  input->action->node? input->action->node->details->uname : "no node",
1643  pcmk_is_set(input->action->flags, pe_action_pseudo)? "pseudo" : "real",
1644  pcmk_is_set(input->action->flags, pe_action_runnable)? "runnable" : "unrunnable",
1645  pcmk_is_set(input->action->flags, pe_action_optional)? "optional" : "required",
1646  input->type);
1647  return true;
1648 }
1649 
1650 static bool
1651 graph_has_loop(pe_action_t *init_action, pe_action_t *action,
1652  pe_action_wrapper_t *input)
1653 {
1654  bool has_loop = false;
1655 
1656  if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
1657  crm_trace("Breaking tracking loop: %s@%s -> %s@%s (0x%.6x)",
1658  input->action->uuid,
1659  input->action->node? input->action->node->details->uname : "",
1660  action->uuid,
1661  action->node? action->node->details->uname : "",
1662  input->type);
1663  return false;
1664  }
1665 
1666  // Don't need to check inputs that won't be used
1667  if (!check_dump_input(action, input)) {
1668  return false;
1669  }
1670 
1671  if (input->action == init_action) {
1672  crm_debug("Input loop found in %s@%s ->...-> %s@%s",
1673  action->uuid,
1674  action->node? action->node->details->uname : "",
1675  init_action->uuid,
1676  init_action->node? init_action->node->details->uname : "");
1677  return true;
1678  }
1679 
1681 
1682  crm_trace("Checking inputs of action %s@%s input %s@%s (0x%.6x)"
1683  "for graph loop with %s@%s ",
1684  action->uuid,
1685  action->node? action->node->details->uname : "",
1686  input->action->uuid,
1687  input->action->node? input->action->node->details->uname : "",
1688  input->type,
1689  init_action->uuid,
1690  init_action->node? init_action->node->details->uname : "");
1691 
1692  // Recursively check input itself for loops
1693  for (GList *iter = input->action->actions_before;
1694  iter != NULL; iter = iter->next) {
1695 
1696  if (graph_has_loop(init_action, input->action,
1697  (pe_action_wrapper_t *) iter->data)) {
1698  // Recursive call already logged a debug message
1699  has_loop = true;
1700  goto done;
1701  }
1702  }
1703 
1704 done:
1706 
1707  if (!has_loop) {
1708  crm_trace("No input loop found in %s@%s -> %s@%s (0x%.6x)",
1709  input->action->uuid,
1710  input->action->node? input->action->node->details->uname : "",
1711  action->uuid,
1712  action->node? action->node->details->uname : "",
1713  input->type);
1714  }
1715  return has_loop;
1716 }
1717 
1718 bool
1720 {
1721  /* Prevent user-defined ordering constraints between resources
1722  * running in a guest node and the resource that defines that node.
1723  */
1724  if (!pcmk_is_set(input->type, pe_order_preserve)
1725  && action->rsc && action->rsc->fillers
1726  && input->action->rsc && input->action->node
1727  && input->action->node->details->remote_rsc
1728  && (input->action->node->details->remote_rsc->container == action->rsc)) {
1729  crm_warn("Invalid ordering constraint between %s and %s",
1730  input->action->rsc->id, action->rsc->id);
1731  return true;
1732  }
1733 
1734  /* If there's an order like
1735  * "rscB_stop node2"-> "load_stopped_node2" -> "rscA_migrate_to node1"
1736  *
1737  * then rscA is being migrated from node1 to node2, while rscB is being
1738  * migrated from node2 to node1. If there would be a graph loop,
1739  * break the order "load_stopped_node2" -> "rscA_migrate_to node1".
1740  */
1741  if ((input->type == pe_order_load) && action->rsc
1742  && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)
1743  && graph_has_loop(action, action, input)) {
1744  return true;
1745  }
1746 
1747  return false;
1748 }
1749 
1750 // Remove duplicate inputs (regardless of flags)
1751 static void
1752 deduplicate_inputs(pe_action_t *action)
1753 {
1754  GList *item = NULL;
1755  GList *next = NULL;
1756  pe_action_wrapper_t *last_input = NULL;
1757 
1758  action->actions_before = g_list_sort(action->actions_before,
1759  sort_action_id);
1760  for (item = action->actions_before; item != NULL; item = next) {
1761  pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1762 
1763  next = item->next;
1764  if (last_input && (input->action->id == last_input->action->id)) {
1765  crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1766  input->action->uuid, input->action->id,
1767  action->uuid, action->id);
1768 
1769  /* For the purposes of scheduling, the ordering flags no longer
1770  * matter, but crm_simulate looks at certain ones when creating a
1771  * dot graph. Combining the flags is sufficient for that purpose.
1772  */
1773  last_input->type |= input->type;
1774  if (input->state == pe_link_dumped) {
1775  last_input->state = pe_link_dumped;
1776  }
1777 
1778  free(item->data);
1779  action->actions_before = g_list_delete_link(action->actions_before,
1780  item);
1781  } else {
1782  last_input = input;
1783  input->state = pe_link_not_dumped;
1784  }
1785  }
1786 }
1787 
1803 void
1805 {
1806  GList *lpc = NULL;
1807  int synapse_priority = 0;
1808  xmlNode *syn = NULL;
1809  xmlNode *set = NULL;
1810  xmlNode *in = NULL;
1811  xmlNode *xml_action = NULL;
1812  pe_action_wrapper_t *input = NULL;
1813 
1814  /* If we haven't already, de-duplicate inputs -- even if we won't be dumping
1815  * the action, so that crm_simulate dot graphs don't have duplicates.
1816  */
1817  if (!pcmk_is_set(action->flags, pe_action_dedup)) {
1818  deduplicate_inputs(action);
1820  }
1821 
1822  if (should_dump_action(action) == FALSE) {
1823  return;
1824  }
1825 
1827 
1828  syn = create_xml_node(data_set->graph, "synapse");
1829  set = create_xml_node(syn, "action_set");
1830  in = create_xml_node(syn, "inputs");
1831 
1832  crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
1833  data_set->num_synapse++;
1834 
1835  if (action->rsc != NULL) {
1836  synapse_priority = action->rsc->priority;
1837  }
1838  if (action->priority > synapse_priority) {
1839  synapse_priority = action->priority;
1840  }
1841  if (synapse_priority > 0) {
1842  crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
1843  }
1844 
1845  xml_action = action2xml(action, FALSE, data_set);
1846  add_node_nocopy(set, crm_element_name(xml_action), xml_action);
1847 
1848  for (lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
1849  input = (pe_action_wrapper_t *) lpc->data;
1850  if (check_dump_input(action, input)) {
1851  xmlNode *input_xml = create_xml_node(in, "trigger");
1852 
1853  input->state = pe_link_dumped;
1854  xml_action = action2xml(input->action, TRUE, data_set);
1855  add_node_nocopy(input_xml, crm_element_name(xml_action), xml_action);
1856  }
1857  }
1858 }
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:98
enum pe_link_state state
Definition: pe_types.h:509
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
char uname[MAX_NAME]
Definition: internal.h:85
GListPtr nodes
Definition: pe_types.h:148
const char * task2text(enum action_tasks task)
Definition: common.c:410
#define RSC_STOP
Definition: crm.h:199
A dumping ground.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:184
#define CRMD_ACTION_MIGRATED
Definition: crm.h:169
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
#define XML_CONFIG_ATTR_SHUTDOWN_LOCK
Definition: msg_xml.h:356
#define INFINITY
Definition: crm.h:95
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:59
gboolean is_parent(pe_resource_t *child, pe_resource_t *rsc)
Definition: complex.c:782
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:785
int runnable_before
Definition: pe_types.h:423
#define CRM_OP_FENCE
Definition: crm.h:141
#define XML_GRAPH_TAG_MAINTENANCE
Definition: msg_xml.h:300
void add_maintenance_update(pe_working_set_t *data_set)
pe_resource_t * container
Definition: pe_types.h:367
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:842
#define XML_ATTR_TYPE
Definition: msg_xml.h:99
resource_alloc_functions_t * cmds
Definition: pe_types.h:320
Internal tracking for transition graph creation.
Definition: pe_types.h:453
enum pe_graph_flags(* update_actions)(pe_action_t *, pe_action_t *, pe_node_t *, enum pe_action_flags, enum pe_action_flags, enum pe_ordering, pe_working_set_t *data_set)
pe_resource_t * rsc
Definition: pe_types.h:391
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:425
void pe_foreach_guest_node(const pe_working_set_t *data_set, const pe_node_t *host, void(*helper)(const pe_node_t *, void *), void *user_data)
Definition: remote.c:120
#define CRM_FEATURE_SET
Definition: crm.h:54
pe_resource_t * remote_rsc
Definition: pe_types.h:219
#define pe_rsc_unique
Definition: pe_types.h:243
#define pe_rsc_notify
Definition: pe_types.h:242
#define XML_TAG_ATTRS
Definition: msg_xml.h:172
resource_object_functions_t * fns
Definition: pe_types.h:319
void pe_action_set_flag_reason(const char *function, long line, pe_action_t *action, pe_action_t *reason, const char *text, enum pe_action_flags flags, bool overwrite)
Definition: utils.c:2620
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:317
#define pe__clear_graph_flags(graph_flags, gr_action, flags_to_clear)
Definition: internal.h:132
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:296
GListPtr resources
Definition: pe_types.h:149
#define XML_NODE_IS_MAINTENANCE
Definition: msg_xml.h:251
AIS_Host host
Definition: internal.h:84
enum action_tasks text2task(const char *task)
Definition: common.c:358
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:298
#define RSC_START
Definition: crm.h:196
pe_action_t * action
Definition: pe_types.h:510
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:504
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:751
#define XML_GRAPH_TAG_DOWNED
Definition: msg_xml.h:299
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:189
#define pe__set_raw_action_flags(action_flags, action_name, flags_to_set)
Definition: internal.h:77
GListPtr actions_before
Definition: pe_types.h:428
#define RSC_NOTIFY
Definition: crm.h:207
#define RSC_MIGRATE
Definition: crm.h:193
const char * action
Definition: pcmk_fence.c:30
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:297
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:242
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:268
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:267
#define CRM_OP_LRM_REFRESH
Definition: crm.h:145
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:53
#define CRMD_ACTION_STOP
Definition: crm.h:174
#define CRM_OP_CLEAR_FAILCOUNT
Definition: crm.h:151
#define crm_warn(fmt, args...)
Definition: logging.h:348
pe_action_flags
Definition: pe_types.h:279
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:228
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:290
#define pe_rsc_failed
Definition: pe_types.h:255
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1929
#define crm_debug(fmt, args...)
Definition: logging.h:352
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:799
#define pe__clear_order_flags(order_flags, flags_to_clear)
Definition: internal.h:118
gboolean shutdown_constraints(pe_node_t *node, pe_action_t *shutdown_op, pe_working_set_t *data_set)
#define XML_ATTR_ID
Definition: msg_xml.h:96
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
char * task
Definition: pe_types.h:395
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:68
int custom_action_order(pe_resource_t *lh_rsc, char *lh_task, pe_action_t *lh_action, pe_resource_t *rh_rsc, char *rh_task, pe_action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set)
#define crm_trace(fmt, args...)
Definition: logging.h:353
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:196
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:641
void rsc_stonith_ordering(pe_resource_t *rsc, pe_action_t *stonith_op, pe_working_set_t *data_set)
struct pe_node_shared_s * details
Definition: pe_types.h:233
GListPtr running_on
Definition: pe_types.h:353
pe_node_t * node
Definition: pe_types.h:392
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:237
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1883
unsigned long long flags
Definition: pe_types.h:335
const char * uname
Definition: pe_types.h:198
GListPtr actions
Definition: pe_types.h:155
Wrappers for and extensions to libxml2.
Internal state tracking when creating graph.
Definition: pe_types.h:303
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
#define pe__set_graph_flags(graph_flags, gr_action, flags_to_set)
Definition: internal.h:125
pe_graph_flags
Definition: pe_types.h:271
void(* append_meta)(pe_resource_t *rsc, xmlNode *xml)
GListPtr rsc_cons_lhs
Definition: pe_types.h:343
char * uuid
Definition: pe_types.h:396
gboolean update_action_flags(pe_action_t *action, enum pe_action_flags flags, const char *source, int line)
#define XML_LRM_ATTR_ROUTER_NODE
Definition: msg_xml.h:275
pe_resource_t * rsc_lh
#define XML_TAG_RSC_VER_ATTRS
Definition: msg_xml.h:173
void free_xml(xmlNode *child)
Definition: xml.c:790
#define PCMK__ENV_PHYSICAL_HOST
Definition: crm_internal.h:93
void update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
enum pe_obj_types variant
Definition: pe_types.h:317
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:2010
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:166
GListPtr actions
Definition: pe_types.h:346
#define CRM_OP_SHUTDOWN
Definition: crm.h:140
const char * id
Definition: pe_types.h:197
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:44
#define CRM_OP_MAINTENANCE_NODES
Definition: crm.h:156
#define CRMD_ACTION_RELOAD
Definition: crm.h:167
xmlNode * sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
Definition: xml.c:2745
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:270
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition: nvpair.c:475
void pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
#define XML_ATTR_UUID
Definition: msg_xml.h:119
#define XML_TAG_CIB
Definition: msg_xml.h:76
void log_action(unsigned int log_level, const char *pre_text, pe_action_t *action, gboolean details)
void get_rsc_attributes(GHashTable *meta_hash, pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: complex.c:147
GListPtr children
Definition: pe_types.h:364
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:210
Cluster Configuration.
#define pe_rsc_reload
Definition: pe_types.h:252
char uname[MAX_NAME]
Definition: internal.h:39
#define PCMK__XA_MODE
Definition: crm_internal.h:60
GListPtr actions_after
Definition: pe_types.h:429
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:265
#define DIMOF(a)
Definition: crm.h:57
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry, as meta-attribute name.
Definition: nvpair.c:813
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:79
void graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
#define pe_rsc_block
Definition: pe_types.h:239
enum pe_action_flags flags
Definition: pe_types.h:400
gboolean maintenance
Definition: pe_types.h:211
#define CRM_OP_PROBED
Definition: crm.h:149
#define pe_rsc_maintenance
Definition: pe_types.h:264
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
Definition: xml.c:655
bool pcmk__ordering_is_invalid(pe_action_t *action, pe_action_wrapper_t *input)
gboolean rsc_update_action(pe_action_t *first, pe_action_t *then, enum pe_ordering type)
gboolean update_action(pe_action_t *then, pe_working_set_t *data_set)
#define crm_log_xml_trace(xml, text)
Definition: logging.h:361
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:269
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
#define pe__set_order_flags(order_flags, flags_to_set)
Definition: internal.h:111
pe_action_t * find_first_action(GListPtr input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1503
#define ID(x)
Definition: msg_xml.h:425
#define pe_err(fmt...)
Definition: internal.h:22
#define CRM_OP_LRM_DELETE
Definition: crm.h:147
enum pe_ordering type
Definition: pe_types.h:508
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
GList * GListPtr
Definition: crm.h:214
#define pe__clear_raw_action_flags(action_flags, action_name, flags_to_clear)
Definition: internal.h:84
#define pe_rsc_managed
Definition: pe_types.h:238
#define pe_rsc_orphan
Definition: pe_types.h:237
pe_ordering
Definition: pe_types.h:464
uint64_t flags
Definition: remote.c:149
int required_runnable_before
Definition: pe_types.h:426
action_tasks
Definition: common.h:62
pe_resource_t * parent
Definition: pe_types.h:315
enum crm_ais_msg_types type
Definition: internal.h:83
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:236
xmlNode * graph
Definition: pe_types.h:167
char * id
Definition: pe_types.h:308