This source file includes following definitions.
- add_node_to_xml_by_id
- add_node_to_xml
- add_maintenance_nodes
- add_maintenance_update
- add_downed_nodes
- clone_op_key
- add_node_details
- add_resource_details
- add_action_attributes
- create_graph_action
- should_add_action_to_graph
- ordering_can_change_actions
- should_add_input_to_graph
- pcmk__graph_has_loop
- create_graph_synapse
- add_action_to_graph
- pcmk__log_transition_summary
- pcmk__add_rsc_actions_to_graph
- pcmk__create_graph
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
25
26 #define action_type_str(flags) \
27 (pcmk_is_set((flags), pe_action_pseudo)? "pseudo-action" : "action")
28
29 #define action_optional_str(flags) \
30 (pcmk_is_set((flags), pe_action_optional)? "optional" : "required")
31
32 #define action_runnable_str(flags) \
33 (pcmk_is_set((flags), pe_action_runnable)? "runnable" : "unrunnable")
34
35 #define action_node_str(a) \
36 (((a)->node == NULL)? "no node" : (a)->node->details->uname)
37
38
39
40
41
42
43
44
45 static xmlNode*
46 add_node_to_xml_by_id(const char *id, xmlNode *xml)
47 {
48 xmlNode *node_xml;
49
50 node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
51 crm_xml_add(node_xml, XML_ATTR_ID, id);
52
53 return node_xml;
54 }
55
56
57
58
59
60
61
62
63 static void
64 add_node_to_xml(const pe_node_t *node, void *xml)
65 {
66 add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
67 }
68
69
70
71
72
73
74
75
76 static int
77 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
78 {
79 GList *gIter = NULL;
80 xmlNode *maintenance =
81 xml?create_xml_node(xml, XML_GRAPH_TAG_MAINTENANCE):NULL;
82 int count = 0;
83
84 for (gIter = data_set->nodes; gIter != NULL;
85 gIter = gIter->next) {
86 pe_node_t *node = (pe_node_t *) gIter->data;
87 struct pe_node_shared_s *details = node->details;
88
89 if (!pe__is_guest_or_remote_node(node)) {
90 continue;
91 }
92
93 if (details->maintenance != details->remote_maintenance) {
94 if (maintenance) {
95 crm_xml_add(
96 add_node_to_xml_by_id(node->details->id, maintenance),
97 XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
98 }
99 count++;
100 }
101 }
102 crm_trace("%s %d nodes to adjust maintenance-mode "
103 "to transition", maintenance?"Added":"Counted", count);
104 return count;
105 }
106
107
108
109
110
111
112
113 static void
114 add_maintenance_update(pe_working_set_t *data_set)
115 {
116 pe_action_t *action = NULL;
117
118 if (add_maintenance_nodes(NULL, data_set)) {
119 crm_trace("adding maintenance state update pseudo action");
120 action = get_pseudo_op(CRM_OP_MAINTENANCE_NODES, data_set);
121 pe__set_action_flags(action, pe_action_print_always);
122 }
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137 static void
138 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
139 const pe_working_set_t *data_set)
140 {
141 CRM_CHECK(xml && action && action->node && data_set, return);
142
143 if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
144
145
146 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
147 add_node_to_xml_by_id(action->node->details->id, downed);
148
149 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
150
151
152 const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
153
154 if (pcmk__is_fencing_action(fence)) {
155 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
156 add_node_to_xml_by_id(action->node->details->id, downed);
157 pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
158 }
159
160 } else if (action->rsc && action->rsc->is_remote_node
161 && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
162
163
164
165
166 GList *iter;
167 pe_action_t *input;
168 gboolean migrating = FALSE;
169
170 for (iter = action->actions_before; iter != NULL; iter = iter->next) {
171 input = ((pe_action_wrapper_t *) iter->data)->action;
172 if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
173 && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
174 migrating = TRUE;
175 break;
176 }
177 }
178 if (!migrating) {
179 xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
180 add_node_to_xml_by_id(action->rsc->id, downed);
181 }
182 }
183 }
184
185
186
187
188
189
190
191
192
193
194 static char *
195 clone_op_key(const pe_action_t *action, guint interval_ms)
196 {
197 if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_none)) {
198 const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
199 const char *n_task = g_hash_table_lookup(action->meta,
200 "notify_operation");
201
202 CRM_LOG_ASSERT((n_type != NULL) && (n_task != NULL));
203 return pcmk__notify_key(action->rsc->clone_name, n_type, n_task);
204
205 } else if (action->cancel_task != NULL) {
206 return pcmk__op_key(action->rsc->clone_name, action->cancel_task,
207 interval_ms);
208 } else {
209 return pcmk__op_key(action->rsc->clone_name, action->task, interval_ms);
210 }
211 }
212
213
214
215
216
217
218
219
220 static void
221 add_node_details(const pe_action_t *action, xmlNode *xml)
222 {
223 pe_node_t *router_node = pcmk__connection_host_for_action(action);
224
225 crm_xml_add(xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
226 crm_xml_add(xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
227 if (router_node != NULL) {
228 crm_xml_add(xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
229 }
230 }
231
232
233
234
235
236
237
238
239 static void
240 add_resource_details(const pe_action_t *action, xmlNode *action_xml)
241 {
242 xmlNode *rsc_xml = NULL;
243 const char *attr_list[] = {
244 XML_AGENT_ATTR_CLASS,
245 XML_AGENT_ATTR_PROVIDER,
246 XML_ATTR_TYPE
247 };
248
249
250
251
252 if (pcmk__action_locks_rsc_to_node(action)) {
253 crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
254 (long long) action->rsc->lock_time);
255 }
256
257
258
259 rsc_xml = create_xml_node(action_xml, crm_element_name(action->rsc->xml));
260 if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
261 && (action->rsc->clone_name != NULL)) {
262
263
264
265
266
267
268
269
270 crm_debug("Using orphan clone name %s instead of %s",
271 action->rsc->id, action->rsc->clone_name);
272 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
273 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
274
275 } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
276 const char *xml_id = ID(action->rsc->xml);
277
278 crm_debug("Using anonymous clone name %s for %s (aka %s)",
279 xml_id, action->rsc->id, action->rsc->clone_name);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
295 if ((action->rsc->clone_name != NULL)
296 && !pcmk__str_eq(xml_id, action->rsc->clone_name,
297 pcmk__str_none)) {
298 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
299 } else {
300 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
301 }
302
303 } else {
304 CRM_ASSERT(action->rsc->clone_name == NULL);
305 crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
306 }
307
308 for (int lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
309 crm_xml_add(rsc_xml, attr_list[lpc],
310 g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
311 }
312 }
313
314
315
316
317
318
319
320
321 static void
322 add_action_attributes(pe_action_t *action, xmlNode *action_xml)
323 {
324 xmlNode *args_xml = NULL;
325
326
327
328
329
330 args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
331
332 crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
333 g_hash_table_foreach(action->extra, hash2field, args_xml);
334
335 if ((action->rsc != NULL) && (action->node != NULL)) {
336
337 GHashTable *params = pe_rsc_params(action->rsc, action->node,
338 action->rsc->cluster);
339
340 pcmk__substitute_remote_addr(action->rsc, params);
341
342 g_hash_table_foreach(params, hash2smartfield, args_xml);
343
344 } else if ((action->rsc != NULL) && (action->rsc->variant <= pe_native)) {
345 GHashTable *params = pe_rsc_params(action->rsc, NULL,
346 action->rsc->cluster);
347
348 g_hash_table_foreach(params, hash2smartfield, args_xml);
349 }
350
351 g_hash_table_foreach(action->meta, hash2metafield, args_xml);
352 if (action->rsc != NULL) {
353 pe_resource_t *parent = action->rsc;
354
355 while (parent != NULL) {
356 parent->cmds->add_graph_meta(parent, args_xml);
357 parent = parent->parent;
358 }
359
360 pcmk__add_bundle_meta_to_xml(args_xml, action);
361
362 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_none)
363 && (action->node != NULL)) {
364
365
366
367
368
369
370 g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
371 }
372
373 sorted_xml(args_xml, action_xml, FALSE);
374 free_xml(args_xml);
375 }
376
377
378
379
380
381
382
383
384
385
386 static void
387 create_graph_action(xmlNode *parent, pe_action_t *action, bool skip_details,
388 const pe_working_set_t *data_set)
389 {
390 bool needs_node_info = true;
391 bool needs_maintenance_info = false;
392 xmlNode *action_xml = NULL;
393
394 if ((action == NULL) || (data_set == NULL)) {
395 return;
396 }
397
398
399
400 if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
401
402 action_xml = create_xml_node(parent,
403 pcmk_is_set(action->flags, pe_action_pseudo)?
404 XML_GRAPH_TAG_PSEUDO_EVENT :
405 XML_GRAPH_TAG_CRM_EVENT);
406
407 } else if (pcmk__str_any_of(action->task,
408 CRM_OP_SHUTDOWN,
409 CRM_OP_CLEAR_FAILCOUNT, NULL)) {
410 action_xml = create_xml_node(parent, XML_GRAPH_TAG_CRM_EVENT);
411
412 } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_none)) {
413
414 action_xml = create_xml_node(parent, XML_GRAPH_TAG_CRM_EVENT);
415 crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
416
417 } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
418 if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES,
419 pcmk__str_none)) {
420 needs_maintenance_info = true;
421 }
422 action_xml = create_xml_node(parent, XML_GRAPH_TAG_PSEUDO_EVENT);
423 needs_node_info = false;
424
425 } else {
426 action_xml = create_xml_node(parent, XML_GRAPH_TAG_RSC_OP);
427 }
428
429 crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
430 crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
431
432 if ((action->rsc != NULL) && (action->rsc->clone_name != NULL)) {
433 char *clone_key = NULL;
434 guint interval_ms;
435
436 if (pcmk__guint_from_hash(action->meta, XML_LRM_ATTR_INTERVAL_MS, 0,
437 &interval_ms) != pcmk_rc_ok) {
438 interval_ms = 0;
439 }
440 clone_key = clone_op_key(action, interval_ms);
441 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
442 crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
443 free(clone_key);
444 } else {
445 crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
446 }
447
448 if (needs_node_info && (action->node != NULL)) {
449 add_node_details(action, action_xml);
450 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET),
451 strdup(action->node->details->uname));
452 g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID),
453 strdup(action->node->details->id));
454 }
455
456 if (skip_details) {
457 return;
458 }
459
460 if ((action->rsc != NULL)
461 && !pcmk_is_set(action->flags, pe_action_pseudo)) {
462
463
464 add_resource_details(action, action_xml);
465 }
466
467
468 add_action_attributes(action, action_xml);
469
470
471 if (needs_node_info && (action->node != NULL)) {
472 add_downed_nodes(action_xml, action, data_set);
473 }
474
475 if (needs_maintenance_info) {
476 add_maintenance_nodes(action_xml, data_set);
477 }
478 }
479
480
481
482
483
484
485
486
487
488 static bool
489 should_add_action_to_graph(const pe_action_t *action)
490 {
491 if (!pcmk_is_set(action->flags, pe_action_runnable)) {
492 crm_trace("Ignoring action %s (%d): unrunnable",
493 action->uuid, action->id);
494 return false;
495 }
496
497 if (pcmk_is_set(action->flags, pe_action_optional)
498 && !pcmk_is_set(action->flags, pe_action_print_always)) {
499 crm_trace("Ignoring action %s (%d): optional",
500 action->uuid, action->id);
501 return false;
502 }
503
504
505
506
507 if ((action->rsc != NULL)
508 && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
509 && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_none)) {
510 const char *interval_ms_s;
511
512
513
514
515
516
517 interval_ms_s = g_hash_table_lookup(action->meta,
518 XML_LRM_ATTR_INTERVAL_MS);
519 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
520 crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
521 action->uuid, action->id, action->rsc->id);
522 return false;
523 }
524 }
525
526
527
528
529 if (pcmk_is_set(action->flags, pe_action_pseudo)
530 || pcmk__strcase_any_of(action->task, CRM_OP_FENCE, CRM_OP_SHUTDOWN,
531 NULL)) {
532 return true;
533 }
534
535 if (action->node == NULL) {
536 pe_err("Skipping action %s (%d) "
537 "because it was not allocated to a node (bug?)",
538 action->uuid, action->id);
539 pcmk__log_action("Unallocated", action, false);
540 return false;
541 }
542
543 if (pcmk_is_set(action->flags, pe_action_dc)) {
544 crm_trace("Action %s (%d) should be dumped: "
545 "can run on DC instead of %s",
546 action->uuid, action->id, pe__node_name(action->node));
547
548 } else if (pe__is_guest_node(action->node)
549 && !action->node->details->remote_requires_reset) {
550 crm_trace("Action %s (%d) should be dumped: "
551 "assuming will be runnable on guest %s",
552 action->uuid, action->id, pe__node_name(action->node));
553
554 } else if (!action->node->details->online) {
555 pe_err("Skipping action %s (%d) "
556 "because it was scheduled for offline node (bug?)",
557 action->uuid, action->id);
558 pcmk__log_action("Offline node", action, false);
559 return false;
560
561 } else if (action->node->details->unclean) {
562 pe_err("Skipping action %s (%d) "
563 "because it was scheduled for unclean node (bug?)",
564 action->uuid, action->id);
565 pcmk__log_action("Unclean node", action, false);
566 return false;
567 }
568 return true;
569 }
570
571
572
573
574
575
576
577
578
579 static bool
580 ordering_can_change_actions(const pe_action_wrapper_t *ordering)
581 {
582 return pcmk_any_flags_set(ordering->type, ~(pe_order_implies_first_printed
583 |pe_order_implies_then_printed
584 |pe_order_optional));
585 }
586
587
588
589
590
591
592
593
594
595
596
597
598 static bool
599 should_add_input_to_graph(const pe_action_t *action, pe_action_wrapper_t *input)
600 {
601 if (input->state == pe_link_dumped) {
602 return true;
603 }
604
605 if (input->type == pe_order_none) {
606 crm_trace("Ignoring %s (%d) input %s (%d): "
607 "ordering disabled",
608 action->uuid, action->id,
609 input->action->uuid, input->action->id);
610 return false;
611
612 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
613 && !ordering_can_change_actions(input)) {
614 crm_trace("Ignoring %s (%d) input %s (%d): "
615 "optional and input unrunnable",
616 action->uuid, action->id,
617 input->action->uuid, input->action->id);
618 return false;
619
620 } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
621 && pcmk_is_set(input->type, pe_order_one_or_more)) {
622 crm_trace("Ignoring %s (%d) input %s (%d): "
623 "one-or-more and input unrunnable",
624 action->uuid, action->id,
625 input->action->uuid, input->action->id);
626 return false;
627
628 } else if (pcmk_is_set(input->type, pe_order_implies_first_migratable)
629 && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
630 crm_trace("Ignoring %s (%d) input %s (%d): "
631 "implies input migratable but input unrunnable",
632 action->uuid, action->id,
633 input->action->uuid, input->action->id);
634 return false;
635
636 } else if (pcmk_is_set(input->type, pe_order_apply_first_non_migratable)
637 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)) {
638 crm_trace("Ignoring %s (%d) input %s (%d): "
639 "only if input unmigratable but input unrunnable",
640 action->uuid, action->id,
641 input->action->uuid, input->action->id);
642 return false;
643
644 } else if ((input->type == pe_order_optional)
645 && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)
646 && pcmk__ends_with(input->action->uuid, "_stop_0")) {
647 crm_trace("Ignoring %s (%d) input %s (%d): "
648 "optional but stop in migration",
649 action->uuid, action->id,
650 input->action->uuid, input->action->id);
651 return false;
652
653 } else if (input->type == pe_order_load) {
654 pe_node_t *input_node = input->action->node;
655
656
657
658 if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
659 pe_node_t *allocated = action->rsc->allocated_to;
660
661
662
663
664 if ((input_node == NULL) || (allocated == NULL)
665 || (input_node->details != allocated->details)) {
666 crm_trace("Ignoring %s (%d) input %s (%d): "
667 "load ordering node mismatch %s vs %s",
668 action->uuid, action->id,
669 input->action->uuid, input->action->id,
670 (allocated? allocated->details->uname : "<none>"),
671 (input_node? input_node->details->uname : "<none>"));
672 input->type = pe_order_none;
673 return false;
674 }
675
676 } else if ((input_node == NULL) || (action->node == NULL)
677 || (input_node->details != action->node->details)) {
678 crm_trace("Ignoring %s (%d) input %s (%d): "
679 "load ordering node mismatch %s vs %s",
680 action->uuid, action->id,
681 input->action->uuid, input->action->id,
682 (action->node? action->node->details->uname : "<none>"),
683 (input_node? input_node->details->uname : "<none>"));
684 input->type = pe_order_none;
685 return false;
686
687 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
688 crm_trace("Ignoring %s (%d) input %s (%d): "
689 "load ordering input optional",
690 action->uuid, action->id,
691 input->action->uuid, input->action->id);
692 input->type = pe_order_none;
693 return false;
694 }
695
696 } else if (input->type == pe_order_anti_colocation) {
697 if (input->action->node && action->node
698 && (input->action->node->details != action->node->details)) {
699 crm_trace("Ignoring %s (%d) input %s (%d): "
700 "anti-colocation node mismatch %s vs %s",
701 action->uuid, action->id,
702 input->action->uuid, input->action->id,
703 pe__node_name(action->node),
704 pe__node_name(input->action->node));
705 input->type = pe_order_none;
706 return false;
707
708 } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
709 crm_trace("Ignoring %s (%d) input %s (%d): "
710 "anti-colocation input optional",
711 action->uuid, action->id,
712 input->action->uuid, input->action->id);
713 input->type = pe_order_none;
714 return false;
715 }
716
717 } else if (input->action->rsc
718 && input->action->rsc != action->rsc
719 && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
720 && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
721 && pcmk__ends_with(input->action->uuid, "_stop_0")
722 && action->rsc && pe_rsc_is_clone(action->rsc)) {
723 crm_warn("Ignoring requirement that %s complete before %s:"
724 " unmanaged failed resources cannot prevent clone shutdown",
725 input->action->uuid, action->uuid);
726 return false;
727
728 } else if (pcmk_is_set(input->action->flags, pe_action_optional)
729 && !pcmk_any_flags_set(input->action->flags,
730 pe_action_print_always|pe_action_dumped)
731 && !should_add_action_to_graph(input->action)) {
732 crm_trace("Ignoring %s (%d) input %s (%d): "
733 "input optional",
734 action->uuid, action->id,
735 input->action->uuid, input->action->id);
736 return false;
737 }
738
739 crm_trace("%s (%d) input %s %s (%d) on %s should be dumped: %s %s %#.6x",
740 action->uuid, action->id, action_type_str(input->action->flags),
741 input->action->uuid, input->action->id,
742 action_node_str(input->action),
743 action_runnable_str(input->action->flags),
744 action_optional_str(input->action->flags), input->type);
745 return true;
746 }
747
748
749
750
751
752
753
754
755
756
757
758
759
760 bool
761 pcmk__graph_has_loop(const pe_action_t *init_action, const pe_action_t *action,
762 pe_action_wrapper_t *input)
763 {
764 bool has_loop = false;
765
766 if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
767 crm_trace("Breaking tracking loop: %s@%s -> %s@%s (%#.6x)",
768 input->action->uuid,
769 input->action->node? input->action->node->details->uname : "",
770 action->uuid,
771 action->node? action->node->details->uname : "",
772 input->type);
773 return false;
774 }
775
776
777 if (!should_add_input_to_graph(action, input)) {
778 return false;
779 }
780
781 if (input->action == init_action) {
782 crm_debug("Input loop found in %s@%s ->...-> %s@%s",
783 action->uuid,
784 action->node? action->node->details->uname : "",
785 init_action->uuid,
786 init_action->node? init_action->node->details->uname : "");
787 return true;
788 }
789
790 pe__set_action_flags(input->action, pe_action_tracking);
791
792 crm_trace("Checking inputs of action %s@%s input %s@%s (%#.6x)"
793 "for graph loop with %s@%s ",
794 action->uuid,
795 action->node? action->node->details->uname : "",
796 input->action->uuid,
797 input->action->node? input->action->node->details->uname : "",
798 input->type,
799 init_action->uuid,
800 init_action->node? init_action->node->details->uname : "");
801
802
803 for (GList *iter = input->action->actions_before;
804 iter != NULL; iter = iter->next) {
805
806 if (pcmk__graph_has_loop(init_action, input->action,
807 (pe_action_wrapper_t *) iter->data)) {
808
809 has_loop = true;
810 break;
811 }
812 }
813
814 pe__clear_action_flags(input->action, pe_action_tracking);
815
816 if (!has_loop) {
817 crm_trace("No input loop found in %s@%s -> %s@%s (%#.6x)",
818 input->action->uuid,
819 input->action->node? input->action->node->details->uname : "",
820 action->uuid,
821 action->node? action->node->details->uname : "",
822 input->type);
823 }
824 return has_loop;
825 }
826
827
828
829
830
831
832
833
834
835
836 static xmlNode *
837 create_graph_synapse(const pe_action_t *action, pe_working_set_t *data_set)
838 {
839 int synapse_priority = 0;
840 xmlNode *syn = create_xml_node(data_set->graph, "synapse");
841
842 crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
843 data_set->num_synapse++;
844
845 if (action->rsc != NULL) {
846 synapse_priority = action->rsc->priority;
847 }
848 if (action->priority > synapse_priority) {
849 synapse_priority = action->priority;
850 }
851 if (synapse_priority > 0) {
852 crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
853 }
854 return syn;
855 }
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873 static void
874 add_action_to_graph(gpointer data, gpointer user_data)
875 {
876 pe_action_t *action = (pe_action_t *) data;
877 pe_working_set_t *data_set = (pe_working_set_t *) user_data;
878
879 xmlNode *syn = NULL;
880 xmlNode *set = NULL;
881 xmlNode *in = NULL;
882
883
884
885
886
887 if (!pcmk_is_set(action->flags, pe_action_dedup)) {
888 pcmk__deduplicate_action_inputs(action);
889 pe__set_action_flags(action, pe_action_dedup);
890 }
891
892 if (pcmk_is_set(action->flags, pe_action_dumped)
893 || !should_add_action_to_graph(action)) {
894 return;
895 }
896 pe__set_action_flags(action, pe_action_dumped);
897
898 crm_trace("Adding action %d (%s%s%s) to graph",
899 action->id, action->uuid,
900 ((action->node == NULL)? "" : " on "),
901 ((action->node == NULL)? "" : action->node->details->uname));
902
903 syn = create_graph_synapse(action, data_set);
904 set = create_xml_node(syn, "action_set");
905 in = create_xml_node(syn, "inputs");
906
907 create_graph_action(set, action, false, data_set);
908
909 for (GList *lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
910 pe_action_wrapper_t *input = (pe_action_wrapper_t *) lpc->data;
911
912 if (should_add_input_to_graph(action, input)) {
913 xmlNode *input_xml = create_xml_node(in, "trigger");
914
915 input->state = pe_link_dumped;
916 create_graph_action(input_xml, input->action, true, data_set);
917 }
918 }
919 }
920
921 static int transition_id = -1;
922
923
924
925
926
927
928
929 void
930 pcmk__log_transition_summary(const char *filename)
931 {
932 if (was_processing_error) {
933 crm_err("Calculated transition %d (with errors)%s%s",
934 transition_id,
935 (filename == NULL)? "" : ", saving inputs in ",
936 (filename == NULL)? "" : filename);
937
938 } else if (was_processing_warning) {
939 crm_warn("Calculated transition %d (with warnings)%s%s",
940 transition_id,
941 (filename == NULL)? "" : ", saving inputs in ",
942 (filename == NULL)? "" : filename);
943
944 } else {
945 crm_notice("Calculated transition %d%s%s",
946 transition_id,
947 (filename == NULL)? "" : ", saving inputs in ",
948 (filename == NULL)? "" : filename);
949 }
950 if (crm_config_error) {
951 crm_notice("Configuration errors found during scheduler processing,"
952 " please run \"crm_verify -L\" to identify issues");
953 }
954 }
955
956
957
958
959
960
961
962 void
963 pcmk__add_rsc_actions_to_graph(pe_resource_t *rsc)
964 {
965 GList *iter = NULL;
966
967 CRM_ASSERT(rsc != NULL);
968 pe_rsc_trace(rsc, "Adding actions for %s to graph", rsc->id);
969
970
971 g_list_foreach(rsc->actions, add_action_to_graph, rsc->cluster);
972
973
974 for (iter = rsc->children; iter != NULL; iter = iter->next) {
975 pe_resource_t *child_rsc = (pe_resource_t *) iter->data;
976
977 child_rsc->cmds->add_actions_to_graph(child_rsc);
978 }
979 }
980
981
982
983
984
985
986
987 void
988 pcmk__create_graph(pe_working_set_t *data_set)
989 {
990 GList *iter = NULL;
991 const char *value = NULL;
992 long long limit = 0LL;
993
994 transition_id++;
995 crm_trace("Creating transition graph %d", transition_id);
996
997 data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
998
999 value = pe_pref(data_set->config_hash, "cluster-delay");
1000 crm_xml_add(data_set->graph, "cluster-delay", value);
1001
1002 value = pe_pref(data_set->config_hash, "stonith-timeout");
1003 crm_xml_add(data_set->graph, "stonith-timeout", value);
1004
1005 crm_xml_add(data_set->graph, "failed-stop-offset", "INFINITY");
1006
1007 if (pcmk_is_set(data_set->flags, pe_flag_start_failure_fatal)) {
1008 crm_xml_add(data_set->graph, "failed-start-offset", "INFINITY");
1009 } else {
1010 crm_xml_add(data_set->graph, "failed-start-offset", "1");
1011 }
1012
1013 value = pe_pref(data_set->config_hash, "batch-limit");
1014 crm_xml_add(data_set->graph, "batch-limit", value);
1015
1016 crm_xml_add_int(data_set->graph, "transition_id", transition_id);
1017
1018 value = pe_pref(data_set->config_hash, "migration-limit");
1019 if ((pcmk__scan_ll(value, &limit, 0LL) == pcmk_rc_ok) && (limit > 0)) {
1020 crm_xml_add(data_set->graph, "migration-limit", value);
1021 }
1022
1023 if (data_set->recheck_by > 0) {
1024 char *recheck_epoch = NULL;
1025
1026 recheck_epoch = crm_strdup_printf("%llu",
1027 (long long) data_set->recheck_by);
1028 crm_xml_add(data_set->graph, "recheck-by", recheck_epoch);
1029 free(recheck_epoch);
1030 }
1031
1032
1033
1034
1035
1036
1037
1038 for (iter = data_set->resources; iter != NULL; iter = iter->next) {
1039 pe_resource_t *rsc = (pe_resource_t *) iter->data;
1040
1041 pe_rsc_trace(rsc, "Processing actions for %s", rsc->id);
1042 rsc->cmds->add_actions_to_graph(rsc);
1043 }
1044
1045
1046 add_maintenance_update(data_set);
1047
1048
1049 for (iter = data_set->actions; iter != NULL; iter = iter->next) {
1050 pe_action_t *action = (pe_action_t *) iter->data;
1051
1052 if ((action->rsc != NULL)
1053 && (action->node != NULL)
1054 && action->node->details->shutdown
1055 && !pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)
1056 && !pcmk_any_flags_set(action->flags,
1057 pe_action_optional|pe_action_runnable)
1058 && pcmk__str_eq(action->task, RSC_STOP, pcmk__str_none)) {
1059
1060
1061
1062
1063 if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)
1064 || (data_set->no_quorum_policy == no_quorum_ignore)) {
1065 crm_crit("Cannot %s %s because of %s:%s%s (%s)",
1066 action->node->details->unclean? "fence" : "shut down",
1067 pe__node_name(action->node), action->rsc->id,
1068 pcmk_is_set(action->rsc->flags, pe_rsc_managed)? " blocked" : " unmanaged",
1069 pcmk_is_set(action->rsc->flags, pe_rsc_failed)? " failed" : "",
1070 action->uuid);
1071 }
1072 }
1073
1074 add_action_to_graph((gpointer) action, (gpointer) data_set);
1075 }
1076
1077 crm_log_xml_trace(data_set->graph, "graph");
1078 }