This source file includes following definitions.
- get_action_flags
- convert_non_atomic_uuid
- rsc_expand_action
- graph_update_action
- update_action
- 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
- ordering_can_change_actions
- check_dump_input
- pcmk__graph_has_loop
- 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 #include "libpacemaker_private.h"
23
24 gboolean rsc_update_action(pe_action_t * first, pe_action_t * then, enum pe_ordering type);
25
26 static enum pe_action_flags
27 get_action_flags(pe_action_t * action, pe_node_t * node)
28 {
29 enum pe_action_flags flags = action->flags;
30
31 if (action->rsc) {
32 flags = action->rsc->cmds->action_flags(action, NULL);
33
34 if (pe_rsc_is_clone(action->rsc) && node) {
35
36
37 enum pe_action_flags clone_flags = action->rsc->cmds->action_flags(action, node);
38
39
40
41
42
43
44
45
46
47
48
49 if (!pcmk_is_set(clone_flags, pe_action_runnable)
50 && pcmk_is_set(flags, pe_action_runnable)) {
51
52 pe__set_raw_action_flags(clone_flags, action->rsc->id,
53 pe_action_runnable);
54 }
55 flags = clone_flags;
56 }
57 }
58 return flags;
59 }
60
61 static char *
62 convert_non_atomic_uuid(char *old_uuid, pe_resource_t * rsc, gboolean allow_notify,
63 gboolean free_original)
64 {
65 guint interval_ms = 0;
66 char *uuid = NULL;
67 char *rid = NULL;
68 char *raw_task = NULL;
69 int task = no_action;
70
71 CRM_ASSERT(rsc);
72 pe_rsc_trace(rsc, "Processing %s", old_uuid);
73 if (old_uuid == NULL) {
74 return NULL;
75
76 } else if (strstr(old_uuid, "notify") != NULL) {
77 goto done;
78
79 } else if (rsc->variant < pe_group) {
80 goto done;
81 }
82
83 CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval_ms));
84 if (interval_ms > 0) {
85 goto done;
86 }
87
88 task = text2task(raw_task);
89 switch (task) {
90 case stop_rsc:
91 case start_rsc:
92 case action_notify:
93 case action_promote:
94 case action_demote:
95 break;
96 case stopped_rsc:
97 case started_rsc:
98 case action_notified:
99 case action_promoted:
100 case action_demoted:
101 task--;
102 break;
103 case monitor_rsc:
104 case shutdown_crm:
105 case stonith_node:
106 task = no_action;
107 break;
108 default:
109 crm_err("Unknown action: %s", raw_task);
110 task = no_action;
111 break;
112 }
113
114 if (task != no_action) {
115 if (pcmk_is_set(rsc->flags, pe_rsc_notify) && allow_notify) {
116 uuid = pcmk__notify_key(rid, "confirmed-post", task2text(task + 1));
117
118 } else {
119 uuid = pcmk__op_key(rid, task2text(task + 1), 0);
120 }
121 pe_rsc_trace(rsc, "Converted %s -> %s", old_uuid, uuid);
122 }
123
124 done:
125 if (uuid == NULL) {
126 uuid = strdup(old_uuid);
127 }
128
129 if (free_original) {
130 free(old_uuid);
131 }
132
133 free(raw_task);
134 free(rid);
135 return uuid;
136 }
137
138 static pe_action_t *
139 rsc_expand_action(pe_action_t * action)
140 {
141 gboolean notify = FALSE;
142 pe_action_t *result = action;
143 pe_resource_t *rsc = action->rsc;
144
145 if (rsc == NULL) {
146 return action;
147 }
148
149 if ((rsc->parent == NULL)
150 || (pe_rsc_is_clone(rsc) && (rsc->parent->variant == pe_container))) {
151
152
153
154 notify = pcmk_is_set(rsc->flags, pe_rsc_notify);
155 }
156
157 if (rsc->variant >= pe_group) {
158
159 char *uuid = NULL;
160
161 uuid = convert_non_atomic_uuid(action->uuid, rsc, notify, FALSE);
162 if (uuid) {
163 pe_rsc_trace(rsc, "Converting %s to %s %d", action->uuid, uuid,
164 pcmk_is_set(rsc->flags, pe_rsc_notify));
165 result = find_first_action(rsc->actions, uuid, NULL, NULL);
166 if (result == NULL) {
167 crm_err("Couldn't expand %s to %s in %s", action->uuid, uuid, rsc->id);
168 result = action;
169 }
170 free(uuid);
171 }
172 }
173 return result;
174 }
175
176 static enum pe_graph_flags
177 graph_update_action(pe_action_t * first, pe_action_t * then, pe_node_t * node,
178 enum pe_action_flags first_flags, enum pe_action_flags then_flags,
179 pe_action_wrapper_t *order, pe_working_set_t *data_set)
180 {
181 enum pe_graph_flags changed = pe_graph_none;
182 enum pe_ordering type = order->type;
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 pe_rsc_trace(then->rsc,
203 "%s then %s: mapped pe_order_implies_then_on_node to "
204 "pe_order_implies_then on %s",
205 first->uuid, then->uuid, node->details->uname);
206 }
207
208 if (type & pe_order_implies_then) {
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 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_then",
220 first->uuid, then->uuid,
221 (changed? "changed" : "unchanged"));
222 }
223
224 if ((type & pe_order_restart) && then->rsc) {
225 enum pe_action_flags restart = (pe_action_optional | pe_action_runnable);
226
227 changed |= then->rsc->cmds->update_actions(first, then, node,
228 first_flags, restart,
229 pe_order_restart, data_set);
230 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_restart",
231 first->uuid, then->uuid,
232 (changed? "changed" : "unchanged"));
233 }
234
235 if (type & pe_order_implies_first) {
236 if (first->rsc) {
237 changed |= first->rsc->cmds->update_actions(first, then, node,
238 first_flags, pe_action_optional, pe_order_implies_first,
239 data_set);
240
241 } else if (!pcmk_is_set(first_flags, pe_action_optional)
242 && pcmk_is_set(first->flags, pe_action_runnable)) {
243 pe__clear_action_flags(first, pe_action_runnable);
244 pe__set_graph_flags(changed, first, pe_graph_updated_first);
245 }
246 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_first",
247 first->uuid, then->uuid,
248 (changed? "changed" : "unchanged"));
249 }
250
251 if (type & pe_order_promoted_implies_first) {
252 if (then->rsc) {
253 changed |= then->rsc->cmds->update_actions(first, then, node,
254 first_flags & pe_action_optional, pe_action_optional,
255 pe_order_promoted_implies_first, data_set);
256 }
257 pe_rsc_trace(then->rsc,
258 "%s then %s: %s after pe_order_promoted_implies_first",
259 first->uuid, then->uuid,
260 (changed? "changed" : "unchanged"));
261 }
262
263 if (type & pe_order_one_or_more) {
264 if (then->rsc) {
265 changed |= then->rsc->cmds->update_actions(first, then, node,
266 first_flags, pe_action_runnable, pe_order_one_or_more,
267 data_set);
268
269 } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
270
271 then->runnable_before++;
272
273
274
275
276 if ((then->runnable_before >= then->required_runnable_before)
277 && !pcmk_is_set(then->flags, pe_action_runnable)) {
278
279 pe__set_action_flags(then, pe_action_runnable);
280 pe__set_graph_flags(changed, first, pe_graph_updated_then);
281 }
282 }
283 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_one_or_more",
284 first->uuid, then->uuid,
285 (changed? "changed" : "unchanged"));
286 }
287
288 if (then->rsc && pcmk_is_set(type, pe_order_probe)) {
289 if (!pcmk_is_set(first_flags, pe_action_runnable)
290 && (first->rsc->running_on != NULL)) {
291
292 pe_rsc_trace(then->rsc,
293 "%s then %s: ignoring because first is stopping",
294 first->uuid, then->uuid);
295 type = pe_order_none;
296 order->type = pe_order_none;
297
298 } else {
299 changed |= then->rsc->cmds->update_actions(first, then, node,
300 first_flags, pe_action_runnable, pe_order_runnable_left,
301 data_set);
302 }
303 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_probe",
304 first->uuid, then->uuid,
305 (changed? "changed" : "unchanged"));
306 }
307
308 if (type & pe_order_runnable_left) {
309 if (then->rsc) {
310 changed |= then->rsc->cmds->update_actions(first, then, node,
311 first_flags, pe_action_runnable, pe_order_runnable_left,
312 data_set);
313
314 } else if (!pcmk_is_set(first_flags, pe_action_runnable)
315 && pcmk_is_set(then->flags, pe_action_runnable)) {
316
317 pe__clear_action_flags(then, pe_action_runnable);
318 pe__set_graph_flags(changed, first, pe_graph_updated_then);
319 }
320 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_runnable_left",
321 first->uuid, then->uuid,
322 (changed? "changed" : "unchanged"));
323 }
324
325 if (type & pe_order_implies_first_migratable) {
326 if (then->rsc) {
327 changed |= then->rsc->cmds->update_actions(first, then, node,
328 first_flags, pe_action_optional,
329 pe_order_implies_first_migratable, data_set);
330 }
331 pe_rsc_trace(then->rsc, "%s then %s: %s after "
332 "pe_order_implies_first_migratable",
333 first->uuid, then->uuid,
334 (changed? "changed" : "unchanged"));
335 }
336
337 if (type & pe_order_pseudo_left) {
338 if (then->rsc) {
339 changed |= then->rsc->cmds->update_actions(first, then, node,
340 first_flags, pe_action_optional, pe_order_pseudo_left,
341 data_set);
342 }
343 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_pseudo_left",
344 first->uuid, then->uuid,
345 (changed? "changed" : "unchanged"));
346 }
347
348 if (type & pe_order_optional) {
349 if (then->rsc) {
350 changed |= then->rsc->cmds->update_actions(first, then, node,
351 first_flags, pe_action_runnable, pe_order_optional, data_set);
352 }
353 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_optional",
354 first->uuid, then->uuid,
355 (changed? "changed" : "unchanged"));
356 }
357
358 if (type & pe_order_asymmetrical) {
359 if (then->rsc) {
360 changed |= then->rsc->cmds->update_actions(first, then, node,
361 first_flags, pe_action_runnable, pe_order_asymmetrical,
362 data_set);
363 }
364 pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_asymmetrical",
365 first->uuid, then->uuid,
366 (changed? "changed" : "unchanged"));
367 }
368
369 if ((first->flags & pe_action_runnable) && (type & pe_order_implies_then_printed)
370 && (first_flags & pe_action_optional) == 0) {
371 pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
372 then->uuid, first->uuid);
373 pe__set_action_flags(then, pe_action_print_always);
374
375 }
376
377 if (pcmk_is_set(type, pe_order_implies_first_printed)
378 && !pcmk_is_set(then_flags, pe_action_optional)) {
379
380 pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
381 first->uuid, then->uuid);
382 pe__set_action_flags(first, pe_action_print_always);
383
384 }
385
386 if ((type & pe_order_implies_then
387 || type & pe_order_implies_first
388 || type & pe_order_restart)
389 && first->rsc
390 && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)
391 && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
392 && pcmk_is_set(first->rsc->flags, pe_rsc_block)
393 && !pcmk_is_set(first->flags, pe_action_runnable)) {
394
395 if (pcmk_is_set(then->flags, pe_action_runnable)) {
396 pe__clear_action_flags(then, pe_action_runnable);
397 pe__set_graph_flags(changed, first, pe_graph_updated_then);
398 }
399 pe_rsc_trace(then->rsc, "%s then %s: %s after checking whether first "
400 "is blocked, unmanaged, unrunnable stop",
401 first->uuid, then->uuid,
402 (changed? "changed" : "unchanged"));
403 }
404
405 return changed;
406 }
407
408
409
410 #define action_type_str(flags) \
411 (pcmk_is_set((flags), pe_action_pseudo)? "pseudo-action" : "action")
412
413 #define action_optional_str(flags) \
414 (pcmk_is_set((flags), pe_action_optional)? "optional" : "required")
415
416 #define action_runnable_str(flags) \
417 (pcmk_is_set((flags), pe_action_runnable)? "runnable" : "unrunnable")
418
419 #define action_node_str(a) \
420 (((a)->node == NULL)? "no node" : (a)->node->details->uname)
421
422 gboolean
423 update_action(pe_action_t *then, pe_working_set_t *data_set)
424 {
425 GList *lpc = NULL;
426 enum pe_graph_flags changed = pe_graph_none;
427 int last_flags = then->flags;
428
429 pe_rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
430 action_type_str(then->flags), then->uuid,
431 action_optional_str(then->flags),
432 action_runnable_str(then->flags), action_node_str(then));
433
434 if (pcmk_is_set(then->flags, pe_action_requires_any)) {
435
436
437
438
439 then->runnable_before = 0;
440
441
442
443
444 if (then->required_runnable_before == 0) {
445 then->required_runnable_before = 1;
446 }
447 pe__clear_action_flags(then, pe_action_runnable);
448
449
450
451
452
453
454
455 }
456
457 for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
458 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
459 pe_action_t *first = other->action;
460
461 pe_node_t *then_node = then->node;
462 pe_node_t *first_node = first->node;
463
464 enum pe_action_flags then_flags = 0;
465 enum pe_action_flags first_flags = 0;
466
467 if (first->rsc && first->rsc->variant == pe_group && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
468 first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
469 if (first_node) {
470 pe_rsc_trace(first->rsc, "Found node %s for 'first' %s",
471 first_node->details->uname, first->uuid);
472 }
473 }
474
475 if (then->rsc && then->rsc->variant == pe_group && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
476 then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
477 if (then_node) {
478 pe_rsc_trace(then->rsc, "Found node %s for 'then' %s",
479 then_node->details->uname, then->uuid);
480 }
481 }
482
483 if (pcmk_is_set(other->type, pe_order_same_node)
484 && (first_node != NULL) && (then_node != NULL)
485 && (first_node->details != then_node->details)) {
486
487 pe_rsc_trace(then->rsc,
488 "Disabled ordering %s on %s then %s on %s: not same node",
489 other->action->uuid, first_node->details->uname,
490 then->uuid, then_node->details->uname);
491 other->type = pe_order_none;
492 continue;
493 }
494
495 pe__clear_graph_flags(changed, then, pe_graph_updated_first);
496
497 if (first->rsc && pcmk_is_set(other->type, pe_order_then_cancels_first)
498 && !pcmk_is_set(then->flags, pe_action_optional)) {
499
500
501
502
503 pe__set_action_flags(other->action, pe_action_optional);
504 if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
505 pe__clear_resource_flags(first->rsc, pe_rsc_reload);
506 }
507 }
508
509 if (first->rsc && then->rsc && (first->rsc != then->rsc)
510 && (is_parent(then->rsc, first->rsc) == FALSE)) {
511 first = rsc_expand_action(first);
512 }
513 if (first != other->action) {
514 pe_rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
515 then->uuid, first->uuid, other->action->uuid);
516 }
517
518 first_flags = get_action_flags(first, then_node);
519 then_flags = get_action_flags(then, first_node);
520
521 pe_rsc_trace(then->rsc,
522 "%s then %s: type=0x%.6x filter=0x%.6x "
523 "(%s %s %s on %s 0x%.6x then 0x%.6x)",
524 first->uuid, then->uuid, other->type, first_flags,
525 action_optional_str(first_flags),
526 action_runnable_str(first_flags),
527 action_type_str(first_flags), action_node_str(first),
528 first->flags, then->flags);
529
530 if (first == other->action) {
531
532
533
534
535
536
537
538
539
540
541
542
543
544 pe_node_t *node = then->node;
545 changed |= graph_update_action(first, then, node, first_flags,
546 then_flags, other, data_set);
547
548
549
550
551 } else if (order_actions(first, then, other->type)) {
552
553
554
555 pe__set_graph_flags(changed, then,
556 pe_graph_updated_then|pe_graph_disable);
557 }
558
559 if (changed & pe_graph_disable) {
560 pe_rsc_trace(then->rsc,
561 "Disabled ordering %s then %s in favor of %s then %s",
562 other->action->uuid, then->uuid, first->uuid,
563 then->uuid);
564 pe__clear_graph_flags(changed, then, pe_graph_disable);
565 other->type = pe_order_none;
566 }
567
568 if (changed & pe_graph_updated_first) {
569 GList *lpc2 = NULL;
570
571 crm_trace("Re-processing %s and its 'after' actions since it changed",
572 first->uuid);
573 for (lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) {
574 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
575
576 update_action(other->action, data_set);
577 }
578 update_action(first, data_set);
579 }
580 }
581
582 if (pcmk_is_set(then->flags, pe_action_requires_any)) {
583 if (last_flags != then->flags) {
584 pe__set_graph_flags(changed, then, pe_graph_updated_then);
585 } else {
586 pe__clear_graph_flags(changed, then, pe_graph_updated_then);
587 }
588 }
589
590 if (changed & pe_graph_updated_then) {
591 crm_trace("Re-processing %s and its 'after' actions since it changed",
592 then->uuid);
593 if (pcmk_is_set(last_flags, pe_action_runnable)
594 && !pcmk_is_set(then->flags, pe_action_runnable)) {
595 pcmk__block_colocated_starts(then, data_set);
596 }
597 update_action(then, data_set);
598 for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
599 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
600
601 update_action(other->action, data_set);
602 }
603 }
604
605 return FALSE;
606 }
607
608
609
610
611
612
613
614
615 static xmlNode*
616 add_node_to_xml_by_id(const char *id, xmlNode *xml)
617 {
618 xmlNode *node_xml;
619
620 node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
621 crm_xml_add(node_xml, XML_ATTR_UUID, id);
622
623 return node_xml;
624 }
625
626
627
628
629
630
631
632
633 static void
634 add_node_to_xml(const pe_node_t *node, void *xml)
635 {
636 add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
637 }
638
639
640
641
642
643
644
645
646 static int
647 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
648 {
649 GList *gIter = NULL;
650 xmlNode *maintenance =
651 xml?create_xml_node(xml, XML_GRAPH_TAG_MAINTENANCE):NULL;
652 int count = 0;
653
654 for (gIter = data_set->nodes; gIter != NULL;
655 gIter = gIter->next) {
656 pe_node_t *node = (pe_node_t *) gIter->data;
657 struct pe_node_shared_s *details = node->details;
658
659 if (!pe__is_guest_or_remote_node(node)) {
660 continue;
661 }
662
663 if (details->maintenance != details->remote_maintenance) {
664 if (maintenance) {
665 crm_xml_add(
666 add_node_to_xml_by_id(node->details->id, maintenance),
667 XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
668 }
669 count++;
670 }
671 }
672 crm_trace("%s %d nodes to adjust maintenance-mode "
673 "to transition", maintenance?"Added":"Counted", count);
674 return count;
675 }
676
677
678
679
680
681
682
683 void
684 add_maintenance_update(pe_working_set_t *data_set)
685 {
686 pe_action_t *action = NULL;
687
688 if (add_maintenance_nodes(NULL, data_set)) {
689 crm_trace("adding maintenance state update pseudo action");
690 action = get_pseudo_op(CRM_OP_MAINTENANCE_NODES, data_set);
691 pe__set_action_flags(action, pe_action_print_always);
692 }
693 }
694
695
696
697
698
699
700
701
702
703
704
705
706
707 static void
708 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
709 const pe_working_set_t *data_set)
710 {
711 CRM_CHECK(xml && action && action->node && data_set, return);
712
713 if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
714
715
716 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
717 add_node_to_xml_by_id(action->node->details->id, downed);
718
719 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
720
721
722 const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
723
724 if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
725 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
726 add_node_to_xml_by_id(action->node->details->id, downed);
727 pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
728 }
729
730 } else if (action->rsc && action->rsc->is_remote_node
731 && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
732
733
734
735
736 GList *iter;
737 pe_action_t *input;
738 gboolean migrating = FALSE;
739
740 for (iter = action->actions_before; iter != NULL; iter = iter->next) {
741 input = ((pe_action_wrapper_t *) iter->data)->action;
742 if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
743 && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
744 migrating = TRUE;
745 break;
746 }
747 }
748 if (!migrating) {
749 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
750 add_node_to_xml_by_id(action->rsc->id, downed);
751 }
752 }
753 }
754
755 static bool
756 should_lock_action(pe_action_t *action)
757 {
758
759 if ((action->rsc->lock_node == NULL) || (action->node == NULL)
760 || (action->node->details != action->rsc->lock_node->details)) {
761 return false;
762 }
763
764
765
766
767 if (action->node->details->shutdown && action->task
768 && strcmp(action->task, RSC_STOP)) {
769 return false;
770 }
771
772 return true;
773 }
774
775 static xmlNode *
776 action2xml(pe_action_t * action, gboolean as_input, pe_working_set_t *data_set)
777 {
778 gboolean needs_node_info = TRUE;
779 gboolean needs_maintenance_info = FALSE;
780 xmlNode *action_xml = NULL;
781 xmlNode *args_xml = NULL;
782 #if ENABLE_VERSIONED_ATTRS
783 pe_rsc_action_details_t *rsc_details = NULL;
784 #endif
785
786 if (action == NULL) {
787 return NULL;
788 }
789
790 if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
791
792 action_xml = create_xml_node(NULL,
793 pcmk_is_set(action->flags, pe_action_pseudo)?
794 XML_GRAPH_TAG_PSEUDO_EVENT :
795 XML_GRAPH_TAG_CRM_EVENT);
796
797 } else if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
798 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
799
800 } else if (pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
801 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
802
803 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_REFRESH, pcmk__str_casei)) {
804 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
805
806 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
807
808 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
809 crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
810
811
812
813
814 } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
815 if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
816 needs_maintenance_info = TRUE;
817 }
818 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
819 needs_node_info = FALSE;
820
821 } else {
822 action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
823
824 #if ENABLE_VERSIONED_ATTRS
825 rsc_details = pe_rsc_action_details(action);
826 #endif
827 }
828
829 crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
830 crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
831 if (action->rsc != NULL && action->rsc->clone_name != NULL) {
832 char *clone_key = NULL;
833 guint interval_ms;
834
835 if (pcmk__guint_from_hash(action->meta,
836 XML_LRM_ATTR_INTERVAL_MS, 0,
837 &interval_ms) != pcmk_rc_ok) {
838 interval_ms = 0;
839 }
840
841 if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_casei)) {
842 const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
843 const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
844
845 CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid));
846 CRM_CHECK(n_task != NULL,
847 crm_err("No notify operation value found for %s", action->uuid));
848 clone_key = pcmk__notify_key(action->rsc->clone_name,
849 n_type, n_task);
850
851 } else if(action->cancel_task) {
852 clone_key = pcmk__op_key(action->rsc->clone_name,
853 action->cancel_task, interval_ms);
854 } else {
855 clone_key = pcmk__op_key(action->rsc->clone_name,
856 action->task, interval_ms);
857 }
858
859 CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid));
860 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
861 crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
862 free(clone_key);
863
864 } else {
865 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
866 }
867
868 if (needs_node_info && action->node != NULL) {
869 pe_node_t *router_node = pcmk__connection_host_for_action(action);
870
871 crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
872 crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
873 if (router_node) {
874 crm_xml_add(action_xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
875 }
876
877 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET), strdup(action->node->details->uname));
878 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID), strdup(action->node->details->id));
879 }
880
881
882 if (as_input) {
883 return action_xml;
884 }
885
886 if (action->rsc && !pcmk_is_set(action->flags, pe_action_pseudo)) {
887 int lpc = 0;
888 xmlNode *rsc_xml = NULL;
889 const char *attr_list[] = {
890 XML_AGENT_ATTR_CLASS,
891 XML_AGENT_ATTR_PROVIDER,
892 XML_ATTR_TYPE
893 };
894
895
896
897
898 if (should_lock_action(action)) {
899 crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
900 (long long) action->rsc->lock_time);
901 }
902
903
904
905 rsc_xml = create_xml_node(action_xml,
906 crm_element_name(action->rsc->xml));
907 if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
908 && action->rsc->clone_name) {
909
910
911
912
913
914
915
916
917
918
919
920 crm_debug("Using orphan clone name %s instead of %s", action->rsc->id,
921 action->rsc->clone_name);
922 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
923 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
924
925 } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
926 const char *xml_id = ID(action->rsc->xml);
927
928 crm_debug("Using anonymous clone name %s for %s (aka. %s)", xml_id, action->rsc->id,
929 action->rsc->clone_name);
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944 crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
945 if (action->rsc->clone_name && !pcmk__str_eq(xml_id, action->rsc->clone_name, pcmk__str_casei)) {
946 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
947 } else {
948 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
949 }
950
951 } else {
952 CRM_ASSERT(action->rsc->clone_name == NULL);
953 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
954 }
955
956 for (lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
957 crm_xml_add(rsc_xml, attr_list[lpc],
958 g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
959 }
960 }
961
962
963 args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
964 crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
965
966 g_hash_table_foreach(action->extra, hash2field, args_xml);
967 if (action->rsc != NULL && action->node) {
968
969 GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
970
971 pcmk__substitute_remote_addr(action->rsc, params, data_set);
972
973 g_hash_table_foreach(params, hash2smartfield, args_xml);
974
975 #if ENABLE_VERSIONED_ATTRS
976 {
977 xmlNode *versioned_parameters = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
978
979 pe_get_versioned_attributes(versioned_parameters, action->rsc,
980 action->node, data_set);
981 if (xml_has_children(versioned_parameters)) {
982 add_node_copy(action_xml, versioned_parameters);
983 }
984 free_xml(versioned_parameters);
985 }
986 #endif
987
988 } else if(action->rsc && action->rsc->variant <= pe_native) {
989 GHashTable *params = pe_rsc_params(action->rsc, NULL, data_set);
990
991 g_hash_table_foreach(params, hash2smartfield, args_xml);
992
993 #if ENABLE_VERSIONED_ATTRS
994 if (xml_has_children(action->rsc->versioned_parameters)) {
995 add_node_copy(action_xml, action->rsc->versioned_parameters);
996 }
997 #endif
998 }
999
1000 #if ENABLE_VERSIONED_ATTRS
1001 if (rsc_details) {
1002 if (xml_has_children(rsc_details->versioned_parameters)) {
1003 add_node_copy(action_xml, rsc_details->versioned_parameters);
1004 }
1005
1006 if (xml_has_children(rsc_details->versioned_meta)) {
1007 add_node_copy(action_xml, rsc_details->versioned_meta);
1008 }
1009 }
1010 #endif
1011
1012 g_hash_table_foreach(action->meta, hash2metafield, args_xml);
1013 if (action->rsc != NULL) {
1014 const char *value = g_hash_table_lookup(action->rsc->meta, "external-ip");
1015 pe_resource_t *parent = action->rsc;
1016
1017 while (parent != NULL) {
1018 parent->cmds->append_meta(parent, args_xml);
1019 parent = parent->parent;
1020 }
1021
1022 if(value) {
1023 hash2smartfield((gpointer)"pcmk_external_ip", (gpointer)value, (gpointer)args_xml);
1024 }
1025
1026 pcmk__add_bundle_meta_to_xml(args_xml, action);
1027
1028 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei) && action->node) {
1029
1030
1031
1032
1033
1034
1035 g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
1036 }
1037
1038 sorted_xml(args_xml, action_xml, FALSE);
1039 free_xml(args_xml);
1040
1041
1042 if (needs_node_info && (action->node != NULL)) {
1043 add_downed_nodes(action_xml, action, data_set);
1044 }
1045
1046 if (needs_maintenance_info) {
1047 add_maintenance_nodes(action_xml, data_set);
1048 }
1049
1050 crm_log_xml_trace(action_xml, "dumped action");
1051 return action_xml;
1052 }
1053
1054 static bool
1055 should_dump_action(pe_action_t *action)
1056 {
1057 CRM_CHECK(action != NULL, return false);
1058
1059 if (pcmk_is_set(action->flags, pe_action_dumped)) {
1060 crm_trace("Action %s (%d) already dumped", action->uuid, action->id);
1061 return false;
1062
1063 } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1064 && pcmk__str_eq(action->task, CRM_OP_PROBED, pcmk__str_casei)) {
1065 GList *lpc = NULL;
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 for (lpc = action->actions_after; lpc != NULL; lpc = lpc->next) {
1083 pe_action_wrapper_t *wrapper = (pe_action_wrapper_t *) lpc->data;
1084
1085 if (!pcmk_is_set(wrapper->action->flags, pe_action_runnable)) {
1086
1087 } else if (!pcmk__str_eq(wrapper->action->task, RSC_START, pcmk__str_casei)) {
1088
1089 } else if (pcmk_is_set(wrapper->action->flags, pe_action_dumped)
1090 || should_dump_action(wrapper->action)) {
1091 crm_trace("Action %s (%d) should be dumped: "
1092 "dependency of %s (%d)",
1093 action->uuid, action->id,
1094 wrapper->action->uuid, wrapper->action->id);
1095 return true;
1096 }
1097 }
1098 }
1099
1100 if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1101 crm_trace("Ignoring action %s (%d): unrunnable",
1102 action->uuid, action->id);
1103 return false;
1104
1105 } else if (pcmk_is_set(action->flags, pe_action_optional)
1106 && !pcmk_is_set(action->flags, pe_action_print_always)) {
1107 crm_trace("Ignoring action %s (%d): optional",
1108 action->uuid, action->id);
1109 return false;
1110
1111
1112 } else if (action->rsc && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
1113 && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)) {
1114
1115 const char *interval_ms_s = g_hash_table_lookup(action->meta,
1116 XML_LRM_ATTR_INTERVAL_MS);
1117
1118
1119 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
1120 crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
1121 action->uuid, action->id, action->rsc->id);
1122 return false;
1123 }
1124 }
1125
1126 if (pcmk_is_set(action->flags, pe_action_pseudo) ||
1127 pcmk__strcase_any_of(action->task, CRM_OP_FENCE, CRM_OP_SHUTDOWN, NULL)) {
1128
1129 return true;
1130 }
1131
1132 if (action->node == NULL) {
1133 pe_err("Skipping action %s (%d) "
1134 "because it was not allocated to a node (bug?)",
1135 action->uuid, action->id);
1136 log_action(LOG_DEBUG, "Unallocated action", action, false);
1137 return false;
1138
1139 } else if (pcmk_is_set(action->flags, pe_action_dc)) {
1140 crm_trace("Action %s (%d) should be dumped: "
1141 "can run on DC instead of %s",
1142 action->uuid, action->id, action->node->details->uname);
1143
1144 } else if (pe__is_guest_node(action->node)
1145 && !action->node->details->remote_requires_reset) {
1146 crm_trace("Action %s (%d) should be dumped: "
1147 "assuming will be runnable on guest node %s",
1148 action->uuid, action->id, action->node->details->uname);
1149
1150 } else if (action->node->details->online == false) {
1151 pe_err("Skipping action %s (%d) "
1152 "because it was scheduled for offline node (bug?)",
1153 action->uuid, action->id);
1154 log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
1155 return false;
1156 #if 0
1157
1158
1159
1160 } else if (action->node->details->unclean == false) {
1161 pe_err("Skipping action %s (%d) "
1162 "because it was scheduled for unclean node (bug?)",
1163 action->uuid, action->id);
1164 log_action(LOG_DEBUG, "Action for unclean node", action, false);
1165 return false;
1166 #endif
1167 }
1168 return true;
1169 }
1170
1171
1172 static gint
1173 sort_action_id(gconstpointer a, gconstpointer b)
1174 {
1175 const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1176 const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1177
1178 if (a == NULL) {
1179 return 1;
1180 }
1181 if (b == NULL) {
1182 return -1;
1183 }
1184
1185 if (action_wrapper1->action->id > action_wrapper2->action->id) {
1186 return -1;
1187 }
1188
1189 if (action_wrapper1->action->id < action_wrapper2->action->id) {
1190 return 1;
1191 }
1192 return 0;
1193 }
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203 static bool
1204 ordering_can_change_actions(pe_action_wrapper_t *ordering)
1205 {
1206 return pcmk_any_flags_set(ordering->type, ~(pe_order_implies_first_printed
1207 |pe_order_implies_then_printed
1208 |pe_order_optional));
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222 static bool
1223 check_dump_input(pe_action_t *action, pe_action_wrapper_t *input)
1224 {
1225 if (input->state == pe_link_dumped) {
1226 return true;
1227 }
1228
1229 if (input->type == pe_order_none) {
1230 crm_trace("Ignoring %s (%d) input %s (%d): "
1231 "ordering disabled",
1232 action->uuid, action->id,
1233 input->action->uuid, input->action->id);
1234 return false;
1235
1236 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1237 && !ordering_can_change_actions(input)
1238 && !pcmk__str_eq(input->action->uuid, CRM_OP_PROBED, pcmk__str_casei)) {
1239 crm_trace("Ignoring %s (%d) input %s (%d): "
1240 "optional and input unrunnable",
1241 action->uuid, action->id,
1242 input->action->uuid, input->action->id);
1243 return false;
1244
1245 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1246 && pcmk_is_set(input->type, pe_order_one_or_more)) {
1247 crm_trace("Ignoring %s (%d) input %s (%d): "
1248 "one-or-more and input unrunnable",
1249 action->uuid, action->id,
1250 input->action->uuid, input->action->id);
1251 return false;
1252
1253 } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1254 && pcmk_is_set(input->type, pe_order_stonith_stop)) {
1255 crm_trace("Ignoring %s (%d) input %s (%d): "
1256 "stonith stop but action is pseudo",
1257 action->uuid, action->id,
1258 input->action->uuid, input->action->id);
1259 return false;
1260
1261 } else if (pcmk_is_set(input->type, pe_order_implies_first_migratable)
1262 && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
1263 crm_trace("Ignoring %s (%d) input %s (%d): "
1264 "implies input migratable but input unrunnable",
1265 action->uuid, action->id,
1266 input->action->uuid, input->action->id);
1267 return false;
1268
1269 } else if (pcmk_is_set(input->type, pe_order_apply_first_non_migratable)
1270 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)) {
1271 crm_trace("Ignoring %s (%d) input %s (%d): "
1272 "only if input unmigratable but input unrunnable",
1273 action->uuid, action->id,
1274 input->action->uuid, input->action->id);
1275 return false;
1276
1277 } else if ((input->type == pe_order_optional)
1278 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)
1279 && pcmk__ends_with(input->action->uuid, "_stop_0")) {
1280 crm_trace("Ignoring %s (%d) input %s (%d): "
1281 "optional but stop in migration",
1282 action->uuid, action->id,
1283 input->action->uuid, input->action->id);
1284 return false;
1285
1286 } else if (input->type == pe_order_load) {
1287 pe_node_t *input_node = input->action->node;
1288
1289
1290
1291 if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
1292 pe_node_t *allocated = action->rsc->allocated_to;
1293
1294
1295
1296
1297 if ((input_node == NULL) || (allocated == NULL)
1298 || (input_node->details != allocated->details)) {
1299 crm_trace("Ignoring %s (%d) input %s (%d): "
1300 "load ordering node mismatch %s vs %s",
1301 action->uuid, action->id,
1302 input->action->uuid, input->action->id,
1303 (allocated? allocated->details->uname : "<none>"),
1304 (input_node? input_node->details->uname : "<none>"));
1305 input->type = pe_order_none;
1306 return false;
1307 }
1308
1309 } else if ((input_node == NULL) || (action->node == NULL)
1310 || (input_node->details != action->node->details)) {
1311 crm_trace("Ignoring %s (%d) input %s (%d): "
1312 "load ordering node mismatch %s vs %s",
1313 action->uuid, action->id,
1314 input->action->uuid, input->action->id,
1315 (action->node? action->node->details->uname : "<none>"),
1316 (input_node? input_node->details->uname : "<none>"));
1317 input->type = pe_order_none;
1318 return false;
1319
1320 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1321 crm_trace("Ignoring %s (%d) input %s (%d): "
1322 "load ordering input optional",
1323 action->uuid, action->id,
1324 input->action->uuid, input->action->id);
1325 input->type = pe_order_none;
1326 return false;
1327 }
1328
1329 } else if (input->type == pe_order_anti_colocation) {
1330 if (input->action->node && action->node
1331 && (input->action->node->details != action->node->details)) {
1332 crm_trace("Ignoring %s (%d) input %s (%d): "
1333 "anti-colocation node mismatch %s vs %s",
1334 action->uuid, action->id,
1335 input->action->uuid, input->action->id,
1336 action->node->details->uname,
1337 input->action->node->details->uname);
1338 input->type = pe_order_none;
1339 return false;
1340
1341 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1342 crm_trace("Ignoring %s (%d) input %s (%d): "
1343 "anti-colocation input optional",
1344 action->uuid, action->id,
1345 input->action->uuid, input->action->id);
1346 input->type = pe_order_none;
1347 return false;
1348 }
1349
1350 } else if (input->action->rsc
1351 && input->action->rsc != action->rsc
1352 && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
1353 && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
1354 && pcmk__ends_with(input->action->uuid, "_stop_0")
1355 && action->rsc && pe_rsc_is_clone(action->rsc)) {
1356 crm_warn("Ignoring requirement that %s complete before %s:"
1357 " unmanaged failed resources cannot prevent clone shutdown",
1358 input->action->uuid, action->uuid);
1359 return false;
1360
1361 } else if (pcmk_is_set(input->action->flags, pe_action_optional)
1362 && !pcmk_any_flags_set(input->action->flags,
1363 pe_action_print_always|pe_action_dumped)
1364 && !should_dump_action(input->action)) {
1365 crm_trace("Ignoring %s (%d) input %s (%d): "
1366 "input optional",
1367 action->uuid, action->id,
1368 input->action->uuid, input->action->id);
1369 return false;
1370 }
1371
1372 crm_trace("%s (%d) input %s %s (%d) on %s should be dumped: %s %s 0x%.6x",
1373 action->uuid, action->id, action_type_str(input->action->flags),
1374 input->action->uuid, input->action->id,
1375 action_node_str(input->action),
1376 action_runnable_str(input->action->flags),
1377 action_optional_str(input->action->flags), input->type);
1378 return true;
1379 }
1380
1381 bool
1382 pcmk__graph_has_loop(pe_action_t *init_action, pe_action_t *action,
1383 pe_action_wrapper_t *input)
1384 {
1385 bool has_loop = false;
1386
1387 if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
1388 crm_trace("Breaking tracking loop: %s@%s -> %s@%s (0x%.6x)",
1389 input->action->uuid,
1390 input->action->node? input->action->node->details->uname : "",
1391 action->uuid,
1392 action->node? action->node->details->uname : "",
1393 input->type);
1394 return false;
1395 }
1396
1397
1398 if (!check_dump_input(action, input)) {
1399 return false;
1400 }
1401
1402 if (input->action == init_action) {
1403 crm_debug("Input loop found in %s@%s ->...-> %s@%s",
1404 action->uuid,
1405 action->node? action->node->details->uname : "",
1406 init_action->uuid,
1407 init_action->node? init_action->node->details->uname : "");
1408 return true;
1409 }
1410
1411 pe__set_action_flags(input->action, pe_action_tracking);
1412
1413 crm_trace("Checking inputs of action %s@%s input %s@%s (0x%.6x)"
1414 "for graph loop with %s@%s ",
1415 action->uuid,
1416 action->node? action->node->details->uname : "",
1417 input->action->uuid,
1418 input->action->node? input->action->node->details->uname : "",
1419 input->type,
1420 init_action->uuid,
1421 init_action->node? init_action->node->details->uname : "");
1422
1423
1424 for (GList *iter = input->action->actions_before;
1425 iter != NULL; iter = iter->next) {
1426
1427 if (pcmk__graph_has_loop(init_action, input->action,
1428 (pe_action_wrapper_t *) iter->data)) {
1429
1430 has_loop = true;
1431 goto done;
1432 }
1433 }
1434
1435 done:
1436 pe__clear_action_flags(input->action, pe_action_tracking);
1437
1438 if (!has_loop) {
1439 crm_trace("No input loop found in %s@%s -> %s@%s (0x%.6x)",
1440 input->action->uuid,
1441 input->action->node? input->action->node->details->uname : "",
1442 action->uuid,
1443 action->node? action->node->details->uname : "",
1444 input->type);
1445 }
1446 return has_loop;
1447 }
1448
1449
1450 static void
1451 deduplicate_inputs(pe_action_t *action)
1452 {
1453 GList *item = NULL;
1454 GList *next = NULL;
1455 pe_action_wrapper_t *last_input = NULL;
1456
1457 action->actions_before = g_list_sort(action->actions_before,
1458 sort_action_id);
1459 for (item = action->actions_before; item != NULL; item = next) {
1460 pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1461
1462 next = item->next;
1463 if (last_input && (input->action->id == last_input->action->id)) {
1464 crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1465 input->action->uuid, input->action->id,
1466 action->uuid, action->id);
1467
1468
1469
1470
1471
1472 last_input->type |= input->type;
1473 if (input->state == pe_link_dumped) {
1474 last_input->state = pe_link_dumped;
1475 }
1476
1477 free(item->data);
1478 action->actions_before = g_list_delete_link(action->actions_before,
1479 item);
1480 } else {
1481 last_input = input;
1482 input->state = pe_link_not_dumped;
1483 }
1484 }
1485 }
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503 void
1504 graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
1505 {
1506 GList *lpc = NULL;
1507 int synapse_priority = 0;
1508 xmlNode *syn = NULL;
1509 xmlNode *set = NULL;
1510 xmlNode *in = NULL;
1511 xmlNode *xml_action = NULL;
1512 pe_action_wrapper_t *input = NULL;
1513
1514
1515
1516
1517 if (!pcmk_is_set(action->flags, pe_action_dedup)) {
1518 deduplicate_inputs(action);
1519 pe__set_action_flags(action, pe_action_dedup);
1520 }
1521
1522 if (should_dump_action(action) == FALSE) {
1523 return;
1524 }
1525
1526 pe__set_action_flags(action, pe_action_dumped);
1527
1528 syn = create_xml_node(data_set->graph, "synapse");
1529 set = create_xml_node(syn, "action_set");
1530 in = create_xml_node(syn, "inputs");
1531
1532 crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
1533 data_set->num_synapse++;
1534
1535 if (action->rsc != NULL) {
1536 synapse_priority = action->rsc->priority;
1537 }
1538 if (action->priority > synapse_priority) {
1539 synapse_priority = action->priority;
1540 }
1541 if (synapse_priority > 0) {
1542 crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
1543 }
1544
1545 xml_action = action2xml(action, FALSE, data_set);
1546 add_node_nocopy(set, crm_element_name(xml_action), xml_action);
1547
1548 for (lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
1549 input = (pe_action_wrapper_t *) lpc->data;
1550 if (check_dump_input(action, input)) {
1551 xmlNode *input_xml = create_xml_node(in, "trigger");
1552
1553 input->state = pe_link_dumped;
1554 xml_action = action2xml(input->action, TRUE, data_set);
1555 add_node_nocopy(input_xml, crm_element_name(xml_action), xml_action);
1556 }
1557 }
1558 }