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