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