This source file includes following definitions.
- get_action_flags
- convert_non_atomic_uuid
- rsc_expand_action
- graph_update_action
- mark_start_blocked
- update_colo_start_chain
- update_action
- shutdown_constraints
- pcmk__order_vs_fence
- get_router_node
- add_node_to_xml_by_id
- add_node_to_xml
- add_maintenance_nodes
- add_maintenance_update
- add_downed_nodes
- should_lock_action
- action2xml
- should_dump_action
- sort_action_id
- check_dump_input
- graph_has_loop
- pcmk__ordering_is_invalid
- deduplicate_inputs
- graph_element_from_action
1
2
3
4
5
6
7
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
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
36 enum pe_action_flags clone_flags = action->rsc->cmds->action_flags(action, node);
37
38
39
40
41
42
43
44
45
46
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 *
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;
77
78 } else if (rsc->variant < pe_group) {
79 goto done;
80 }
81
82 CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval_ms));
83 if (interval_ms > 0) {
84 goto done;
85 }
86
87 task = text2task(raw_task);
88 switch (task) {
89 case stop_rsc:
90 case start_rsc:
91 case action_notify:
92 case action_promote:
93 case action_demote:
94 break;
95 case stopped_rsc:
96 case started_rsc:
97 case action_notified:
98 case action_promoted:
99 case action_demoted:
100 task--;
101 break;
102 case monitor_rsc:
103 case shutdown_crm:
104 case stonith_node:
105 task = no_action;
106 break;
107 default:
108 crm_err("Unknown action: %s", raw_task);
109 task = no_action;
110 break;
111 }
112
113 if (task != no_action) {
114 if (pcmk_is_set(rsc->flags, pe_rsc_notify) && allow_notify) {
115 uuid = pcmk__notify_key(rid, "confirmed-post", task2text(task + 1));
116
117 } else {
118 uuid = pcmk__op_key(rid, task2text(task + 1), 0);
119 }
120 pe_rsc_trace(rsc, "Converted %s -> %s", old_uuid, uuid);
121 }
122
123 done:
124 if (uuid == NULL) {
125 uuid = strdup(old_uuid);
126 }
127
128 if (free_original) {
129 free(old_uuid);
130 }
131
132 free(raw_task);
133 free(rid);
134 return uuid;
135 }
136
137 static pe_action_t *
138 rsc_expand_action(pe_action_t * action)
139 {
140 gboolean notify = FALSE;
141 pe_action_t *result = action;
142 pe_resource_t *rsc = action->rsc;
143
144 if (rsc == NULL) {
145 return action;
146 }
147
148 if ((rsc->parent == NULL)
149 || (pe_rsc_is_clone(rsc) && (rsc->parent->variant == pe_container))) {
150
151
152
153 notify = pcmk_is_set(rsc->flags, pe_rsc_notify);
154 }
155
156 if (rsc->variant >= pe_group) {
157
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
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
185
186 if (pcmk_is_set(type, pe_order_implies_then_on_node)) {
187
188
189
190
191
192
193
194
195
196
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 if (update_action_flags(then, pe_action_optional | pe_action_clear, __func__, __LINE__)) {
216 pe__set_graph_flags(changed, first, pe_graph_updated_then);
217 }
218 }
219 if (changed) {
220 pe_rsc_trace(then->rsc, "implies right: %s then %s: changed", first->uuid, then->uuid);
221 } else {
222 crm_trace("implies right: %s then %s %p", first->uuid, then->uuid, then->rsc);
223 }
224 }
225
226 if ((type & pe_order_restart) && then->rsc) {
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 (update_action_flags(first, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
252 pe__set_graph_flags(changed, first, pe_graph_updated_first);
253 }
254 }
255
256 if (changed) {
257 pe_rsc_trace(then->rsc, "implies left: %s then %s: changed", first->uuid, then->uuid);
258 } else {
259 crm_trace("implies left: %s (%d) then %s (%d)",
260 first->uuid, pcmk_is_set(first_flags, pe_action_optional),
261 then->uuid, pcmk_is_set(then_flags, pe_action_optional));
262 }
263 }
264
265 if (type & pe_order_implies_first_master) {
266 processed = TRUE;
267 if (then->rsc) {
268 changed |= then->rsc->cmds->update_actions(first, then, node,
269 first_flags & pe_action_optional, pe_action_optional,
270 pe_order_implies_first_master, data_set);
271 }
272
273 if (changed) {
274 pe_rsc_trace(then->rsc,
275 "implies left when right rsc is Master role: %s then %s: changed",
276 first->uuid, then->uuid);
277 } else {
278 crm_trace("implies left when right rsc is Master role: %s then %s", first->uuid,
279 then->uuid);
280 }
281 }
282
283 if (type & pe_order_one_or_more) {
284 processed = TRUE;
285 if (then->rsc) {
286 changed |= then->rsc->cmds->update_actions(first, then, node,
287 first_flags, pe_action_runnable, pe_order_one_or_more,
288 data_set);
289
290 } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
291
292
293 then->runnable_before++;
294
295
296
297 if (then->runnable_before >= then->required_runnable_before) {
298 if (update_action_flags(then, pe_action_runnable, __func__, __LINE__)) {
299 pe__set_graph_flags(changed, first, pe_graph_updated_then);
300 }
301 }
302 }
303 if (changed) {
304 pe_rsc_trace(then->rsc, "runnable_one_or_more: %s then %s: changed", first->uuid,
305 then->uuid);
306 } else {
307 crm_trace("runnable_one_or_more: %s then %s", first->uuid, then->uuid);
308 }
309 }
310
311 if (then->rsc && pcmk_is_set(type, pe_order_probe)) {
312 processed = TRUE;
313
314 if (!pcmk_is_set(first_flags, pe_action_runnable)
315 && (first->rsc->running_on != NULL)) {
316
317 pe_rsc_trace(then->rsc, "Ignoring %s then %s - %s is about to be stopped",
318 first->uuid, then->uuid, first->rsc->id);
319 type = pe_order_none;
320 order->type = pe_order_none;
321
322 } else {
323 pe_rsc_trace(then->rsc, "Enforcing %s then %s", first->uuid, then->uuid);
324 changed |= then->rsc->cmds->update_actions(first, then, node,
325 first_flags, pe_action_runnable, pe_order_runnable_left,
326 data_set);
327 }
328
329 if (changed) {
330 pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
331 } else {
332 crm_trace("runnable: %s then %s", first->uuid, then->uuid);
333 }
334 }
335
336 if (type & pe_order_runnable_left) {
337 processed = TRUE;
338 if (then->rsc) {
339 changed |= then->rsc->cmds->update_actions(first, then, node,
340 first_flags, pe_action_runnable, pe_order_runnable_left,
341 data_set);
342
343 } else if (!pcmk_is_set(first_flags, pe_action_runnable)) {
344 pe_rsc_trace(then->rsc, "then unrunnable: %s then %s", first->uuid, then->uuid);
345 if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
346 pe__set_graph_flags(changed, first, pe_graph_updated_then);
347 }
348 }
349 if (changed) {
350 pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
351 } else {
352 crm_trace("runnable: %s then %s", first->uuid, then->uuid);
353 }
354 }
355
356 if (type & pe_order_implies_first_migratable) {
357 processed = TRUE;
358 if (then->rsc) {
359 changed |= then->rsc->cmds->update_actions(first, then, node,
360 first_flags, pe_action_optional,
361 pe_order_implies_first_migratable, data_set);
362 }
363 if (changed) {
364 pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
365 } else {
366 crm_trace("optional: %s then %s", first->uuid, then->uuid);
367 }
368 }
369
370 if (type & pe_order_pseudo_left) {
371 processed = TRUE;
372 if (then->rsc) {
373 changed |= then->rsc->cmds->update_actions(first, then, node,
374 first_flags, pe_action_optional, pe_order_pseudo_left,
375 data_set);
376 }
377 if (changed) {
378 pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
379 } else {
380 crm_trace("optional: %s then %s", first->uuid, then->uuid);
381 }
382 }
383
384 if (type & pe_order_optional) {
385 processed = TRUE;
386 if (then->rsc) {
387 changed |= then->rsc->cmds->update_actions(first, then, node,
388 first_flags, pe_action_runnable, pe_order_optional, data_set);
389 }
390 if (changed) {
391 pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
392 } else {
393 crm_trace("optional: %s then %s", first->uuid, then->uuid);
394 }
395 }
396
397 if (type & pe_order_asymmetrical) {
398 processed = TRUE;
399 if (then->rsc) {
400 changed |= then->rsc->cmds->update_actions(first, then, node,
401 first_flags, pe_action_runnable, pe_order_asymmetrical,
402 data_set);
403 }
404
405 if (changed) {
406 pe_rsc_trace(then->rsc, "asymmetrical: %s then %s: changed", first->uuid, then->uuid);
407 } else {
408 crm_trace("asymmetrical: %s then %s", first->uuid, then->uuid);
409 }
410
411 }
412
413 if ((first->flags & pe_action_runnable) && (type & pe_order_implies_then_printed)
414 && (first_flags & pe_action_optional) == 0) {
415 processed = TRUE;
416 crm_trace("%s implies %s printed", first->uuid, then->uuid);
417 update_action_flags(then, pe_action_print_always, __func__, __LINE__);
418 }
419
420 if (pcmk_is_set(type, pe_order_implies_first_printed)
421 && !pcmk_is_set(then_flags, pe_action_optional)) {
422
423 processed = TRUE;
424 crm_trace("%s implies %s printed", then->uuid, first->uuid);
425 update_action_flags(first, pe_action_print_always, __func__, __LINE__);
426 }
427
428 if ((type & pe_order_implies_then
429 || type & pe_order_implies_first
430 || type & pe_order_restart)
431 && first->rsc
432 && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)
433 && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
434 && pcmk_is_set(first->rsc->flags, pe_rsc_block)
435 && !pcmk_is_set(first->flags, pe_action_runnable)) {
436
437 if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
438 pe__set_graph_flags(changed, first, pe_graph_updated_then);
439 }
440
441 if (changed) {
442 pe_rsc_trace(then->rsc, "unmanaged left: %s then %s: changed", first->uuid, then->uuid);
443 } else {
444 crm_trace("unmanaged left: %s then %s", first->uuid, then->uuid);
445 }
446 }
447
448 if (processed == FALSE) {
449 crm_trace("Constraint 0x%.6x not applicable", type);
450 }
451
452 return changed;
453 }
454
455 static void
456 mark_start_blocked(pe_resource_t *rsc, pe_resource_t *reason,
457 pe_working_set_t *data_set)
458 {
459 GListPtr gIter = rsc->actions;
460 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
461
462 for (; gIter != NULL; gIter = gIter->next) {
463 pe_action_t *action = (pe_action_t *) gIter->data;
464
465 if (!pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
466 continue;
467 }
468 if (pcmk_is_set(action->flags, pe_action_runnable)) {
469 pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
470 reason_text, pe_action_runnable, FALSE);
471 update_colo_start_chain(action, data_set);
472 update_action(action, data_set);
473 }
474 }
475 free(reason_text);
476 }
477
478 void
479 update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
480 {
481 GListPtr gIter = NULL;
482 pe_resource_t *rsc = NULL;
483
484 if (!pcmk_is_set(action->flags, pe_action_runnable)
485 && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
486
487 rsc = uber_parent(action->rsc);
488 if (rsc->parent) {
489
490
491
492
493
494 rsc = rsc->parent;
495 }
496 }
497
498 if (rsc == NULL || rsc->rsc_cons_lhs == NULL) {
499 return;
500 }
501
502
503
504 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
505 pe_resource_t *child = (pe_resource_t *)gIter->data;
506 pe_action_t *start = find_first_action(child->actions, NULL, RSC_START, NULL);
507 if ((start == NULL) || pcmk_is_set(start->flags, pe_action_runnable)) {
508 return;
509 }
510 }
511
512 for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
513 rsc_colocation_t *colocate_with = (rsc_colocation_t *)gIter->data;
514 if (colocate_with->score == INFINITY) {
515 mark_start_blocked(colocate_with->rsc_lh, action->rsc, data_set);
516 }
517 }
518 }
519
520 gboolean
521 update_action(pe_action_t *then, pe_working_set_t *data_set)
522 {
523 GListPtr lpc = NULL;
524 enum pe_graph_flags changed = pe_graph_none;
525 int last_flags = then->flags;
526
527 crm_trace("Processing %s (%s %s %s)",
528 then->uuid,
529 pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
530 pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
531 pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
532 : (then->node? then->node->details->uname : ""));
533
534 if (pcmk_is_set(then->flags, pe_action_requires_any)) {
535
536
537
538
539 then->runnable_before = 0;
540
541
542
543
544 if (then->required_runnable_before == 0) {
545 then->required_runnable_before = 1;
546 }
547 pe__clear_action_flags(then, pe_action_runnable);
548
549
550
551
552
553
554
555 }
556
557 for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
558 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
559 pe_action_t *first = other->action;
560
561 pe_node_t *then_node = then->node;
562 pe_node_t *first_node = first->node;
563
564 enum pe_action_flags then_flags = 0;
565 enum pe_action_flags first_flags = 0;
566
567 if (first->rsc && first->rsc->variant == pe_group && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
568 first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
569 if (first_node) {
570 crm_trace("First: Found node %s for %s", first_node->details->uname, first->uuid);
571 }
572 }
573
574 if (then->rsc && then->rsc->variant == pe_group && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
575 then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
576 if (then_node) {
577 crm_trace("Then: Found node %s for %s", then_node->details->uname, then->uuid);
578 }
579 }
580
581 if (pcmk_is_set(other->type, pe_order_same_node)
582 && (first_node != NULL) && (then_node != NULL)
583 && (first_node->details != then_node->details)) {
584
585 crm_trace("Disabled constraint %s on %s -> %s on %s",
586 other->action->uuid, first_node->details->uname,
587 then->uuid, then_node->details->uname);
588 other->type = pe_order_none;
589 continue;
590 }
591
592 pe__clear_graph_flags(changed, then, pe_graph_updated_first);
593
594 if (first->rsc && pcmk_is_set(other->type, pe_order_then_cancels_first)
595 && !pcmk_is_set(then->flags, pe_action_optional)) {
596
597
598
599
600 pe__set_action_flags(other->action, pe_action_optional);
601 if (!strcmp(first->task, CRMD_ACTION_RELOAD)) {
602 pe__clear_resource_flags(first->rsc, pe_rsc_reload);
603 }
604 }
605
606 if (first->rsc && then->rsc && (first->rsc != then->rsc)
607 && (is_parent(then->rsc, first->rsc) == FALSE)) {
608 first = rsc_expand_action(first);
609 }
610 if (first != other->action) {
611 crm_trace("Ordering %s after %s instead of %s", then->uuid, first->uuid,
612 other->action->uuid);
613 }
614
615 first_flags = get_action_flags(first, then_node);
616 then_flags = get_action_flags(then, first_node);
617
618 crm_trace("Checking %s (%s %s %s) against %s (%s %s %s) filter=0x%.6x type=0x%.6x",
619 then->uuid,
620 pcmk_is_set(then_flags, pe_action_optional)? "optional" : "required",
621 pcmk_is_set(then_flags, pe_action_runnable)? "runnable" : "unrunnable",
622 pcmk_is_set(then_flags, pe_action_pseudo)? "pseudo"
623 : (then->node? then->node->details->uname : ""),
624 first->uuid,
625 pcmk_is_set(first_flags, pe_action_optional)? "optional" : "required",
626 pcmk_is_set(first_flags, pe_action_runnable)? "runnable" : "unrunnable",
627 pcmk_is_set(first_flags, pe_action_pseudo)? "pseudo"
628 : (first->node? first->node->details->uname : ""),
629 first_flags, other->type);
630
631 if (first == other->action) {
632
633
634
635
636
637
638
639
640
641
642
643
644
645 pe_node_t *node = then->node;
646 changed |= graph_update_action(first, then, node, first_flags,
647 then_flags, other, data_set);
648
649
650
651
652 } else if (order_actions(first, then, other->type)) {
653
654
655
656 pe__set_graph_flags(changed, then,
657 pe_graph_updated_then|pe_graph_disable);
658 }
659
660 if (changed & pe_graph_disable) {
661 crm_trace("Disabled constraint %s -> %s in favor of %s -> %s",
662 other->action->uuid, then->uuid, first->uuid, then->uuid);
663 pe__clear_graph_flags(changed, then, pe_graph_disable);
664 other->type = pe_order_none;
665 }
666
667 if (changed & pe_graph_updated_first) {
668 GListPtr lpc2 = NULL;
669
670 crm_trace("Updated %s (first %s %s %s), processing dependents ",
671 first->uuid,
672 pcmk_is_set(first->flags, pe_action_optional)? "optional" : "required",
673 pcmk_is_set(first->flags, pe_action_runnable)? "runnable" : "unrunnable",
674 pcmk_is_set(first->flags, pe_action_pseudo)? "pseudo"
675 : (first->node? first->node->details->uname : ""));
676 for (lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) {
677 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
678
679 update_action(other->action, data_set);
680 }
681 update_action(first, data_set);
682 }
683 }
684
685 if (pcmk_is_set(then->flags, pe_action_requires_any)) {
686 if (last_flags != then->flags) {
687 pe__set_graph_flags(changed, then, pe_graph_updated_then);
688 } else {
689 pe__clear_graph_flags(changed, then, pe_graph_updated_then);
690 }
691 }
692
693 if (changed & pe_graph_updated_then) {
694 crm_trace("Updated %s (then %s %s %s), processing dependents ",
695 then->uuid,
696 pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
697 pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
698 pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
699 : (then->node? then->node->details-> uname : ""));
700
701 if (pcmk_is_set(last_flags, pe_action_runnable)
702 && !pcmk_is_set(then->flags, pe_action_runnable)) {
703 update_colo_start_chain(then, data_set);
704 }
705 update_action(then, data_set);
706 for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
707 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
708
709 update_action(other->action, data_set);
710 }
711 }
712
713 return FALSE;
714 }
715
716 gboolean
717 shutdown_constraints(pe_node_t * node, pe_action_t * shutdown_op, pe_working_set_t * data_set)
718 {
719
720
721
722 GListPtr lpc = NULL;
723
724 for (lpc = data_set->actions; lpc != NULL; lpc = lpc->next) {
725 pe_action_t *action = (pe_action_t *) lpc->data;
726
727 if (action->rsc == NULL || action->node == NULL) {
728 continue;
729 } else if (action->node->details != node->details) {
730 continue;
731 } else if (pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)) {
732 pe_rsc_trace(action->rsc, "Skipping %s: maintenance mode", action->uuid);
733 continue;
734 } else if (node->details->maintenance) {
735 pe_rsc_trace(action->rsc, "Skipping %s: node %s is in maintenance mode",
736 action->uuid, node->details->uname);
737 continue;
738 } else if (!pcmk__str_eq(action->task, RSC_STOP, pcmk__str_casei)) {
739 continue;
740 } else if (!pcmk_any_flags_set(action->rsc->flags,
741 pe_rsc_managed|pe_rsc_block)) {
742
743
744
745 pe_rsc_trace(action->rsc, "Skipping %s: unmanaged", action->uuid);
746 continue;
747 }
748
749 pe_rsc_trace(action->rsc, "Ordering %s before shutdown on %s", action->uuid,
750 node->details->uname);
751 pe__clear_action_flags(action, pe_action_optional);
752 custom_action_order(action->rsc, NULL, action,
753 NULL, strdup(CRM_OP_SHUTDOWN), shutdown_op,
754 pe_order_optional | pe_order_runnable_left, data_set);
755 }
756
757 return TRUE;
758 }
759
760
761
762
763
764
765
766
767
768
769
770
771 void
772 pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
773 {
774 CRM_CHECK(stonith_op && data_set, return);
775 for (GList *r = data_set->resources; r != NULL; r = r->next) {
776 rsc_stonith_ordering((pe_resource_t *) r->data, stonith_op, data_set);
777 }
778 }
779
780 static pe_node_t *
781 get_router_node(pe_action_t *action)
782 {
783 pe_node_t *began_on = NULL;
784 pe_node_t *ended_on = NULL;
785 pe_node_t *router_node = NULL;
786 bool partial_migration = FALSE;
787 const char *task = action->task;
788
789 if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)
790 || !pe__is_guest_or_remote_node(action->node)) {
791 return NULL;
792 }
793
794 CRM_ASSERT(action->node->details->remote_rsc != NULL);
795
796 began_on = pe__current_node(action->node->details->remote_rsc);
797 ended_on = action->node->details->remote_rsc->allocated_to;
798 if (action->node->details->remote_rsc
799 && (action->node->details->remote_rsc->container == NULL)
800 && action->node->details->remote_rsc->partial_migration_target) {
801 partial_migration = TRUE;
802 }
803
804
805
806 if (!began_on || !ended_on) {
807
808 return began_on ? began_on : ended_on;
809 } else if (began_on->details == ended_on->details) {
810
811 return began_on;
812 }
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836 if (pcmk__str_eq(task, "notify", pcmk__str_casei)) {
837 task = g_hash_table_lookup(action->meta, "notify_operation");
838 }
839
840
841 if (pcmk__strcase_any_of(task, "stop", "demote", "migrate_from", "migrate_to",
842 NULL) && !partial_migration) {
843 router_node = began_on;
844
845
846 } else {
847 router_node = ended_on;
848 }
849 return router_node;
850 }
851
852
853
854
855
856
857
858
859 static xmlNode*
860 add_node_to_xml_by_id(const char *id, xmlNode *xml)
861 {
862 xmlNode *node_xml;
863
864 node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
865 crm_xml_add(node_xml, XML_ATTR_UUID, id);
866
867 return node_xml;
868 }
869
870
871
872
873
874
875
876
877 static void
878 add_node_to_xml(const pe_node_t *node, void *xml)
879 {
880 add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
881 }
882
883
884
885
886
887
888
889
890 static int
891 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
892 {
893 GListPtr gIter = NULL;
894 xmlNode *maintenance =
895 xml?create_xml_node(xml, XML_GRAPH_TAG_MAINTENANCE):NULL;
896 int count = 0;
897
898 for (gIter = data_set->nodes; gIter != NULL;
899 gIter = gIter->next) {
900 pe_node_t *node = (pe_node_t *) gIter->data;
901 struct pe_node_shared_s *details = node->details;
902
903 if (!pe__is_guest_or_remote_node(node)) {
904 continue;
905 }
906
907 if (details->maintenance != details->remote_maintenance) {
908 if (maintenance) {
909 crm_xml_add(
910 add_node_to_xml_by_id(node->details->id, maintenance),
911 XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
912 }
913 count++;
914 }
915 }
916 crm_trace("%s %d nodes to adjust maintenance-mode "
917 "to transition", maintenance?"Added":"Counted", count);
918 return count;
919 }
920
921
922
923
924
925
926
927 void
928 add_maintenance_update(pe_working_set_t *data_set)
929 {
930 pe_action_t *action = NULL;
931
932 if (add_maintenance_nodes(NULL, data_set)) {
933 crm_trace("adding maintenance state update pseudo action");
934 action = get_pseudo_op(CRM_OP_MAINTENANCE_NODES, data_set);
935 pe__set_action_flags(action, pe_action_print_always);
936 }
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951 static void
952 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
953 const pe_working_set_t *data_set)
954 {
955 CRM_CHECK(xml && action && action->node && data_set, return);
956
957 if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
958
959
960 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
961 add_node_to_xml_by_id(action->node->details->id, downed);
962
963 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
964
965
966 const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
967
968 if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
969 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
970 add_node_to_xml_by_id(action->node->details->id, downed);
971 pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
972 }
973
974 } else if (action->rsc && action->rsc->is_remote_node
975 && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
976
977
978
979
980 GListPtr iter;
981 pe_action_t *input;
982 gboolean migrating = FALSE;
983
984 for (iter = action->actions_before; iter != NULL; iter = iter->next) {
985 input = ((pe_action_wrapper_t *) iter->data)->action;
986 if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
987 && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
988 migrating = TRUE;
989 break;
990 }
991 }
992 if (!migrating) {
993 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
994 add_node_to_xml_by_id(action->rsc->id, downed);
995 }
996 }
997 }
998
999 static bool
1000 should_lock_action(pe_action_t *action)
1001 {
1002
1003 if ((action->rsc->lock_node == NULL) || (action->node == NULL)
1004 || (action->node->details != action->rsc->lock_node->details)) {
1005 return false;
1006 }
1007
1008
1009
1010
1011 if (action->node->details->shutdown && action->task
1012 && strcmp(action->task, RSC_STOP)) {
1013 return false;
1014 }
1015
1016 return true;
1017 }
1018
1019 static xmlNode *
1020 action2xml(pe_action_t * action, gboolean as_input, pe_working_set_t *data_set)
1021 {
1022 gboolean needs_node_info = TRUE;
1023 gboolean needs_maintenance_info = FALSE;
1024 xmlNode *action_xml = NULL;
1025 xmlNode *args_xml = NULL;
1026 #if ENABLE_VERSIONED_ATTRS
1027 pe_rsc_action_details_t *rsc_details = NULL;
1028 #endif
1029
1030 if (action == NULL) {
1031 return NULL;
1032 }
1033
1034 if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1035
1036 action_xml = create_xml_node(NULL,
1037 pcmk_is_set(action->flags, pe_action_pseudo)?
1038 XML_GRAPH_TAG_PSEUDO_EVENT :
1039 XML_GRAPH_TAG_CRM_EVENT);
1040
1041 } else if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1042 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1043
1044 } else if (pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
1045 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1046
1047 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_REFRESH, pcmk__str_casei)) {
1048 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1049
1050 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
1051
1052 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1053 crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
1054
1055
1056
1057
1058 } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
1059 if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
1060 needs_maintenance_info = TRUE;
1061 }
1062 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
1063 needs_node_info = FALSE;
1064
1065 } else {
1066 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
1067
1068 #if ENABLE_VERSIONED_ATTRS
1069 rsc_details = pe_rsc_action_details(action);
1070 #endif
1071 }
1072
1073 crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
1074 crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
1075 if (action->rsc != NULL && action->rsc->clone_name != NULL) {
1076 char *clone_key = NULL;
1077 guint interval_ms;
1078
1079 if (pcmk__guint_from_hash(action->meta,
1080 XML_LRM_ATTR_INTERVAL_MS, 0,
1081 &interval_ms) != pcmk_rc_ok) {
1082 interval_ms = 0;
1083 }
1084
1085 if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_casei)) {
1086 const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
1087 const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1088
1089 CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid));
1090 CRM_CHECK(n_task != NULL,
1091 crm_err("No notify operation value found for %s", action->uuid));
1092 clone_key = pcmk__notify_key(action->rsc->clone_name,
1093 n_type, n_task);
1094
1095 } else if(action->cancel_task) {
1096 clone_key = pcmk__op_key(action->rsc->clone_name,
1097 action->cancel_task, interval_ms);
1098 } else {
1099 clone_key = pcmk__op_key(action->rsc->clone_name,
1100 action->task, interval_ms);
1101 }
1102
1103 CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid));
1104 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
1105 crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
1106 free(clone_key);
1107
1108 } else {
1109 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
1110 }
1111
1112 if (needs_node_info && action->node != NULL) {
1113 pe_node_t *router_node = get_router_node(action);
1114
1115 crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
1116 crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
1117 if (router_node) {
1118 crm_xml_add(action_xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
1119 }
1120
1121 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET), strdup(action->node->details->uname));
1122 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID), strdup(action->node->details->id));
1123 }
1124
1125
1126 if (as_input) {
1127 return action_xml;
1128 }
1129
1130 if (action->rsc && !pcmk_is_set(action->flags, pe_action_pseudo)) {
1131 int lpc = 0;
1132 xmlNode *rsc_xml = NULL;
1133 const char *attr_list[] = {
1134 XML_AGENT_ATTR_CLASS,
1135 XML_AGENT_ATTR_PROVIDER,
1136 XML_ATTR_TYPE
1137 };
1138
1139
1140
1141
1142 if (should_lock_action(action)) {
1143 crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
1144 (long long) action->rsc->lock_time);
1145 }
1146
1147
1148
1149 rsc_xml = create_xml_node(action_xml,
1150 crm_element_name(action->rsc->xml));
1151 if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
1152 && action->rsc->clone_name) {
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164 crm_debug("Using orphan clone name %s instead of %s", action->rsc->id,
1165 action->rsc->clone_name);
1166 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
1167 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1168
1169 } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
1170 const char *xml_id = ID(action->rsc->xml);
1171
1172 crm_debug("Using anonymous clone name %s for %s (aka. %s)", xml_id, action->rsc->id,
1173 action->rsc->clone_name);
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
1189 if (action->rsc->clone_name && !pcmk__str_eq(xml_id, action->rsc->clone_name, pcmk__str_casei)) {
1190 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
1191 } else {
1192 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1193 }
1194
1195 } else {
1196 CRM_ASSERT(action->rsc->clone_name == NULL);
1197 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
1198 }
1199
1200 for (lpc = 0; lpc < DIMOF(attr_list); lpc++) {
1201 crm_xml_add(rsc_xml, attr_list[lpc],
1202 g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
1203 }
1204 }
1205
1206
1207 args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
1208 crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
1209
1210 g_hash_table_foreach(action->extra, hash2field, args_xml);
1211 if (action->rsc != NULL && action->node) {
1212 GHashTable *p = crm_str_table_new();
1213
1214 get_rsc_attributes(p, action->rsc, action->node, data_set);
1215 g_hash_table_foreach(p, hash2smartfield, args_xml);
1216 g_hash_table_destroy(p);
1217
1218 #if ENABLE_VERSIONED_ATTRS
1219 {
1220 xmlNode *versioned_parameters = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1221
1222 pe_get_versioned_attributes(versioned_parameters, action->rsc,
1223 action->node, data_set);
1224 if (xml_has_children(versioned_parameters)) {
1225 add_node_copy(action_xml, versioned_parameters);
1226 }
1227 free_xml(versioned_parameters);
1228 }
1229 #endif
1230
1231 } else if(action->rsc && action->rsc->variant <= pe_native) {
1232 g_hash_table_foreach(action->rsc->parameters, hash2smartfield, args_xml);
1233
1234 #if ENABLE_VERSIONED_ATTRS
1235 if (xml_has_children(action->rsc->versioned_parameters)) {
1236 add_node_copy(action_xml, action->rsc->versioned_parameters);
1237 }
1238 #endif
1239 }
1240
1241 #if ENABLE_VERSIONED_ATTRS
1242 if (rsc_details) {
1243 if (xml_has_children(rsc_details->versioned_parameters)) {
1244 add_node_copy(action_xml, rsc_details->versioned_parameters);
1245 }
1246
1247 if (xml_has_children(rsc_details->versioned_meta)) {
1248 add_node_copy(action_xml, rsc_details->versioned_meta);
1249 }
1250 }
1251 #endif
1252
1253 g_hash_table_foreach(action->meta, hash2metafield, args_xml);
1254 if (action->rsc != NULL) {
1255 const char *value = g_hash_table_lookup(action->rsc->meta, "external-ip");
1256 pe_resource_t *parent = action->rsc;
1257
1258 while (parent != NULL) {
1259 parent->cmds->append_meta(parent, args_xml);
1260 parent = parent->parent;
1261 }
1262
1263 if(value) {
1264 hash2smartfield((gpointer)"pcmk_external_ip", (gpointer)value, (gpointer)args_xml);
1265 }
1266
1267 if (action->node &&
1268 pe__is_guest_node(action->node)) {
1269 pe_node_t *host = NULL;
1270 enum action_tasks task = text2task(action->task);
1271
1272 if(task == action_notify || task == action_notified) {
1273 const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1274 task = text2task(n_task);
1275 }
1276
1277
1278 switch (task) {
1279 case stop_rsc:
1280 case stopped_rsc:
1281 case action_demote:
1282 case action_demoted:
1283 host = pe__current_node(action->node->details->remote_rsc->container);
1284 break;
1285 case start_rsc:
1286 case started_rsc:
1287 case monitor_rsc:
1288 case action_promote:
1289 case action_promoted:
1290 host = action->node->details->remote_rsc->container->allocated_to;
1291 break;
1292 default:
1293 break;
1294 }
1295
1296 if(host) {
1297 hash2metafield((gpointer)XML_RSC_ATTR_TARGET,
1298 (gpointer)g_hash_table_lookup(action->rsc->meta, XML_RSC_ATTR_TARGET), (gpointer)args_xml);
1299 hash2metafield((gpointer) PCMK__ENV_PHYSICAL_HOST,
1300 (gpointer)host->details->uname,
1301 (gpointer)args_xml);
1302 }
1303 }
1304
1305 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei) && action->node) {
1306
1307
1308
1309
1310
1311
1312 g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
1313 }
1314
1315 sorted_xml(args_xml, action_xml, FALSE);
1316 free_xml(args_xml);
1317
1318
1319 if (needs_node_info && (action->node != NULL)) {
1320 add_downed_nodes(action_xml, action, data_set);
1321 }
1322
1323 if (needs_maintenance_info) {
1324 add_maintenance_nodes(action_xml, data_set);
1325 }
1326
1327 crm_log_xml_trace(action_xml, "dumped action");
1328 return action_xml;
1329 }
1330
1331 static bool
1332 should_dump_action(pe_action_t *action)
1333 {
1334 CRM_CHECK(action != NULL, return false);
1335
1336 if (pcmk_is_set(action->flags, pe_action_dumped)) {
1337 crm_trace("Action %s (%d) already dumped", action->uuid, action->id);
1338 return false;
1339
1340 } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1341 && pcmk__str_eq(action->task, CRM_OP_PROBED, pcmk__str_casei)) {
1342 GListPtr lpc = NULL;
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359 for (lpc = action->actions_after; lpc != NULL; lpc = lpc->next) {
1360 pe_action_wrapper_t *wrapper = (pe_action_wrapper_t *) lpc->data;
1361
1362 if (!pcmk_is_set(wrapper->action->flags, pe_action_runnable)) {
1363
1364 } else if (!pcmk__str_eq(wrapper->action->task, RSC_START, pcmk__str_casei)) {
1365
1366 } else if (pcmk_is_set(wrapper->action->flags, pe_action_dumped)
1367 || should_dump_action(wrapper->action)) {
1368 crm_trace("Action %s (%d) should be dumped: "
1369 "dependency of %s (%d)",
1370 action->uuid, action->id,
1371 wrapper->action->uuid, wrapper->action->id);
1372 return true;
1373 }
1374 }
1375 }
1376
1377 if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1378 crm_trace("Ignoring action %s (%d): unrunnable",
1379 action->uuid, action->id);
1380 return false;
1381
1382 } else if (pcmk_is_set(action->flags, pe_action_optional)
1383 && !pcmk_is_set(action->flags, pe_action_print_always)) {
1384 crm_trace("Ignoring action %s (%d): optional",
1385 action->uuid, action->id);
1386 return false;
1387
1388
1389 } else if (action->rsc && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
1390 && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)) {
1391
1392 const char *interval_ms_s = g_hash_table_lookup(action->meta,
1393 XML_LRM_ATTR_INTERVAL_MS);
1394
1395
1396 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
1397 crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
1398 action->uuid, action->id, action->rsc->id);
1399 return false;
1400 }
1401 }
1402
1403 if (pcmk_is_set(action->flags, pe_action_pseudo) ||
1404 pcmk__strcase_any_of(action->task, CRM_OP_FENCE, CRM_OP_SHUTDOWN, NULL)) {
1405
1406 return true;
1407 }
1408
1409 if (action->node == NULL) {
1410 pe_err("Skipping action %s (%d) "
1411 "because it was not allocated to a node (bug?)",
1412 action->uuid, action->id);
1413 log_action(LOG_DEBUG, "Unallocated action", action, false);
1414 return false;
1415
1416 } else if (pcmk_is_set(action->flags, pe_action_dc)) {
1417 crm_trace("Action %s (%d) should be dumped: "
1418 "can run on DC instead of %s",
1419 action->uuid, action->id, action->node->details->uname);
1420
1421 } else if (pe__is_guest_node(action->node)
1422 && !action->node->details->remote_requires_reset) {
1423 crm_trace("Action %s (%d) should be dumped: "
1424 "assuming will be runnable on guest node %s",
1425 action->uuid, action->id, action->node->details->uname);
1426
1427 } else if (action->node->details->online == false) {
1428 pe_err("Skipping action %s (%d) "
1429 "because it was scheduled for offline node (bug?)",
1430 action->uuid, action->id);
1431 log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
1432 return false;
1433 #if 0
1434
1435
1436
1437 } else if (action->node->details->unclean == false) {
1438 pe_err("Skipping action %s (%d) "
1439 "because it was scheduled for unclean node (bug?)",
1440 action->uuid, action->id);
1441 log_action(LOG_DEBUG, "Action for unclean node", action, false);
1442 return false;
1443 #endif
1444 }
1445 return true;
1446 }
1447
1448
1449 static gint
1450 sort_action_id(gconstpointer a, gconstpointer b)
1451 {
1452 const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1453 const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1454
1455 if (a == NULL) {
1456 return 1;
1457 }
1458 if (b == NULL) {
1459 return -1;
1460 }
1461
1462 if (action_wrapper1->action->id > action_wrapper2->action->id) {
1463 return -1;
1464 }
1465
1466 if (action_wrapper1->action->id < action_wrapper2->action->id) {
1467 return 1;
1468 }
1469 return 0;
1470 }
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483 static bool
1484 check_dump_input(pe_action_t *action, pe_action_wrapper_t *input)
1485 {
1486 int type = input->type;
1487
1488 if (input->state == pe_link_dumped) {
1489 return true;
1490 }
1491
1492 pe__clear_order_flags(type, pe_order_implies_first_printed
1493 |pe_order_implies_then_printed
1494 |pe_order_optional);
1495
1496 if (input->type == pe_order_none) {
1497 crm_trace("Ignoring %s (%d) input %s (%d): "
1498 "ordering disabled",
1499 action->uuid, action->id,
1500 input->action->uuid, input->action->id);
1501 return false;
1502
1503 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1504 && (type == pe_order_none)
1505 && !pcmk__str_eq(input->action->uuid, CRM_OP_PROBED, pcmk__str_casei)) {
1506 crm_trace("Ignoring %s (%d) input %s (%d): "
1507 "optional and input unrunnable",
1508 action->uuid, action->id,
1509 input->action->uuid, input->action->id);
1510 return false;
1511
1512 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1513 && pcmk_is_set(input->type, pe_order_one_or_more)) {
1514 crm_trace("Ignoring %s (%d) input %s (%d): "
1515 "one-or-more and input unrunnable",
1516 action->uuid, action->id,
1517 input->action->uuid, input->action->id);
1518 return false;
1519
1520 } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1521 && pcmk_is_set(input->type, pe_order_stonith_stop)) {
1522 crm_trace("Ignoring %s (%d) input %s (%d): "
1523 "stonith stop but action is pseudo",
1524 action->uuid, action->id,
1525 input->action->uuid, input->action->id);
1526 return false;
1527
1528 } else if (pcmk_is_set(input->type, pe_order_implies_first_migratable)
1529 && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
1530 crm_trace("Ignoring %s (%d) input %s (%d): "
1531 "implies input migratable but input unrunnable",
1532 action->uuid, action->id,
1533 input->action->uuid, input->action->id);
1534 return false;
1535
1536 } else if (pcmk_is_set(input->type, pe_order_apply_first_non_migratable)
1537 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)) {
1538 crm_trace("Ignoring %s (%d) input %s (%d): "
1539 "only if input unmigratable but input unrunnable",
1540 action->uuid, action->id,
1541 input->action->uuid, input->action->id);
1542 return false;
1543
1544 } else if ((input->type == pe_order_optional)
1545 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)
1546 && pcmk__ends_with(input->action->uuid, "_stop_0")) {
1547 crm_trace("Ignoring %s (%d) input %s (%d): "
1548 "optional but stop in migration",
1549 action->uuid, action->id,
1550 input->action->uuid, input->action->id);
1551 return false;
1552
1553 } else if (input->type == pe_order_load) {
1554 pe_node_t *input_node = input->action->node;
1555
1556
1557
1558 if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
1559 pe_node_t *allocated = action->rsc->allocated_to;
1560
1561
1562
1563
1564 if ((input_node == NULL) || (allocated == NULL)
1565 || (input_node->details != allocated->details)) {
1566 crm_trace("Ignoring %s (%d) input %s (%d): "
1567 "load ordering node mismatch %s vs %s",
1568 action->uuid, action->id,
1569 input->action->uuid, input->action->id,
1570 (allocated? allocated->details->uname : "<none>"),
1571 (input_node? input_node->details->uname : "<none>"));
1572 input->type = pe_order_none;
1573 return false;
1574 }
1575
1576 } else if ((input_node == NULL) || (action->node == NULL)
1577 || (input_node->details != action->node->details)) {
1578 crm_trace("Ignoring %s (%d) input %s (%d): "
1579 "load ordering node mismatch %s vs %s",
1580 action->uuid, action->id,
1581 input->action->uuid, input->action->id,
1582 (action->node? action->node->details->uname : "<none>"),
1583 (input_node? input_node->details->uname : "<none>"));
1584 input->type = pe_order_none;
1585 return false;
1586
1587 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1588 crm_trace("Ignoring %s (%d) input %s (%d): "
1589 "load ordering input optional",
1590 action->uuid, action->id,
1591 input->action->uuid, input->action->id);
1592 input->type = pe_order_none;
1593 return false;
1594 }
1595
1596 } else if (input->type == pe_order_anti_colocation) {
1597 if (input->action->node && action->node
1598 && (input->action->node->details != action->node->details)) {
1599 crm_trace("Ignoring %s (%d) input %s (%d): "
1600 "anti-colocation node mismatch %s vs %s",
1601 action->uuid, action->id,
1602 input->action->uuid, input->action->id,
1603 action->node->details->uname,
1604 input->action->node->details->uname);
1605 input->type = pe_order_none;
1606 return false;
1607
1608 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1609 crm_trace("Ignoring %s (%d) input %s (%d): "
1610 "anti-colocation input optional",
1611 action->uuid, action->id,
1612 input->action->uuid, input->action->id);
1613 input->type = pe_order_none;
1614 return false;
1615 }
1616
1617 } else if (input->action->rsc
1618 && input->action->rsc != action->rsc
1619 && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
1620 && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
1621 && pcmk__ends_with(input->action->uuid, "_stop_0")
1622 && action->rsc && pe_rsc_is_clone(action->rsc)) {
1623 crm_warn("Ignoring requirement that %s complete before %s:"
1624 " unmanaged failed resources cannot prevent clone shutdown",
1625 input->action->uuid, action->uuid);
1626 return false;
1627
1628 } else if (pcmk_is_set(input->action->flags, pe_action_optional)
1629 && !pcmk_any_flags_set(input->action->flags,
1630 pe_action_print_always|pe_action_dumped)
1631 && !should_dump_action(input->action)) {
1632 crm_trace("Ignoring %s (%d) input %s (%d): "
1633 "input optional",
1634 action->uuid, action->id,
1635 input->action->uuid, input->action->id);
1636 return false;
1637 }
1638
1639 crm_trace("%s (%d) input %s (%d) @ %s should be dumped: %s, %s, %s, 0x%.6x",
1640 action->uuid, action->id,
1641 input->action->uuid, input->action->id,
1642 input->action->node? input->action->node->details->uname : "no node",
1643 pcmk_is_set(input->action->flags, pe_action_pseudo)? "pseudo" : "real",
1644 pcmk_is_set(input->action->flags, pe_action_runnable)? "runnable" : "unrunnable",
1645 pcmk_is_set(input->action->flags, pe_action_optional)? "optional" : "required",
1646 input->type);
1647 return true;
1648 }
1649
1650 static bool
1651 graph_has_loop(pe_action_t *init_action, pe_action_t *action,
1652 pe_action_wrapper_t *input)
1653 {
1654 bool has_loop = false;
1655
1656 if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
1657 crm_trace("Breaking tracking loop: %s@%s -> %s@%s (0x%.6x)",
1658 input->action->uuid,
1659 input->action->node? input->action->node->details->uname : "",
1660 action->uuid,
1661 action->node? action->node->details->uname : "",
1662 input->type);
1663 return false;
1664 }
1665
1666
1667 if (!check_dump_input(action, input)) {
1668 return false;
1669 }
1670
1671 if (input->action == init_action) {
1672 crm_debug("Input loop found in %s@%s ->...-> %s@%s",
1673 action->uuid,
1674 action->node? action->node->details->uname : "",
1675 init_action->uuid,
1676 init_action->node? init_action->node->details->uname : "");
1677 return true;
1678 }
1679
1680 pe__set_action_flags(input->action, pe_action_tracking);
1681
1682 crm_trace("Checking inputs of action %s@%s input %s@%s (0x%.6x)"
1683 "for graph loop with %s@%s ",
1684 action->uuid,
1685 action->node? action->node->details->uname : "",
1686 input->action->uuid,
1687 input->action->node? input->action->node->details->uname : "",
1688 input->type,
1689 init_action->uuid,
1690 init_action->node? init_action->node->details->uname : "");
1691
1692
1693 for (GList *iter = input->action->actions_before;
1694 iter != NULL; iter = iter->next) {
1695
1696 if (graph_has_loop(init_action, input->action,
1697 (pe_action_wrapper_t *) iter->data)) {
1698
1699 has_loop = true;
1700 goto done;
1701 }
1702 }
1703
1704 done:
1705 pe__clear_action_flags(input->action, pe_action_tracking);
1706
1707 if (!has_loop) {
1708 crm_trace("No input loop found in %s@%s -> %s@%s (0x%.6x)",
1709 input->action->uuid,
1710 input->action->node? input->action->node->details->uname : "",
1711 action->uuid,
1712 action->node? action->node->details->uname : "",
1713 input->type);
1714 }
1715 return has_loop;
1716 }
1717
1718 bool
1719 pcmk__ordering_is_invalid(pe_action_t *action, pe_action_wrapper_t *input)
1720 {
1721
1722
1723
1724 if (!pcmk_is_set(input->type, pe_order_preserve)
1725 && action->rsc && action->rsc->fillers
1726 && input->action->rsc && input->action->node
1727 && input->action->node->details->remote_rsc
1728 && (input->action->node->details->remote_rsc->container == action->rsc)) {
1729 crm_warn("Invalid ordering constraint between %s and %s",
1730 input->action->rsc->id, action->rsc->id);
1731 return true;
1732 }
1733
1734
1735
1736
1737
1738
1739
1740
1741 if ((input->type == pe_order_load) && action->rsc
1742 && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)
1743 && graph_has_loop(action, action, input)) {
1744 return true;
1745 }
1746
1747 return false;
1748 }
1749
1750
1751 static void
1752 deduplicate_inputs(pe_action_t *action)
1753 {
1754 GList *item = NULL;
1755 GList *next = NULL;
1756 pe_action_wrapper_t *last_input = NULL;
1757
1758 action->actions_before = g_list_sort(action->actions_before,
1759 sort_action_id);
1760 for (item = action->actions_before; item != NULL; item = next) {
1761 pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1762
1763 next = item->next;
1764 if (last_input && (input->action->id == last_input->action->id)) {
1765 crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1766 input->action->uuid, input->action->id,
1767 action->uuid, action->id);
1768
1769
1770
1771
1772
1773 last_input->type |= input->type;
1774 if (input->state == pe_link_dumped) {
1775 last_input->state = pe_link_dumped;
1776 }
1777
1778 free(item->data);
1779 action->actions_before = g_list_delete_link(action->actions_before,
1780 item);
1781 } else {
1782 last_input = input;
1783 input->state = pe_link_not_dumped;
1784 }
1785 }
1786 }
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803 void
1804 graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
1805 {
1806 GList *lpc = NULL;
1807 int synapse_priority = 0;
1808 xmlNode *syn = NULL;
1809 xmlNode *set = NULL;
1810 xmlNode *in = NULL;
1811 xmlNode *xml_action = NULL;
1812 pe_action_wrapper_t *input = NULL;
1813
1814
1815
1816
1817 if (!pcmk_is_set(action->flags, pe_action_dedup)) {
1818 deduplicate_inputs(action);
1819 pe__set_action_flags(action, pe_action_dedup);
1820 }
1821
1822 if (should_dump_action(action) == FALSE) {
1823 return;
1824 }
1825
1826 pe__set_action_flags(action, pe_action_dumped);
1827
1828 syn = create_xml_node(data_set->graph, "synapse");
1829 set = create_xml_node(syn, "action_set");
1830 in = create_xml_node(syn, "inputs");
1831
1832 crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
1833 data_set->num_synapse++;
1834
1835 if (action->rsc != NULL) {
1836 synapse_priority = action->rsc->priority;
1837 }
1838 if (action->priority > synapse_priority) {
1839 synapse_priority = action->priority;
1840 }
1841 if (synapse_priority > 0) {
1842 crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
1843 }
1844
1845 xml_action = action2xml(action, FALSE, data_set);
1846 add_node_nocopy(set, crm_element_name(xml_action), xml_action);
1847
1848 for (lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
1849 input = (pe_action_wrapper_t *) lpc->data;
1850 if (check_dump_input(action, input)) {
1851 xmlNode *input_xml = create_xml_node(in, "trigger");
1852
1853 input->state = pe_link_dumped;
1854 xml_action = action2xml(input->action, TRUE, data_set);
1855 add_node_nocopy(input_xml, crm_element_name(xml_action), xml_action);
1856 }
1857 }
1858 }