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 
22 void update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set);
23 gboolean rsc_update_action(pe_action_t * first, pe_action_t * then, enum pe_ordering type);
24 
25 static enum pe_action_flags
get_action_flags(pe_action_t * action,pe_node_t * node)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)
49                 && pcmk_is_set(flags, pe_action_runnable)) {
50 
51                 pe__set_raw_action_flags(clone_flags, action->rsc->id,
52                                          pe_action_runnable);
53             }
54             flags = clone_flags;
55         }
56     }
57     return flags;
58 }
59 
60 static char *
convert_non_atomic_uuid(char * old_uuid,pe_resource_t * rsc,gboolean allow_notify,gboolean free_original)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 *
rsc_expand_action(pe_action_t * action)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,
163                          pcmk_is_set(rsc->flags, pe_rsc_notify));
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
graph_update_action(pe_action_t * first,pe_action_t * then,pe_node_t * node,enum pe_action_flags first_flags,enum pe_action_flags then_flags,pe_action_wrapper_t * order,pe_working_set_t * data_set)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 
186     if (pcmk_is_set(type, pe_order_implies_then_on_node)) {
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 
199         pe__clear_order_flags(type, pe_order_implies_then_on_node);
200         pe__set_order_flags(type, pe_order_implies_then);
201         node = first->node;
202     }
203 
204     pe__clear_raw_action_flags(first_flags, "first action update",
205                                pe_action_pseudo);
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)) {
216             pe__clear_action_flags(then, pe_action_optional);
217             pe__set_graph_flags(changed, first, pe_graph_updated_then);
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) {
227         enum pe_action_flags restart = (pe_action_optional | pe_action_runnable);
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 
240     if (type & pe_order_implies_first) {
241         processed = TRUE;
242         if (first->rsc) {
243             changed |= first->rsc->cmds->update_actions(first, then, node,
244                 first_flags, pe_action_optional, pe_order_implies_first,
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)) {
252                 pe__clear_action_flags(first, pe_action_runnable);
253                 pe__set_graph_flags(changed, first, pe_graph_updated_first);
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 
266     if (type & pe_order_promoted_implies_first) {
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,
271                 pe_order_promoted_implies_first, data_set);
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,
288                 first_flags, pe_action_runnable, pe_order_one_or_more,
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 
301                 pe__set_action_flags(then, pe_action_runnable);
302                 pe__set_graph_flags(changed, first, pe_graph_updated_then);
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);
321             type = pe_order_none;
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,
327                 first_flags, pe_action_runnable, pe_order_runnable_left,
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 
338     if (type & pe_order_runnable_left) {
339         processed = TRUE;
340         if (then->rsc) {
341             changed |= then->rsc->cmds->update_actions(first, then, node,
342                 first_flags, pe_action_runnable, pe_order_runnable_left,
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 
348             pe__clear_action_flags(then, pe_action_runnable);
349             pe__set_graph_flags(changed, first, pe_graph_updated_then);
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 
358     if (type & pe_order_implies_first_migratable) {
359         processed = TRUE;
360         if (then->rsc) {
361             changed |= then->rsc->cmds->update_actions(first, then, node,
362                 first_flags, pe_action_optional,
363                 pe_order_implies_first_migratable, data_set);
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,
376                 first_flags, pe_action_optional, pe_order_pseudo_left,
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,
403                 first_flags, pe_action_runnable, pe_order_asymmetrical,
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 
415     if ((first->flags & pe_action_runnable) && (type & pe_order_implies_then_printed)
416         && (first_flags & pe_action_optional) == 0) {
417         processed = TRUE;
418         crm_trace("%s implies %s printed", first->uuid, then->uuid);
419         pe__set_action_flags(then, pe_action_print_always);
420         // Don't bother marking 'then' as changed just for this
421     }
422 
423     if (pcmk_is_set(type, pe_order_implies_first_printed)
424         && !pcmk_is_set(then_flags, pe_action_optional)) {
425 
426         processed = TRUE;
427         crm_trace("%s implies %s printed", then->uuid, first->uuid);
428         pe__set_action_flags(first, pe_action_print_always);
429         // Don't bother marking 'first' as changed just for this
430     }
431 
432     if ((type & pe_order_implies_then
433          || type & pe_order_implies_first
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)) {
442             pe__clear_action_flags(then, pe_action_runnable);
443             pe__set_graph_flags(changed, first, pe_graph_updated_then);
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
mark_start_blocked(pe_resource_t * rsc,pe_resource_t * reason,pe_working_set_t * data_set)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
update_colo_start_chain(pe_action_t * action,pe_working_set_t * data_set)484 update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
485 {
486     GList *gIter = NULL;
487     pe_resource_t *rsc = NULL;
488 
489     if (!pcmk_is_set(action->flags, pe_action_runnable)
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
update_action(pe_action_t * then,pe_working_set_t * data_set)527 update_action(pe_action_t *then, pe_working_set_t *data_set)
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 
540     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
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         }
553         pe__clear_action_flags(then, pe_action_runnable);
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 
598         pe__clear_graph_flags(changed, then, pe_graph_updated_first);
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              */
606             pe__set_action_flags(other->action, pe_action_optional);
607             if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
608                 pe__clear_resource_flags(first->rsc, pe_rsc_reload);
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,
663                                 pe_graph_updated_then|pe_graph_disable);
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 
691     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
692         if (last_flags != then->flags) {
693             pe__set_graph_flags(changed, then, pe_graph_updated_then);
694         } else {
695             pe__clear_graph_flags(changed, then, pe_graph_updated_then);
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
shutdown_constraints(pe_node_t * node,pe_action_t * shutdown_op,pe_working_set_t * data_set)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,
747                                        pe_rsc_managed|pe_rsc_block)) {
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);
757         pe__clear_action_flags(action, pe_action_optional);
758         custom_action_order(action->rsc, NULL, action,
759                             NULL, strdup(CRM_OP_SHUTDOWN), shutdown_op,
760                             pe_order_optional | pe_order_runnable_left, data_set);
761     }
762 
763     return TRUE;
764 }
765 
766 /*!
767  * \internal
768  * \brief Order all actions appropriately relative to a fencing operation
769  *
770  * Ensure start operations of affected resources are ordered after fencing,
771  * imply stop and demote operations of affected resources by marking them as
772  * pseudo-actions, etc.
773  *
774  * \param[in]     stonith_op  Fencing operation
775  * \param[in,out] data_set    Working set of cluster
776  */
777 void
pcmk__order_vs_fence(pe_action_t * stonith_op,pe_working_set_t * data_set)778 pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
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 *
get_router_node(pe_action_t * action)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 
881 /*!
882  * \internal
883  * \brief Add an XML node tag for a specified ID
884  *
885  * \param[in]     id      Node UUID to add
886  * \param[in,out] xml     Parent XML tag to add to
887  */
888 static xmlNode*
add_node_to_xml_by_id(const char * id,xmlNode * xml)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 
899 /*!
900  * \internal
901  * \brief Add an XML node tag for a specified node
902  *
903  * \param[in]     node  Node to add
904  * \param[in,out] xml   XML to add node to
905  */
906 static void
add_node_to_xml(const pe_node_t * node,void * xml)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 
912 /*!
913  * \internal
914  * \brief Add XML with nodes that need an update of their maintenance state
915  *
916  * \param[in,out] xml       Parent XML tag to add to
917  * \param[in]     data_set  Working set for cluster
918  */
919 static int
add_maintenance_nodes(xmlNode * xml,const pe_working_set_t * data_set)920 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
921 {
922     GList *gIter = NULL;
923     xmlNode *maintenance =
924         xml?create_xml_node(xml, XML_GRAPH_TAG_MAINTENANCE):NULL;
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 
950 /*!
951  * \internal
952  * \brief Add pseudo action with nodes needing maintenance state update
953  *
954  * \param[in,out] data_set  Working set for cluster
955  */
956 void
add_maintenance_update(pe_working_set_t * data_set)957 add_maintenance_update(pe_working_set_t *data_set)
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");
963         action = get_pseudo_op(CRM_OP_MAINTENANCE_NODES, data_set);
964         pe__set_action_flags(action, pe_action_print_always);
965     }
966 }
967 
968 /*!
969  * \internal
970  * \brief Add XML with nodes that an action is expected to bring down
971  *
972  * If a specified action is expected to bring any nodes down, add an XML block
973  * with their UUIDs. When a node is lost, this allows the controller to
974  * determine whether it was expected.
975  *
976  * \param[in,out] xml       Parent XML tag to add to
977  * \param[in]     action    Action to check for downed nodes
978  * \param[in]     data_set  Working set for cluster
979  */
980 static void
add_downed_nodes(xmlNode * xml,const pe_action_t * action,const pe_working_set_t * data_set)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
should_lock_action(pe_action_t * action)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 *
action2xml(pe_action_t * action,gboolean as_input,pe_working_set_t * data_set)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,
1066                                      pcmk_is_set(action->flags, pe_action_pseudo)?
1067                                      XML_GRAPH_TAG_PSEUDO_EVENT :
1068                                      XML_GRAPH_TAG_CRM_EVENT);
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,
1109                                   XML_LRM_ATTR_INTERVAL_MS, 0,
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[] = {
1163             XML_AGENT_ATTR_CLASS,
1164             XML_AGENT_ATTR_PROVIDER,
1165             XML_ATTR_TYPE
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)) {
1172             crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
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);
1237     crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
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,
1250                                                       XML_RSC_ATTR_REMOTE_RA_ADDR);
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,
1256                                               XML_RSC_ATTR_REMOTE_RA_ADDR);
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) {
1346                 hash2metafield((gpointer)XML_RSC_ATTR_TARGET,
1347                                (gpointer)g_hash_table_lookup(action->rsc->meta, XML_RSC_ATTR_TARGET), (gpointer)args_xml);
1348                 hash2metafield((gpointer) PCMK__ENV_PHYSICAL_HOST,
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
should_dump_action(pe_action_t * action)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,
1442                                                         XML_LRM_ATTR_INTERVAL_MS);
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) ||
1453         pcmk__strcase_any_of(action->task, CRM_OP_FENCE, CRM_OP_SHUTDOWN, NULL)) {
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
sort_action_id(gconstpointer a,gconstpointer b)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 
1521 /*!
1522  * \internal
1523  * \brief Check whether an action input should be in the transition graph
1524  *
1525  * \param[in]     action  Action to check
1526  * \param[in,out] input   Action input to check
1527  *
1528  * \return true if input should be in graph, false otherwise
1529  * \note This function may not only check an input, but disable it under certian
1530  *       circumstances (load or anti-colocation orderings that are not needed).
1531  */
1532 static bool
check_dump_input(pe_action_t * action,pe_action_wrapper_t * input)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 
1541     pe__clear_order_flags(type, pe_order_implies_first_printed
1542                                 |pe_order_implies_then_printed
1543                                 |pe_order_optional);
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 
1577     } else if (pcmk_is_set(input->type, pe_order_implies_first_migratable)
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 
1585     } else if (pcmk_is_set(input->type, pe_order_apply_first_non_migratable)
1586                && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)) {
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)
1594                && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)
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,
1679                                       pe_action_print_always|pe_action_dumped)
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
graph_has_loop(pe_action_t * init_action,pe_action_t * action,pe_action_wrapper_t * input)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 
1729     pe__set_action_flags(input->action, pe_action_tracking);
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:
1754     pe__clear_action_flags(input->action, pe_action_tracking);
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
pcmk__ordering_is_invalid(pe_action_t * action,pe_action_wrapper_t * input)1768 pcmk__ordering_is_invalid(pe_action_t *action, pe_action_wrapper_t *input)
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
deduplicate_inputs(pe_action_t * action)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 
1837 /*!
1838  * \internal
1839  * \brief Add an action to the transition graph XML if appropriate
1840  *
1841  * \param[in] action    Action to possibly add
1842  * \param[in] data_set  Cluster working set
1843  *
1844  * \note This will de-duplicate the action inputs, meaning that the
1845  *       pe_action_wrapper_t:type flags can no longer be relied on to retain
1846  *       their original settings. That means this MUST be called after stage7()
1847  *       is complete, and nothing after this should rely on those type flags.
1848  *       (For example, some code looks for type equal to some flag rather than
1849  *       whether the flag is set, and some code looks for particular
1850  *       combinations of flags -- such code must be done before stage8().)
1851  */
1852 void
graph_element_from_action(pe_action_t * action,pe_working_set_t * data_set)1853 graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
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);
1868         pe__set_action_flags(action, pe_action_dedup);
1869     }
1870 
1871     if (should_dump_action(action) == FALSE) {
1872         return;
1873     }
1874 
1875     pe__set_action_flags(action, pe_action_dumped);
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 }
1908