pacemaker  2.1.1-52dc28db4
Scalable High-Availability cluster resource manager
pcmk_sched_graph.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 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  && pcmk_is_set(then->flags, pe_action_optional)) {
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 (pcmk_is_set(first->flags, pe_action_runnable)) {
254  }
255  }
256 
257  if (changed) {
258  pe_rsc_trace(then->rsc, "implies left: %s then %s: changed", first->uuid, then->uuid);
259  } else {
260  crm_trace("implies left: %s (%d) then %s (%d)",
261  first->uuid, pcmk_is_set(first_flags, pe_action_optional),
262  then->uuid, pcmk_is_set(then_flags, pe_action_optional));
263  }
264  }
265 
267  processed = TRUE;
268  if (then->rsc) {
269  changed |= then->rsc->cmds->update_actions(first, then, node,
270  first_flags & pe_action_optional, pe_action_optional,
272  }
273 
274  if (changed) {
275  pe_rsc_trace(then->rsc,
276  "implies left when right resource is promoted: "
277  "%s then %s: changed", first->uuid, then->uuid);
278  } else {
279  crm_trace("implies left when right resource is promoted: "
280  "%s then %s", first->uuid, then->uuid);
281  }
282  }
283 
284  if (type & pe_order_one_or_more) {
285  processed = TRUE;
286  if (then->rsc) {
287  changed |= then->rsc->cmds->update_actions(first, then, node,
289  data_set);
290 
291  } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
292  // We have another runnable instance of "first"
293  then->runnable_before++;
294 
295  /* Mark "then" as runnable if it requires a certain number of
296  * "before" instances to be runnable, and they now are.
297  */
298  if ((then->runnable_before >= then->required_runnable_before)
299  && !pcmk_is_set(then->flags, pe_action_runnable)) {
300 
303  }
304  }
305  if (changed) {
306  pe_rsc_trace(then->rsc, "runnable_one_or_more: %s then %s: changed", first->uuid,
307  then->uuid);
308  } else {
309  crm_trace("runnable_one_or_more: %s then %s", first->uuid, then->uuid);
310  }
311  }
312 
313  if (then->rsc && pcmk_is_set(type, pe_order_probe)) {
314  processed = TRUE;
315 
316  if (!pcmk_is_set(first_flags, pe_action_runnable)
317  && (first->rsc->running_on != NULL)) {
318 
319  pe_rsc_trace(then->rsc, "Ignoring %s then %s - %s is about to be stopped",
320  first->uuid, then->uuid, first->rsc->id);
322  order->type = pe_order_none;
323 
324  } else {
325  pe_rsc_trace(then->rsc, "Enforcing %s then %s", first->uuid, then->uuid);
326  changed |= then->rsc->cmds->update_actions(first, then, node,
328  data_set);
329  }
330 
331  if (changed) {
332  pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
333  } else {
334  crm_trace("runnable: %s then %s", first->uuid, then->uuid);
335  }
336  }
337 
339  processed = TRUE;
340  if (then->rsc) {
341  changed |= then->rsc->cmds->update_actions(first, then, node,
343  data_set);
344 
345  } else if (!pcmk_is_set(first_flags, pe_action_runnable)
346  && pcmk_is_set(then->flags, pe_action_runnable)) {
347 
350  }
351  if (changed) {
352  pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
353  } else {
354  crm_trace("runnable: %s then %s", first->uuid, then->uuid);
355  }
356  }
357 
359  processed = TRUE;
360  if (then->rsc) {
361  changed |= then->rsc->cmds->update_actions(first, then, node,
362  first_flags, pe_action_optional,
364  }
365  if (changed) {
366  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
367  } else {
368  crm_trace("optional: %s then %s", first->uuid, then->uuid);
369  }
370  }
371 
372  if (type & pe_order_pseudo_left) {
373  processed = TRUE;
374  if (then->rsc) {
375  changed |= then->rsc->cmds->update_actions(first, then, node,
377  data_set);
378  }
379  if (changed) {
380  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
381  } else {
382  crm_trace("optional: %s then %s", first->uuid, then->uuid);
383  }
384  }
385 
386  if (type & pe_order_optional) {
387  processed = TRUE;
388  if (then->rsc) {
389  changed |= then->rsc->cmds->update_actions(first, then, node,
390  first_flags, pe_action_runnable, pe_order_optional, data_set);
391  }
392  if (changed) {
393  pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
394  } else {
395  crm_trace("optional: %s then %s", first->uuid, then->uuid);
396  }
397  }
398 
399  if (type & pe_order_asymmetrical) {
400  processed = TRUE;
401  if (then->rsc) {
402  changed |= then->rsc->cmds->update_actions(first, then, node,
404  data_set);
405  }
406 
407  if (changed) {
408  pe_rsc_trace(then->rsc, "asymmetrical: %s then %s: changed", first->uuid, then->uuid);
409  } else {
410  crm_trace("asymmetrical: %s then %s", first->uuid, then->uuid);
411  }
412 
413  }
414 
416  && (first_flags & pe_action_optional) == 0) {
417  processed = TRUE;
418  crm_trace("%s implies %s printed", first->uuid, then->uuid);
420  // Don't bother marking 'then' as changed just for this
421  }
422 
424  && !pcmk_is_set(then_flags, pe_action_optional)) {
425 
426  processed = TRUE;
427  crm_trace("%s implies %s printed", then->uuid, first->uuid);
429  // Don't bother marking 'first' as changed just for this
430  }
431 
434  || type & pe_order_restart)
435  && first->rsc
436  && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)
437  && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
438  && pcmk_is_set(first->rsc->flags, pe_rsc_block)
439  && !pcmk_is_set(first->flags, pe_action_runnable)) {
440 
441  if (pcmk_is_set(then->flags, pe_action_runnable)) {
444  }
445 
446  if (changed) {
447  pe_rsc_trace(then->rsc, "unmanaged left: %s then %s: changed", first->uuid, then->uuid);
448  } else {
449  crm_trace("unmanaged left: %s then %s", first->uuid, then->uuid);
450  }
451  }
452 
453  if (processed == FALSE) {
454  crm_trace("Constraint 0x%.6x not applicable", type);
455  }
456 
457  return changed;
458 }
459 
460 static void
461 mark_start_blocked(pe_resource_t *rsc, pe_resource_t *reason,
462  pe_working_set_t *data_set)
463 {
464  GList *gIter = rsc->actions;
465  char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
466 
467  for (; gIter != NULL; gIter = gIter->next) {
468  pe_action_t *action = (pe_action_t *) gIter->data;
469 
470  if (!pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
471  continue;
472  }
473  if (pcmk_is_set(action->flags, pe_action_runnable)) {
474  pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
475  reason_text, pe_action_runnable, FALSE);
476  update_colo_start_chain(action, data_set);
477  update_action(action, data_set);
478  }
479  }
480  free(reason_text);
481 }
482 
483 void
485 {
486  GList *gIter = NULL;
487  pe_resource_t *rsc = NULL;
488 
490  && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
491 
492  rsc = uber_parent(action->rsc);
493  if (rsc->parent) {
494  /* For bundles, uber_parent() returns the clone, not the bundle, so
495  * the existence of rsc->parent implies this is a bundle.
496  * In this case, we need the bundle resource, so that we can check
497  * if all containers are stopped/stopping.
498  */
499  rsc = rsc->parent;
500  }
501  }
502 
503  if (rsc == NULL || rsc->rsc_cons_lhs == NULL) {
504  return;
505  }
506 
507  /* if rsc has children, all the children need to have start set to
508  * unrunnable before we follow the colo chain for the parent. */
509  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
510  pe_resource_t *child = (pe_resource_t *)gIter->data;
511  pe_action_t *start = find_first_action(child->actions, NULL, RSC_START, NULL);
512  if ((start == NULL) || pcmk_is_set(start->flags, pe_action_runnable)) {
513  return;
514  }
515  }
516 
517  for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
518  pcmk__colocation_t *colocate_with = (pcmk__colocation_t *) gIter->data;
519 
520  if (colocate_with->score == INFINITY) {
521  mark_start_blocked(colocate_with->rsc_lh, action->rsc, data_set);
522  }
523  }
524 }
525 
526 gboolean
528 {
529  GList *lpc = NULL;
530  enum pe_graph_flags changed = pe_graph_none;
531  int last_flags = then->flags;
532 
533  crm_trace("Processing %s (%s %s %s)",
534  then->uuid,
535  pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
536  pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
537  pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
538  : (then->node? then->node->details->uname : ""));
539 
541  /* initialize current known runnable before actions to 0
542  * from here as graph_update_action is called for each of
543  * then's before actions, this number will increment as
544  * runnable 'first' actions are encountered */
545  then->runnable_before = 0;
546 
547  /* for backwards compatibility with previous options that use
548  * the 'requires_any' flag, initialize required to 1 if it is
549  * not set. */
550  if (then->required_runnable_before == 0) {
551  then->required_runnable_before = 1;
552  }
554  /* We are relying on the pe_order_one_or_more clause of
555  * graph_update_action(), called as part of the:
556  *
557  * 'if (first == other->action)'
558  *
559  * block below, to set this back if appropriate
560  */
561  }
562 
563  for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
564  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
565  pe_action_t *first = other->action;
566 
567  pe_node_t *then_node = then->node;
568  pe_node_t *first_node = first->node;
569 
570  enum pe_action_flags then_flags = 0;
571  enum pe_action_flags first_flags = 0;
572 
573  if (first->rsc && first->rsc->variant == pe_group && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
574  first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
575  if (first_node) {
576  crm_trace("First: Found node %s for %s", first_node->details->uname, first->uuid);
577  }
578  }
579 
580  if (then->rsc && then->rsc->variant == pe_group && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
581  then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
582  if (then_node) {
583  crm_trace("Then: Found node %s for %s", then_node->details->uname, then->uuid);
584  }
585  }
586  /* Disable constraint if it only applies when on same node, but isn't */
587  if (pcmk_is_set(other->type, pe_order_same_node)
588  && (first_node != NULL) && (then_node != NULL)
589  && (first_node->details != then_node->details)) {
590 
591  crm_trace("Disabled constraint %s on %s -> %s on %s",
592  other->action->uuid, first_node->details->uname,
593  then->uuid, then_node->details->uname);
594  other->type = pe_order_none;
595  continue;
596  }
597 
599 
600  if (first->rsc && pcmk_is_set(other->type, pe_order_then_cancels_first)
601  && !pcmk_is_set(then->flags, pe_action_optional)) {
602 
603  /* 'then' is required, so we must abandon 'first'
604  * (e.g. a required stop cancels any agent reload).
605  */
607  if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
609  }
610  }
611 
612  if (first->rsc && then->rsc && (first->rsc != then->rsc)
613  && (is_parent(then->rsc, first->rsc) == FALSE)) {
614  first = rsc_expand_action(first);
615  }
616  if (first != other->action) {
617  crm_trace("Ordering %s after %s instead of %s", then->uuid, first->uuid,
618  other->action->uuid);
619  }
620 
621  first_flags = get_action_flags(first, then_node);
622  then_flags = get_action_flags(then, first_node);
623 
624  crm_trace("Checking %s (%s %s %s) against %s (%s %s %s) filter=0x%.6x type=0x%.6x",
625  then->uuid,
626  pcmk_is_set(then_flags, pe_action_optional)? "optional" : "required",
627  pcmk_is_set(then_flags, pe_action_runnable)? "runnable" : "unrunnable",
628  pcmk_is_set(then_flags, pe_action_pseudo)? "pseudo"
629  : (then->node? then->node->details->uname : ""),
630  first->uuid,
631  pcmk_is_set(first_flags, pe_action_optional)? "optional" : "required",
632  pcmk_is_set(first_flags, pe_action_runnable)? "runnable" : "unrunnable",
633  pcmk_is_set(first_flags, pe_action_pseudo)? "pseudo"
634  : (first->node? first->node->details->uname : ""),
635  first_flags, other->type);
636 
637  if (first == other->action) {
638  /*
639  * 'first' was not expanded (e.g. from 'start' to 'running'), which could mean it:
640  * - has no associated resource,
641  * - was a primitive,
642  * - was pre-expanded (e.g. 'running' instead of 'start')
643  *
644  * The third argument here to graph_update_action() is a node which is used under two conditions:
645  * - Interleaving, in which case first->node and
646  * then->node are equal (and NULL)
647  * - If 'then' is a clone, to limit the scope of the
648  * constraint to instances on the supplied node
649  *
650  */
651  pe_node_t *node = then->node;
652  changed |= graph_update_action(first, then, node, first_flags,
653  then_flags, other, data_set);
654 
655  /* 'first' was for a complex resource (clone, group, etc),
656  * create a new dependency if necessary
657  */
658  } else if (order_actions(first, then, other->type)) {
659  /* This was the first time 'first' and 'then' were associated,
660  * start again to get the new actions_before list
661  */
662  pe__set_graph_flags(changed, then,
664  }
665 
666  if (changed & pe_graph_disable) {
667  crm_trace("Disabled constraint %s -> %s in favor of %s -> %s",
668  other->action->uuid, then->uuid, first->uuid, then->uuid);
669  pe__clear_graph_flags(changed, then, pe_graph_disable);
670  other->type = pe_order_none;
671  }
672 
673  if (changed & pe_graph_updated_first) {
674  GList *lpc2 = NULL;
675 
676  crm_trace("Updated %s (first %s %s %s), processing dependents ",
677  first->uuid,
678  pcmk_is_set(first->flags, pe_action_optional)? "optional" : "required",
679  pcmk_is_set(first->flags, pe_action_runnable)? "runnable" : "unrunnable",
680  pcmk_is_set(first->flags, pe_action_pseudo)? "pseudo"
681  : (first->node? first->node->details->uname : ""));
682  for (lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) {
683  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
684 
685  update_action(other->action, data_set);
686  }
687  update_action(first, data_set);
688  }
689  }
690 
692  if (last_flags != then->flags) {
694  } else {
696  }
697  }
698 
699  if (changed & pe_graph_updated_then) {
700  crm_trace("Updated %s (then %s %s %s), processing dependents ",
701  then->uuid,
702  pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
703  pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
704  pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
705  : (then->node? then->node->details-> uname : ""));
706 
707  if (pcmk_is_set(last_flags, pe_action_runnable)
708  && !pcmk_is_set(then->flags, pe_action_runnable)) {
709  update_colo_start_chain(then, data_set);
710  }
711  update_action(then, data_set);
712  for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
713  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
714 
715  update_action(other->action, data_set);
716  }
717  }
718 
719  return FALSE;
720 }
721 
722 gboolean
723 shutdown_constraints(pe_node_t * node, pe_action_t * shutdown_op, pe_working_set_t * data_set)
724 {
725  /* add the stop to the before lists so it counts as a pre-req
726  * for the shutdown
727  */
728  GList *lpc = NULL;
729 
730  for (lpc = data_set->actions; lpc != NULL; lpc = lpc->next) {
731  pe_action_t *action = (pe_action_t *) lpc->data;
732 
733  if (action->rsc == NULL || action->node == NULL) {
734  continue;
735  } else if (action->node->details != node->details) {
736  continue;
737  } else if (pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)) {
738  pe_rsc_trace(action->rsc, "Skipping %s: maintenance mode", action->uuid);
739  continue;
740  } else if (node->details->maintenance) {
741  pe_rsc_trace(action->rsc, "Skipping %s: node %s is in maintenance mode",
742  action->uuid, node->details->uname);
743  continue;
744  } else if (!pcmk__str_eq(action->task, RSC_STOP, pcmk__str_casei)) {
745  continue;
746  } else if (!pcmk_any_flags_set(action->rsc->flags,
748  /*
749  * If another action depends on this one, we may still end up blocking
750  */
751  pe_rsc_trace(action->rsc, "Skipping %s: unmanaged", action->uuid);
752  continue;
753  }
754 
755  pe_rsc_trace(action->rsc, "Ordering %s before shutdown on %s", action->uuid,
756  node->details->uname);
758  custom_action_order(action->rsc, NULL, action,
759  NULL, strdup(CRM_OP_SHUTDOWN), shutdown_op,
761  }
762 
763  return TRUE;
764 }
765 
777 void
779 {
780  CRM_CHECK(stonith_op && data_set, return);
781  for (GList *r = data_set->resources; r != NULL; r = r->next) {
782  rsc_stonith_ordering((pe_resource_t *) r->data, stonith_op, data_set);
783  }
784 }
785 
786 static pe_node_t *
787 get_router_node(pe_action_t *action)
788 {
789  pe_node_t *began_on = NULL;
790  pe_node_t *ended_on = NULL;
791  bool partial_migration = FALSE;
792  const char *task = action->task;
793 
794  if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)
795  || !pe__is_guest_or_remote_node(action->node)) {
796  return NULL;
797  }
798 
799  CRM_ASSERT(action->node->details->remote_rsc != NULL);
800 
801  began_on = pe__current_node(action->node->details->remote_rsc);
802  ended_on = action->node->details->remote_rsc->allocated_to;
803  if (action->node->details->remote_rsc
804  && (action->node->details->remote_rsc->container == NULL)
805  && action->node->details->remote_rsc->partial_migration_target) {
806  partial_migration = TRUE;
807  }
808 
809  if (began_on == NULL) {
810  crm_trace("Routing %s for %s through remote connection's "
811  "next node %s (starting)%s",
812  action->task, (action->rsc? action->rsc->id : "no resource"),
813  (ended_on? ended_on->details->uname : "none"),
814  partial_migration? " (partial migration)" : "");
815  return ended_on;
816  }
817 
818  if (ended_on == NULL) {
819  crm_trace("Routing %s for %s through remote connection's "
820  "current node %s (stopping)%s",
821  action->task, (action->rsc? action->rsc->id : "no resource"),
822  (began_on? began_on->details->uname : "none"),
823  partial_migration? " (partial migration)" : "");
824  return began_on;
825  }
826 
827  if (began_on->details == ended_on->details) {
828  crm_trace("Routing %s for %s through remote connection's "
829  "current node %s (not moving)%s",
830  action->task, (action->rsc? action->rsc->id : "no resource"),
831  (began_on? began_on->details->uname : "none"),
832  partial_migration? " (partial migration)" : "");
833  return began_on;
834  }
835 
836  /* If we get here, the remote connection is moving during this transition.
837  * This means some actions for resources behind the connection will get
838  * routed through the cluster node the connection reource is currently on,
839  * and others are routed through the cluster node the connection will end up
840  * on.
841  */
842 
843  if (pcmk__str_eq(task, "notify", pcmk__str_casei)) {
844  task = g_hash_table_lookup(action->meta, "notify_operation");
845  }
846 
847  /*
848  * Stop, demote, and migration actions must occur before the connection can
849  * move (these actions are required before the remote resource can stop). In
850  * this case, we know these actions have to be routed through the initial
851  * cluster node the connection resource lived on before the move takes
852  * place.
853  *
854  * The exception is a partial migration of a (non-guest) remote connection
855  * resource; in that case, all actions (even these) will be ordered after
856  * the connection's pseudo-start on the migration target, so the target is
857  * the router node.
858  */
859  if (pcmk__strcase_any_of(task, "cancel", "stop", "demote", "migrate_from",
860  "migrate_to", NULL) && !partial_migration) {
861  crm_trace("Routing %s for %s through remote connection's "
862  "current node %s (moving)%s",
863  action->task, (action->rsc? action->rsc->id : "no resource"),
864  (began_on? began_on->details->uname : "none"),
865  partial_migration? " (partial migration)" : "");
866  return began_on;
867  }
868 
869  /* Everything else (start, promote, monitor, probe, refresh,
870  * clear failcount, delete, ...) must occur after the connection starts on
871  * the node it is moving to.
872  */
873  crm_trace("Routing %s for %s through remote connection's "
874  "next node %s (moving)%s",
875  action->task, (action->rsc? action->rsc->id : "no resource"),
876  (ended_on? ended_on->details->uname : "none"),
877  partial_migration? " (partial migration)" : "");
878  return ended_on;
879 }
880 
888 static xmlNode*
889 add_node_to_xml_by_id(const char *id, xmlNode *xml)
890 {
891  xmlNode *node_xml;
892 
893  node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
894  crm_xml_add(node_xml, XML_ATTR_UUID, id);
895 
896  return node_xml;
897 }
898 
906 static void
907 add_node_to_xml(const pe_node_t *node, void *xml)
908 {
909  add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
910 }
911 
919 static int
920 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
921 {
922  GList *gIter = NULL;
923  xmlNode *maintenance =
925  int count = 0;
926 
927  for (gIter = data_set->nodes; gIter != NULL;
928  gIter = gIter->next) {
929  pe_node_t *node = (pe_node_t *) gIter->data;
930  struct pe_node_shared_s *details = node->details;
931 
932  if (!pe__is_guest_or_remote_node(node)) {
933  continue; /* just remote nodes need to know atm */
934  }
935 
936  if (details->maintenance != details->remote_maintenance) {
937  if (maintenance) {
938  crm_xml_add(
939  add_node_to_xml_by_id(node->details->id, maintenance),
940  XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
941  }
942  count++;
943  }
944  }
945  crm_trace("%s %d nodes to adjust maintenance-mode "
946  "to transition", maintenance?"Added":"Counted", count);
947  return count;
948 }
949 
956 void
958 {
959  pe_action_t *action = NULL;
960 
961  if (add_maintenance_nodes(NULL, data_set)) {
962  crm_trace("adding maintenance state update pseudo action");
965  }
966 }
967 
980 static void
981 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
982  const pe_working_set_t *data_set)
983 {
984  CRM_CHECK(xml && action && action->node && data_set, return);
985 
986  if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
987 
988  /* Shutdown makes the action's node down */
989  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
990  add_node_to_xml_by_id(action->node->details->id, downed);
991 
992  } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
993 
994  /* Fencing makes the action's node and any hosted guest nodes down */
995  const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
996 
997  if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
998  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
999  add_node_to_xml_by_id(action->node->details->id, downed);
1000  pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
1001  }
1002 
1003  } else if (action->rsc && action->rsc->is_remote_node
1004  && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
1005 
1006  /* Stopping a remote connection resource makes connected node down,
1007  * unless it's part of a migration
1008  */
1009  GList *iter;
1010  pe_action_t *input;
1011  gboolean migrating = FALSE;
1012 
1013  for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1014  input = ((pe_action_wrapper_t *) iter->data)->action;
1015  if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
1016  && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
1017  migrating = TRUE;
1018  break;
1019  }
1020  }
1021  if (!migrating) {
1022  xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
1023  add_node_to_xml_by_id(action->rsc->id, downed);
1024  }
1025  }
1026 }
1027 
1028 static bool
1029 should_lock_action(pe_action_t *action)
1030 {
1031  // Only actions taking place on resource's lock node are locked
1032  if ((action->rsc->lock_node == NULL) || (action->node == NULL)
1033  || (action->node->details != action->rsc->lock_node->details)) {
1034  return false;
1035  }
1036 
1037  /* During shutdown, only stops are locked (otherwise, another action such as
1038  * a demote would cause the controller to clear the lock)
1039  */
1040  if (action->node->details->shutdown && action->task
1041  && strcmp(action->task, RSC_STOP)) {
1042  return false;
1043  }
1044 
1045  return true;
1046 }
1047 
1048 static xmlNode *
1049 action2xml(pe_action_t * action, gboolean as_input, pe_working_set_t *data_set)
1050 {
1051  gboolean needs_node_info = TRUE;
1052  gboolean needs_maintenance_info = FALSE;
1053  xmlNode *action_xml = NULL;
1054  xmlNode *args_xml = NULL;
1055 #if ENABLE_VERSIONED_ATTRS
1056  pe_rsc_action_details_t *rsc_details = NULL;
1057 #endif
1058 
1059  if (action == NULL) {
1060  return NULL;
1061  }
1062 
1063  if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1064  /* All fences need node info; guest node fences are pseudo-events */
1065  action_xml = create_xml_node(NULL,
1069 
1070  } else if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1071  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1072 
1073  } else if (pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
1074  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1075 
1076  } else if (pcmk__str_eq(action->task, CRM_OP_LRM_REFRESH, pcmk__str_casei)) {
1077  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1078 
1079  } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
1080  // CIB-only clean-up for shutdown locks
1081  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1082  crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
1083 
1084 /* } else if(pcmk__str_eq(action->task, RSC_PROBED, pcmk__str_casei)) { */
1085 /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */
1086 
1087  } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
1088  if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
1089  needs_maintenance_info = TRUE;
1090  }
1091  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
1092  needs_node_info = FALSE;
1093 
1094  } else {
1095  action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
1096 
1097 #if ENABLE_VERSIONED_ATTRS
1098  rsc_details = pe_rsc_action_details(action);
1099 #endif
1100  }
1101 
1102  crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
1103  crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
1104  if (action->rsc != NULL && action->rsc->clone_name != NULL) {
1105  char *clone_key = NULL;
1106  guint interval_ms;
1107 
1108  if (pcmk__guint_from_hash(action->meta,
1110  &interval_ms) != pcmk_rc_ok) {
1111  interval_ms = 0;
1112  }
1113 
1114  if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_casei)) {
1115  const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
1116  const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1117 
1118  CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid));
1119  CRM_CHECK(n_task != NULL,
1120  crm_err("No notify operation value found for %s", action->uuid));
1121  clone_key = pcmk__notify_key(action->rsc->clone_name,
1122  n_type, n_task);
1123 
1124  } else if(action->cancel_task) {
1125  clone_key = pcmk__op_key(action->rsc->clone_name,
1126  action->cancel_task, interval_ms);
1127  } else {
1128  clone_key = pcmk__op_key(action->rsc->clone_name,
1129  action->task, interval_ms);
1130  }
1131 
1132  CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid));
1133  crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
1134  crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
1135  free(clone_key);
1136 
1137  } else {
1138  crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
1139  }
1140 
1141  if (needs_node_info && action->node != NULL) {
1142  pe_node_t *router_node = get_router_node(action);
1143 
1144  crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
1145  crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
1146  if (router_node) {
1147  crm_xml_add(action_xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
1148  }
1149 
1150  g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET), strdup(action->node->details->uname));
1151  g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID), strdup(action->node->details->id));
1152  }
1153 
1154  /* No details if this action is only being listed in the inputs section */
1155  if (as_input) {
1156  return action_xml;
1157  }
1158 
1159  if (action->rsc && !pcmk_is_set(action->flags, pe_action_pseudo)) {
1160  int lpc = 0;
1161  xmlNode *rsc_xml = NULL;
1162  const char *attr_list[] = {
1166  };
1167 
1168  /* If a resource is locked to a node via shutdown-lock, mark its actions
1169  * so the controller can preserve the lock when the action completes.
1170  */
1171  if (should_lock_action(action)) {
1173  (long long) action->rsc->lock_time);
1174  }
1175 
1176  // List affected resource
1177 
1178  rsc_xml = create_xml_node(action_xml,
1179  crm_element_name(action->rsc->xml));
1180  if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
1181  && action->rsc->clone_name) {
1182  /* Do not use the 'instance free' name here as that
1183  * might interfere with the instance we plan to keep.
1184  * Ie. if there are more than two named /anonymous/
1185  * instances on a given node, we need to make sure the
1186  * command goes to the right one.
1187  *
1188  * Keep this block, even when everyone is using
1189  * 'instance free' anonymous clone names - it means
1190  * we'll do the right thing if anyone toggles the
1191  * unique flag to 'off'
1192  */
1193  crm_debug("Using orphan clone name %s instead of %s", action->rsc->id,
1194  action->rsc->clone_name);
1195  crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
1196  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1197 
1198  } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
1199  const char *xml_id = ID(action->rsc->xml);
1200 
1201  crm_debug("Using anonymous clone name %s for %s (aka. %s)", xml_id, action->rsc->id,
1202  action->rsc->clone_name);
1203 
1204  /* ID is what we'd like client to use
1205  * ID_LONG is what they might know it as instead
1206  *
1207  * ID_LONG is only strictly needed /here/ during the
1208  * transition period until all nodes in the cluster
1209  * are running the new software /and/ have rebooted
1210  * once (meaning that they've only ever spoken to a DC
1211  * supporting this feature).
1212  *
1213  * If anyone toggles the unique flag to 'on', the
1214  * 'instance free' name will correspond to an orphan
1215  * and fall into the clause above instead
1216  */
1217  crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
1218  if (action->rsc->clone_name && !pcmk__str_eq(xml_id, action->rsc->clone_name, pcmk__str_casei)) {
1219  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
1220  } else {
1221  crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1222  }
1223 
1224  } else {
1225  CRM_ASSERT(action->rsc->clone_name == NULL);
1226  crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
1227  }
1228 
1229  for (lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
1230  crm_xml_add(rsc_xml, attr_list[lpc],
1231  g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
1232  }
1233  }
1234 
1235  /* List any attributes in effect */
1236  args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
1238 
1239  g_hash_table_foreach(action->extra, hash2field, args_xml);
1240  if (action->rsc != NULL && action->node) {
1241  // Get the resource instance attributes, evaluated properly for node
1242  GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
1243 
1244  /* REMOTE_CONTAINER_HACK: If this is a remote connection resource with
1245  * addr="#uname", pull the actual value from the parameters evaluated
1246  * without a node (which was put there earlier in stage8() when the
1247  * bundle's expand() method was called).
1248  */
1249  const char *remote_addr = g_hash_table_lookup(params,
1251 
1252  if (pcmk__str_eq(remote_addr, "#uname", pcmk__str_none)) {
1253  GHashTable *base = pe_rsc_params(action->rsc, NULL, data_set);
1254 
1255  remote_addr = g_hash_table_lookup(base,
1257  if (remote_addr != NULL) {
1258  g_hash_table_insert(params, strdup(XML_RSC_ATTR_REMOTE_RA_ADDR),
1259  strdup(remote_addr));
1260  }
1261  }
1262 
1263  g_hash_table_foreach(params, hash2smartfield, args_xml);
1264 
1265 #if ENABLE_VERSIONED_ATTRS
1266  {
1267  xmlNode *versioned_parameters = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1268 
1269  pe_get_versioned_attributes(versioned_parameters, action->rsc,
1270  action->node, data_set);
1271  if (xml_has_children(versioned_parameters)) {
1272  add_node_copy(action_xml, versioned_parameters);
1273  }
1274  free_xml(versioned_parameters);
1275  }
1276 #endif
1277 
1278  } else if(action->rsc && action->rsc->variant <= pe_native) {
1279  GHashTable *params = pe_rsc_params(action->rsc, NULL, data_set);
1280 
1281  g_hash_table_foreach(params, hash2smartfield, args_xml);
1282 
1283 #if ENABLE_VERSIONED_ATTRS
1284  if (xml_has_children(action->rsc->versioned_parameters)) {
1285  add_node_copy(action_xml, action->rsc->versioned_parameters);
1286  }
1287 #endif
1288  }
1289 
1290 #if ENABLE_VERSIONED_ATTRS
1291  if (rsc_details) {
1292  if (xml_has_children(rsc_details->versioned_parameters)) {
1293  add_node_copy(action_xml, rsc_details->versioned_parameters);
1294  }
1295 
1296  if (xml_has_children(rsc_details->versioned_meta)) {
1297  add_node_copy(action_xml, rsc_details->versioned_meta);
1298  }
1299  }
1300 #endif
1301 
1302  g_hash_table_foreach(action->meta, hash2metafield, args_xml);
1303  if (action->rsc != NULL) {
1304  const char *value = g_hash_table_lookup(action->rsc->meta, "external-ip");
1305  pe_resource_t *parent = action->rsc;
1306 
1307  while (parent != NULL) {
1308  parent->cmds->append_meta(parent, args_xml);
1309  parent = parent->parent;
1310  }
1311 
1312  if(value) {
1313  hash2smartfield((gpointer)"pcmk_external_ip", (gpointer)value, (gpointer)args_xml);
1314  }
1315 
1316  if (action->node && /* make clang analyzer happy */
1317  pe__is_guest_node(action->node)) {
1318  pe_node_t *host = NULL;
1319  enum action_tasks task = text2task(action->task);
1320 
1321  if(task == action_notify || task == action_notified) {
1322  const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1323  task = text2task(n_task);
1324  }
1325 
1326  // Differentiate between up and down actions
1327  switch (task) {
1328  case stop_rsc:
1329  case stopped_rsc:
1330  case action_demote:
1331  case action_demoted:
1332  host = pe__current_node(action->node->details->remote_rsc->container);
1333  break;
1334  case start_rsc:
1335  case started_rsc:
1336  case monitor_rsc:
1337  case action_promote:
1338  case action_promoted:
1339  host = action->node->details->remote_rsc->container->allocated_to;
1340  break;
1341  default:
1342  break;
1343  }
1344 
1345  if(host) {
1347  (gpointer)g_hash_table_lookup(action->rsc->meta, XML_RSC_ATTR_TARGET), (gpointer)args_xml);
1349  (gpointer)host->details->uname,
1350  (gpointer)args_xml);
1351  }
1352  }
1353 
1354  } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei) && action->node) {
1355  /* Pass the node's attributes as meta-attributes.
1356  *
1357  * @TODO: Determine whether it is still necessary to do this. It was
1358  * added in 33d99707, probably for the libfence-based implementation in
1359  * c9a90bd, which is no longer used.
1360  */
1361  g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
1362  }
1363 
1364  sorted_xml(args_xml, action_xml, FALSE);
1365  free_xml(args_xml);
1366 
1367  /* List any nodes this action is expected to make down */
1368  if (needs_node_info && (action->node != NULL)) {
1369  add_downed_nodes(action_xml, action, data_set);
1370  }
1371 
1372  if (needs_maintenance_info) {
1373  add_maintenance_nodes(action_xml, data_set);
1374  }
1375 
1376  crm_log_xml_trace(action_xml, "dumped action");
1377  return action_xml;
1378 }
1379 
1380 static bool
1381 should_dump_action(pe_action_t *action)
1382 {
1383  CRM_CHECK(action != NULL, return false);
1384 
1385  if (pcmk_is_set(action->flags, pe_action_dumped)) {
1386  crm_trace("Action %s (%d) already dumped", action->uuid, action->id);
1387  return false;
1388 
1389  } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1390  && pcmk__str_eq(action->task, CRM_OP_PROBED, pcmk__str_casei)) {
1391  GList *lpc = NULL;
1392 
1393  /* This is a horrible but convenient hack
1394  *
1395  * It mimimizes the number of actions with unsatisfied inputs
1396  * (i.e. not included in the graph)
1397  *
1398  * This in turn, means we can be more concise when printing
1399  * aborted/incomplete graphs.
1400  *
1401  * It also makes it obvious which node is preventing
1402  * probe_complete from running (presumably because it is only
1403  * partially up)
1404  *
1405  * For these reasons we tolerate such perversions
1406  */
1407 
1408  for (lpc = action->actions_after; lpc != NULL; lpc = lpc->next) {
1409  pe_action_wrapper_t *wrapper = (pe_action_wrapper_t *) lpc->data;
1410 
1411  if (!pcmk_is_set(wrapper->action->flags, pe_action_runnable)) {
1412  /* Only interested in runnable operations */
1413  } else if (!pcmk__str_eq(wrapper->action->task, RSC_START, pcmk__str_casei)) {
1414  /* Only interested in start operations */
1415  } else if (pcmk_is_set(wrapper->action->flags, pe_action_dumped)
1416  || should_dump_action(wrapper->action)) {
1417  crm_trace("Action %s (%d) should be dumped: "
1418  "dependency of %s (%d)",
1419  action->uuid, action->id,
1420  wrapper->action->uuid, wrapper->action->id);
1421  return true;
1422  }
1423  }
1424  }
1425 
1426  if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1427  crm_trace("Ignoring action %s (%d): unrunnable",
1428  action->uuid, action->id);
1429  return false;
1430 
1431  } else if (pcmk_is_set(action->flags, pe_action_optional)
1432  && !pcmk_is_set(action->flags, pe_action_print_always)) {
1433  crm_trace("Ignoring action %s (%d): optional",
1434  action->uuid, action->id);
1435  return false;
1436 
1437  // Monitors should be dumped even for unmanaged resources
1438  } else if (action->rsc && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
1439  && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)) {
1440 
1441  const char *interval_ms_s = g_hash_table_lookup(action->meta,
1443 
1444  // Cancellation of recurring monitors should still be dumped
1445  if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
1446  crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
1447  action->uuid, action->id, action->rsc->id);
1448  return false;
1449  }
1450  }
1451 
1452  if (pcmk_is_set(action->flags, pe_action_pseudo) ||
1454  /* skip the next checks */
1455  return true;
1456  }
1457 
1458  if (action->node == NULL) {
1459  pe_err("Skipping action %s (%d) "
1460  "because it was not allocated to a node (bug?)",
1461  action->uuid, action->id);
1462  log_action(LOG_DEBUG, "Unallocated action", action, false);
1463  return false;
1464 
1465  } else if (pcmk_is_set(action->flags, pe_action_dc)) {
1466  crm_trace("Action %s (%d) should be dumped: "
1467  "can run on DC instead of %s",
1468  action->uuid, action->id, action->node->details->uname);
1469 
1470  } else if (pe__is_guest_node(action->node)
1471  && !action->node->details->remote_requires_reset) {
1472  crm_trace("Action %s (%d) should be dumped: "
1473  "assuming will be runnable on guest node %s",
1474  action->uuid, action->id, action->node->details->uname);
1475 
1476  } else if (action->node->details->online == false) {
1477  pe_err("Skipping action %s (%d) "
1478  "because it was scheduled for offline node (bug?)",
1479  action->uuid, action->id);
1480  log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
1481  return false;
1482 #if 0
1483  /* but this would also affect resources that can be safely
1484  * migrated before a fencing op
1485  */
1486  } else if (action->node->details->unclean == false) {
1487  pe_err("Skipping action %s (%d) "
1488  "because it was scheduled for unclean node (bug?)",
1489  action->uuid, action->id);
1490  log_action(LOG_DEBUG, "Action for unclean node", action, false);
1491  return false;
1492 #endif
1493  }
1494  return true;
1495 }
1496 
1497 /* lowest to highest */
1498 static gint
1499 sort_action_id(gconstpointer a, gconstpointer b)
1500 {
1501  const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1502  const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1503 
1504  if (a == NULL) {
1505  return 1;
1506  }
1507  if (b == NULL) {
1508  return -1;
1509  }
1510 
1511  if (action_wrapper1->action->id > action_wrapper2->action->id) {
1512  return -1;
1513  }
1514 
1515  if (action_wrapper1->action->id < action_wrapper2->action->id) {
1516  return 1;
1517  }
1518  return 0;
1519 }
1520 
1532 static bool
1533 check_dump_input(pe_action_t *action, pe_action_wrapper_t *input)
1534 {
1535  int type = input->type;
1536 
1537  if (input->state == pe_link_dumped) {
1538  return true;
1539  }
1540 
1544 
1545  if (input->type == pe_order_none) {
1546  crm_trace("Ignoring %s (%d) input %s (%d): "
1547  "ordering disabled",
1548  action->uuid, action->id,
1549  input->action->uuid, input->action->id);
1550  return false;
1551 
1552  } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1553  && (type == pe_order_none)
1554  && !pcmk__str_eq(input->action->uuid, CRM_OP_PROBED, pcmk__str_casei)) {
1555  crm_trace("Ignoring %s (%d) input %s (%d): "
1556  "optional and input unrunnable",
1557  action->uuid, action->id,
1558  input->action->uuid, input->action->id);
1559  return false;
1560 
1561  } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1562  && pcmk_is_set(input->type, pe_order_one_or_more)) {
1563  crm_trace("Ignoring %s (%d) input %s (%d): "
1564  "one-or-more and input unrunnable",
1565  action->uuid, action->id,
1566  input->action->uuid, input->action->id);
1567  return false;
1568 
1569  } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1570  && pcmk_is_set(input->type, pe_order_stonith_stop)) {
1571  crm_trace("Ignoring %s (%d) input %s (%d): "
1572  "stonith stop but action is pseudo",
1573  action->uuid, action->id,
1574  input->action->uuid, input->action->id);
1575  return false;
1576 
1578  && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
1579  crm_trace("Ignoring %s (%d) input %s (%d): "
1580  "implies input migratable but input unrunnable",
1581  action->uuid, action->id,
1582  input->action->uuid, input->action->id);
1583  return false;
1584 
1587  crm_trace("Ignoring %s (%d) input %s (%d): "
1588  "only if input unmigratable but input unrunnable",
1589  action->uuid, action->id,
1590  input->action->uuid, input->action->id);
1591  return false;
1592 
1593  } else if ((input->type == pe_order_optional)
1595  && pcmk__ends_with(input->action->uuid, "_stop_0")) {
1596  crm_trace("Ignoring %s (%d) input %s (%d): "
1597  "optional but stop in migration",
1598  action->uuid, action->id,
1599  input->action->uuid, input->action->id);
1600  return false;
1601 
1602  } else if (input->type == pe_order_load) {
1603  pe_node_t *input_node = input->action->node;
1604 
1605  // load orderings are relevant only if actions are for same node
1606 
1607  if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
1608  pe_node_t *allocated = action->rsc->allocated_to;
1609 
1610  /* For load_stopped -> migrate_to orderings, we care about where it
1611  * has been allocated to, not where it will be executed.
1612  */
1613  if ((input_node == NULL) || (allocated == NULL)
1614  || (input_node->details != allocated->details)) {
1615  crm_trace("Ignoring %s (%d) input %s (%d): "
1616  "load ordering node mismatch %s vs %s",
1617  action->uuid, action->id,
1618  input->action->uuid, input->action->id,
1619  (allocated? allocated->details->uname : "<none>"),
1620  (input_node? input_node->details->uname : "<none>"));
1621  input->type = pe_order_none;
1622  return false;
1623  }
1624 
1625  } else if ((input_node == NULL) || (action->node == NULL)
1626  || (input_node->details != action->node->details)) {
1627  crm_trace("Ignoring %s (%d) input %s (%d): "
1628  "load ordering node mismatch %s vs %s",
1629  action->uuid, action->id,
1630  input->action->uuid, input->action->id,
1631  (action->node? action->node->details->uname : "<none>"),
1632  (input_node? input_node->details->uname : "<none>"));
1633  input->type = pe_order_none;
1634  return false;
1635 
1636  } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1637  crm_trace("Ignoring %s (%d) input %s (%d): "
1638  "load ordering input optional",
1639  action->uuid, action->id,
1640  input->action->uuid, input->action->id);
1641  input->type = pe_order_none;
1642  return false;
1643  }
1644 
1645  } else if (input->type == pe_order_anti_colocation) {
1646  if (input->action->node && action->node
1647  && (input->action->node->details != action->node->details)) {
1648  crm_trace("Ignoring %s (%d) input %s (%d): "
1649  "anti-colocation node mismatch %s vs %s",
1650  action->uuid, action->id,
1651  input->action->uuid, input->action->id,
1652  action->node->details->uname,
1653  input->action->node->details->uname);
1654  input->type = pe_order_none;
1655  return false;
1656 
1657  } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1658  crm_trace("Ignoring %s (%d) input %s (%d): "
1659  "anti-colocation input optional",
1660  action->uuid, action->id,
1661  input->action->uuid, input->action->id);
1662  input->type = pe_order_none;
1663  return false;
1664  }
1665 
1666  } else if (input->action->rsc
1667  && input->action->rsc != action->rsc
1668  && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
1669  && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
1670  && pcmk__ends_with(input->action->uuid, "_stop_0")
1671  && action->rsc && pe_rsc_is_clone(action->rsc)) {
1672  crm_warn("Ignoring requirement that %s complete before %s:"
1673  " unmanaged failed resources cannot prevent clone shutdown",
1674  input->action->uuid, action->uuid);
1675  return false;
1676 
1677  } else if (pcmk_is_set(input->action->flags, pe_action_optional)
1678  && !pcmk_any_flags_set(input->action->flags,
1680  && !should_dump_action(input->action)) {
1681  crm_trace("Ignoring %s (%d) input %s (%d): "
1682  "input optional",
1683  action->uuid, action->id,
1684  input->action->uuid, input->action->id);
1685  return false;
1686  }
1687 
1688  crm_trace("%s (%d) input %s (%d) @ %s should be dumped: %s, %s, %s, 0x%.6x",
1689  action->uuid, action->id,
1690  input->action->uuid, input->action->id,
1691  input->action->node? input->action->node->details->uname : "no node",
1692  pcmk_is_set(input->action->flags, pe_action_pseudo)? "pseudo" : "real",
1693  pcmk_is_set(input->action->flags, pe_action_runnable)? "runnable" : "unrunnable",
1694  pcmk_is_set(input->action->flags, pe_action_optional)? "optional" : "required",
1695  input->type);
1696  return true;
1697 }
1698 
1699 static bool
1700 graph_has_loop(pe_action_t *init_action, pe_action_t *action,
1701  pe_action_wrapper_t *input)
1702 {
1703  bool has_loop = false;
1704 
1705  if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
1706  crm_trace("Breaking tracking loop: %s@%s -> %s@%s (0x%.6x)",
1707  input->action->uuid,
1708  input->action->node? input->action->node->details->uname : "",
1709  action->uuid,
1710  action->node? action->node->details->uname : "",
1711  input->type);
1712  return false;
1713  }
1714 
1715  // Don't need to check inputs that won't be used
1716  if (!check_dump_input(action, input)) {
1717  return false;
1718  }
1719 
1720  if (input->action == init_action) {
1721  crm_debug("Input loop found in %s@%s ->...-> %s@%s",
1722  action->uuid,
1723  action->node? action->node->details->uname : "",
1724  init_action->uuid,
1725  init_action->node? init_action->node->details->uname : "");
1726  return true;
1727  }
1728 
1730 
1731  crm_trace("Checking inputs of action %s@%s input %s@%s (0x%.6x)"
1732  "for graph loop with %s@%s ",
1733  action->uuid,
1734  action->node? action->node->details->uname : "",
1735  input->action->uuid,
1736  input->action->node? input->action->node->details->uname : "",
1737  input->type,
1738  init_action->uuid,
1739  init_action->node? init_action->node->details->uname : "");
1740 
1741  // Recursively check input itself for loops
1742  for (GList *iter = input->action->actions_before;
1743  iter != NULL; iter = iter->next) {
1744 
1745  if (graph_has_loop(init_action, input->action,
1746  (pe_action_wrapper_t *) iter->data)) {
1747  // Recursive call already logged a debug message
1748  has_loop = true;
1749  goto done;
1750  }
1751  }
1752 
1753 done:
1755 
1756  if (!has_loop) {
1757  crm_trace("No input loop found in %s@%s -> %s@%s (0x%.6x)",
1758  input->action->uuid,
1759  input->action->node? input->action->node->details->uname : "",
1760  action->uuid,
1761  action->node? action->node->details->uname : "",
1762  input->type);
1763  }
1764  return has_loop;
1765 }
1766 
1767 bool
1769 {
1770  /* Prevent user-defined ordering constraints between resources
1771  * running in a guest node and the resource that defines that node.
1772  */
1773  if (!pcmk_is_set(input->type, pe_order_preserve)
1774  && action->rsc && action->rsc->fillers
1775  && input->action->rsc && input->action->node
1776  && input->action->node->details->remote_rsc
1777  && (input->action->node->details->remote_rsc->container == action->rsc)) {
1778  crm_warn("Invalid ordering constraint between %s and %s",
1779  input->action->rsc->id, action->rsc->id);
1780  return true;
1781  }
1782 
1783  /* If there's an order like
1784  * "rscB_stop node2"-> "load_stopped_node2" -> "rscA_migrate_to node1"
1785  *
1786  * then rscA is being migrated from node1 to node2, while rscB is being
1787  * migrated from node2 to node1. If there would be a graph loop,
1788  * break the order "load_stopped_node2" -> "rscA_migrate_to node1".
1789  */
1790  if ((input->type == pe_order_load) && action->rsc
1791  && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)
1792  && graph_has_loop(action, action, input)) {
1793  return true;
1794  }
1795 
1796  return false;
1797 }
1798 
1799 // Remove duplicate inputs (regardless of flags)
1800 static void
1801 deduplicate_inputs(pe_action_t *action)
1802 {
1803  GList *item = NULL;
1804  GList *next = NULL;
1805  pe_action_wrapper_t *last_input = NULL;
1806 
1807  action->actions_before = g_list_sort(action->actions_before,
1808  sort_action_id);
1809  for (item = action->actions_before; item != NULL; item = next) {
1810  pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1811 
1812  next = item->next;
1813  if (last_input && (input->action->id == last_input->action->id)) {
1814  crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1815  input->action->uuid, input->action->id,
1816  action->uuid, action->id);
1817 
1818  /* For the purposes of scheduling, the ordering flags no longer
1819  * matter, but crm_simulate looks at certain ones when creating a
1820  * dot graph. Combining the flags is sufficient for that purpose.
1821  */
1822  last_input->type |= input->type;
1823  if (input->state == pe_link_dumped) {
1824  last_input->state = pe_link_dumped;
1825  }
1826 
1827  free(item->data);
1828  action->actions_before = g_list_delete_link(action->actions_before,
1829  item);
1830  } else {
1831  last_input = input;
1832  input->state = pe_link_not_dumped;
1833  }
1834  }
1835 }
1836 
1852 void
1854 {
1855  GList *lpc = NULL;
1856  int synapse_priority = 0;
1857  xmlNode *syn = NULL;
1858  xmlNode *set = NULL;
1859  xmlNode *in = NULL;
1860  xmlNode *xml_action = NULL;
1861  pe_action_wrapper_t *input = NULL;
1862 
1863  /* If we haven't already, de-duplicate inputs -- even if we won't be dumping
1864  * the action, so that crm_simulate dot graphs don't have duplicates.
1865  */
1866  if (!pcmk_is_set(action->flags, pe_action_dedup)) {
1867  deduplicate_inputs(action);
1869  }
1870 
1871  if (should_dump_action(action) == FALSE) {
1872  return;
1873  }
1874 
1876 
1877  syn = create_xml_node(data_set->graph, "synapse");
1878  set = create_xml_node(syn, "action_set");
1879  in = create_xml_node(syn, "inputs");
1880 
1881  crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
1882  data_set->num_synapse++;
1883 
1884  if (action->rsc != NULL) {
1885  synapse_priority = action->rsc->priority;
1886  }
1887  if (action->priority > synapse_priority) {
1888  synapse_priority = action->priority;
1889  }
1890  if (synapse_priority > 0) {
1891  crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
1892  }
1893 
1894  xml_action = action2xml(action, FALSE, data_set);
1895  add_node_nocopy(set, crm_element_name(xml_action), xml_action);
1896 
1897  for (lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
1898  input = (pe_action_wrapper_t *) lpc->data;
1899  if (check_dump_input(action, input)) {
1900  xmlNode *input_xml = create_xml_node(in, "trigger");
1901 
1902  input->state = pe_link_dumped;
1903  xml_action = action2xml(input->action, TRUE, data_set);
1904  add_node_nocopy(input_xml, crm_element_name(xml_action), xml_action);
1905  }
1906  }
1907 }
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:131
enum pe_link_state state
Definition: pe_types.h:534
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
const char * task2text(enum action_tasks task)
Definition: common.c:406
#define RSC_STOP
Definition: crm.h:204
A dumping ground.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
#define CRMD_ACTION_MIGRATED
Definition: crm.h:174
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
pe_resource_t * rsc_lh
#define XML_CONFIG_ATTR_SHUTDOWN_LOCK
Definition: msg_xml.h:387
#define INFINITY
Definition: crm.h:99
#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:886
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:786
int runnable_before
Definition: pe_types.h:443
#define CRM_OP_FENCE
Definition: crm.h:145
#define XML_GRAPH_TAG_MAINTENANCE
Definition: msg_xml.h:330
void add_maintenance_update(pe_working_set_t *data_set)
pe_resource_t * container
Definition: pe_types.h:381
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
#define XML_ATTR_TYPE
Definition: msg_xml.h:132
GList * children
Definition: pe_types.h:378
resource_alloc_functions_t * cmds
Definition: pe_types.h:334
Internal tracking for transition graph creation.
Definition: pe_types.h:473
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:411
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:432
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:69
pe_resource_t * remote_rsc
Definition: pe_types.h:230
#define pe_rsc_unique
Definition: pe_types.h:254
#define pe_rsc_notify
Definition: pe_types.h:253
#define XML_TAG_ATTRS
Definition: msg_xml.h:205
resource_object_functions_t * fns
Definition: pe_types.h:333
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:2220
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:324
#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:326
#define XML_NODE_IS_MAINTENANCE
Definition: msg_xml.h:281
enum action_tasks text2task(const char *task)
Definition: common.c:354
GList * actions
Definition: pe_types.h:164
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:328
GList * rsc_cons_lhs
Definition: pe_types.h:357
enum crm_ais_msg_types type
Definition: cpg.c:48
#define RSC_START
Definition: crm.h:201
pe_action_t * action
Definition: pe_types.h:535
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:535
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:752
#define XML_GRAPH_TAG_DOWNED
Definition: msg_xml.h:329
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:221
#define pe__set_raw_action_flags(action_flags, action_name, flags_to_set)
Definition: internal.h:77
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:247
#define RSC_NOTIFY
Definition: crm.h:212
#define RSC_MIGRATE
Definition: crm.h:198
const char * action
Definition: pcmk_fence.c:30
GList * resources
Definition: pe_types.h:158
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:327
GList * nodes
Definition: pe_types.h:157
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:272
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:298
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:297
#define CRM_OP_LRM_REFRESH
Definition: crm.h:149
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:54
#define CRMD_ACTION_STOP
Definition: crm.h:179
#define CRM_OP_CLEAR_FAILCOUNT
Definition: crm.h:155
#define crm_warn(fmt, args...)
Definition: logging.h:351
#define CRMD_ACTION_RELOAD_AGENT
Definition: crm.h:172
pe_action_flags
Definition: pe_types.h:291
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:311
#define pe_rsc_failed
Definition: pe_types.h:267
pe_action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1854
#define crm_debug(fmt, args...)
Definition: logging.h:355
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:903
#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:129
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
char * task
Definition: pe_types.h:415
GList * actions_after
Definition: pe_types.h:449
#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:356
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:674
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:244
pe_node_t * node
Definition: pe_types.h:412
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:267
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1808
unsigned long long flags
Definition: pe_types.h:349
const char * uname
Definition: pe_types.h:209
GHashTable * pe_rsc_params(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:457
Wrappers for and extensions to libxml2.
Internal state tracking when creating graph.
Definition: pe_types.h:317
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696
#define PCMK__NELEM(a)
Definition: internal.h:38
#define pe__set_graph_flags(graph_flags, gr_action, flags_to_set)
Definition: internal.h:125
GList * actions
Definition: pe_types.h:360
pe_graph_flags
Definition: pe_types.h:283
void(* append_meta)(pe_resource_t *rsc, xmlNode *xml)
char * uuid
Definition: pe_types.h:416
#define XML_LRM_ATTR_ROUTER_NODE
Definition: msg_xml.h:305
#define XML_TAG_RSC_VER_ATTRS
Definition: msg_xml.h:206
void free_xml(xmlNode *child)
Definition: xml.c:823
#define PCMK__ENV_PHYSICAL_HOST
Definition: crm_internal.h:102
void update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
enum pe_obj_types variant
Definition: pe_types.h:331
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:2027
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:199
#define CRM_OP_SHUTDOWN
Definition: crm.h:144
const char * id
Definition: pe_types.h:208
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
#define CRM_OP_MAINTENANCE_NODES
Definition: crm.h:160
xmlNode * sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
Definition: xml.c:2758
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:300
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:482
void pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
#define XML_ATTR_UUID
Definition: msg_xml.h:152
#define XML_TAG_CIB
Definition: msg_xml.h:109
void log_action(unsigned int log_level, const char *pre_text, pe_action_t *action, gboolean details)
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:215
Cluster Configuration.
#define pe_rsc_reload
Definition: pe_types.h:263
#define PCMK__XA_MODE
Definition: crm_internal.h:69
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:295
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry, as meta-attribute name.
Definition: nvpair.c:814
char uname[MAX_NAME]
Definition: cpg.c:50
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:112
void graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
GList * running_on
Definition: pe_types.h:367
#define pe_rsc_block
Definition: pe_types.h:250
enum pe_action_flags flags
Definition: pe_types.h:420
gboolean maintenance
Definition: pe_types.h:222
#define CRM_OP_PROBED
Definition: crm.h:153
#define pe_rsc_maintenance
Definition: pe_types.h:276
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
Definition: xml.c:688
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:364
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:299
#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
#define ID(x)
Definition: msg_xml.h:456
#define pe_err(fmt...)
Definition: internal.h:22
#define CRM_OP_LRM_DELETE
Definition: crm.h:151
enum pe_ordering type
Definition: pe_types.h:533
#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:249
#define pe_rsc_orphan
Definition: pe_types.h:248
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1428
pe_ordering
Definition: pe_types.h:484
uint64_t flags
Definition: remote.c:149
GList * actions_before
Definition: pe_types.h:448
int required_runnable_before
Definition: pe_types.h:446
action_tasks
Definition: common.h:62
pe_resource_t * parent
Definition: pe_types.h:329
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:266
xmlNode * graph
Definition: pe_types.h:176
char * id
Definition: pe_types.h:322