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/common/xml.h>
16
17 #include <glib.h>
18
19 #include <pacemaker-internal.h>
20
21 #include "libpacemaker_private.h"
22
23
24
25 #define action_type_str(flags) \
26 (pcmk_is_set((flags), pcmk_action_pseudo)? "pseudo-action" : "action")
27
28 #define action_optional_str(flags) \
29 (pcmk_is_set((flags), pcmk_action_optional)? "optional" : "required")
30
31 #define action_runnable_str(flags) \
32 (pcmk_is_set((flags), pcmk_action_runnable)? "runnable" : "unrunnable")
33
34 #define action_node_str(a) \
35 (((a)->node == NULL)? "no node" : (a)->node->details->uname)
36
37
38
39
40
41
42
43
44 static xmlNode*
45 add_node_to_xml_by_id(const char *id, xmlNode *xml)
46 {
47 xmlNode *node_xml;
48
49 node_xml = pcmk__xe_create(xml, PCMK_XE_NODE);
50 crm_xml_add(node_xml, PCMK_XA_ID, id);
51
52 return node_xml;
53 }
54
55
56
57
58
59
60
61
62 static void
63 add_node_to_xml(const pcmk_node_t *node, void *xml)
64 {
65 add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
66 }
67
68
69
70
71
72
73
74
75
76
77
78 static int
79 add_maintenance_nodes(xmlNode *xml, const pcmk_scheduler_t *scheduler)
80 {
81 xmlNode *maintenance = NULL;
82 int count = 0;
83
84 if (xml != NULL) {
85 maintenance = pcmk__xe_create(xml, PCMK__XE_MAINTENANCE);
86 }
87 for (const GList *iter = scheduler->nodes;
88 iter != NULL; iter = iter->next) {
89 const pcmk_node_t *node = iter->data;
90
91 if (pcmk__is_pacemaker_remote_node(node) &&
92 (node->details->maintenance != node->details->remote_maintenance)) {
93
94 if (maintenance != NULL) {
95 crm_xml_add(add_node_to_xml_by_id(node->details->id,
96 maintenance),
97 PCMK__XA_NODE_IN_MAINTENANCE,
98 (node->details->maintenance? "1" : "0"));
99 }
100 count++;
101 }
102 }
103 crm_trace("%s %d nodes in need of maintenance mode update in state",
104 ((maintenance == NULL)? "Counted" : "Added"), count);
105 return count;
106 }
107
108
109
110
111
112
113
114 static void
115 add_maintenance_update(pcmk_scheduler_t *scheduler)
116 {
117 pcmk_action_t *action = NULL;
118
119 if (add_maintenance_nodes(NULL, scheduler) != 0) {
120 action = get_pseudo_op(PCMK_ACTION_MAINTENANCE_NODES, scheduler);
121 pcmk__set_action_flags(action, pcmk_action_always_in_graph);
122 }
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136 static void
137 add_downed_nodes(xmlNode *xml, const pcmk_action_t *action)
138 {
139 CRM_CHECK((xml != NULL) && (action != NULL) && (action->node != NULL),
140 return);
141
142 if (pcmk__str_eq(action->task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
143
144
145 xmlNode *downed = pcmk__xe_create(xml, PCMK__XE_DOWNED);
146 add_node_to_xml_by_id(action->node->details->id, downed);
147
148 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
149 pcmk__str_none)) {
150
151
152 const char *fence = g_hash_table_lookup(action->meta,
153 PCMK__META_STONITH_ACTION);
154
155 if (pcmk__is_fencing_action(fence)) {
156 xmlNode *downed = pcmk__xe_create(xml, PCMK__XE_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 = pcmk__xe_create(xml, PCMK__XE_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, PCMK__META_ON_NODE, action->node->details->uname);
231 crm_xml_add(xml, PCMK__META_ON_NODE_UUID, action->node->details->id);
232 if (router_node != NULL) {
233 crm_xml_add(xml, PCMK__XA_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 PCMK_XA_CLASS,
250 PCMK_XA_PROVIDER,
251 PCMK_XA_TYPE,
252 };
253
254
255
256
257
258 if (pcmk__action_locks_rsc_to_node(action)) {
259 crm_xml_add_ll(action_xml, PCMK_OPT_SHUTDOWN_LOCK,
260 (long long) action->rsc->lock_time);
261 }
262
263
264
265 rsc_xml = pcmk__xe_create(action_xml,
266 (const char *) action->rsc->xml->name);
267 if (pcmk_is_set(action->rsc->flags, pcmk_rsc_removed)
268 && (action->rsc->clone_name != NULL)) {
269
270
271
272
273
274
275
276
277 crm_debug("Using orphan clone name %s instead of %s",
278 action->rsc->id, action->rsc->clone_name);
279 crm_xml_add(rsc_xml, PCMK_XA_ID, action->rsc->clone_name);
280 crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->id);
281
282 } else if (!pcmk_is_set(action->rsc->flags, pcmk_rsc_unique)) {
283 const char *xml_id = pcmk__xe_id(action->rsc->xml);
284
285 crm_debug("Using anonymous clone name %s for %s (aka %s)",
286 xml_id, action->rsc->id, action->rsc->clone_name);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 crm_xml_add(rsc_xml, PCMK_XA_ID, xml_id);
302 if ((action->rsc->clone_name != NULL)
303 && !pcmk__str_eq(xml_id, action->rsc->clone_name,
304 pcmk__str_none)) {
305 crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->clone_name);
306 } else {
307 crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->id);
308 }
309
310 } else {
311 CRM_ASSERT(action->rsc->clone_name == NULL);
312 crm_xml_add(rsc_xml, PCMK_XA_ID, action->rsc->id);
313 }
314
315 for (int lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
316 crm_xml_add(rsc_xml, attr_list[lpc],
317 g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
318 }
319 }
320
321
322
323
324
325
326
327
328 static void
329 add_action_attributes(pcmk_action_t *action, xmlNode *action_xml)
330 {
331 xmlNode *args_xml = NULL;
332
333
334
335
336
337 args_xml = pcmk__xe_create(NULL, PCMK__XE_ATTRIBUTES);
338
339 crm_xml_add(args_xml, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
340 g_hash_table_foreach(action->extra, hash2field, args_xml);
341
342 if ((action->rsc != NULL) && (action->node != NULL)) {
343
344 GHashTable *params = pe_rsc_params(action->rsc, action->node,
345 action->rsc->cluster);
346
347 pcmk__substitute_remote_addr(action->rsc, params);
348
349 g_hash_table_foreach(params, hash2smartfield, args_xml);
350
351 } else if ((action->rsc != NULL)
352 && (action->rsc->variant <= pcmk_rsc_variant_primitive)) {
353 GHashTable *params = pe_rsc_params(action->rsc, NULL,
354 action->rsc->cluster);
355
356 g_hash_table_foreach(params, hash2smartfield, args_xml);
357 }
358
359 g_hash_table_foreach(action->meta, hash2metafield, args_xml);
360 if (action->rsc != NULL) {
361 pcmk_resource_t *parent = action->rsc;
362
363 while (parent != NULL) {
364 parent->cmds->add_graph_meta(parent, args_xml);
365 parent = parent->parent;
366 }
367
368 pcmk__add_guest_meta_to_xml(args_xml, action);
369
370 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH, pcmk__str_none)
371 && (action->node != NULL)) {
372
373
374
375
376
377
378 g_hash_table_foreach(action->node->details->attrs, hash2metafield,
379 args_xml);
380 }
381
382 sorted_xml(args_xml, action_xml, FALSE);
383 free_xml(args_xml);
384 }
385
386
387
388
389
390
391
392
393
394
395 static void
396 create_graph_action(xmlNode *parent, pcmk_action_t *action, bool skip_details,
397 const pcmk_scheduler_t *scheduler)
398 {
399 bool needs_node_info = true;
400 bool needs_maintenance_info = false;
401 xmlNode *action_xml = NULL;
402
403 if ((action == NULL) || (scheduler == NULL)) {
404 return;
405 }
406
407
408
409 if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH, pcmk__str_none)) {
410
411 if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
412 action_xml = pcmk__xe_create(parent, PCMK__XE_PSEUDO_EVENT);
413 } else {
414 action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
415 }
416
417 } else if (pcmk__str_any_of(action->task,
418 PCMK_ACTION_DO_SHUTDOWN,
419 PCMK_ACTION_CLEAR_FAILCOUNT, NULL)) {
420 action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
421
422 } else if (pcmk__str_eq(action->task, PCMK_ACTION_LRM_DELETE,
423 pcmk__str_none)) {
424
425 action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
426 crm_xml_add(action_xml, PCMK__XA_MODE, PCMK__VALUE_CIB);
427
428 } else if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
429 if (pcmk__str_eq(action->task, PCMK_ACTION_MAINTENANCE_NODES,
430 pcmk__str_none)) {
431 needs_maintenance_info = true;
432 }
433 action_xml = pcmk__xe_create(parent, PCMK__XE_PSEUDO_EVENT);
434 needs_node_info = false;
435
436 } else {
437 action_xml = pcmk__xe_create(parent, PCMK__XE_RSC_OP);
438 }
439
440 crm_xml_add_int(action_xml, PCMK_XA_ID, action->id);
441 crm_xml_add(action_xml, PCMK_XA_OPERATION, action->task);
442
443 if ((action->rsc != NULL) && (action->rsc->clone_name != NULL)) {
444 char *clone_key = NULL;
445 guint interval_ms;
446
447 if (pcmk__guint_from_hash(action->meta, PCMK_META_INTERVAL, 0,
448 &interval_ms) != pcmk_rc_ok) {
449 interval_ms = 0;
450 }
451 clone_key = clone_op_key(action, interval_ms);
452 crm_xml_add(action_xml, PCMK__XA_OPERATION_KEY, clone_key);
453 crm_xml_add(action_xml, "internal_" PCMK__XA_OPERATION_KEY,
454 action->uuid);
455 free(clone_key);
456 } else {
457 crm_xml_add(action_xml, PCMK__XA_OPERATION_KEY, action->uuid);
458 }
459
460 if (needs_node_info && (action->node != NULL)) {
461 add_node_details(action, action_xml);
462 pcmk__insert_dup(action->meta, PCMK__META_ON_NODE,
463 action->node->details->uname);
464 pcmk__insert_dup(action->meta, PCMK__META_ON_NODE_UUID,
465 action->node->details->id);
466 }
467
468 if (skip_details) {
469 return;
470 }
471
472 if ((action->rsc != NULL)
473 && !pcmk_is_set(action->flags, pcmk_action_pseudo)) {
474
475
476 add_resource_details(action, action_xml);
477 }
478
479
480 add_action_attributes(action, action_xml);
481
482
483 if (needs_node_info && (action->node != NULL)) {
484 add_downed_nodes(action_xml, action);
485 }
486
487 if (needs_maintenance_info) {
488 add_maintenance_nodes(action_xml, scheduler);
489 }
490 }
491
492
493
494
495
496
497
498
499
500 static bool
501 should_add_action_to_graph(const pcmk_action_t *action)
502 {
503 if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
504 crm_trace("Ignoring action %s (%d): unrunnable",
505 action->uuid, action->id);
506 return false;
507 }
508
509 if (pcmk_is_set(action->flags, pcmk_action_optional)
510 && !pcmk_is_set(action->flags, pcmk_action_always_in_graph)) {
511 crm_trace("Ignoring action %s (%d): optional",
512 action->uuid, action->id);
513 return false;
514 }
515
516
517
518
519 if ((action->rsc != NULL)
520 && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
521 && !pcmk__str_eq(action->task, PCMK_ACTION_MONITOR, pcmk__str_none)) {
522
523 const char *interval_ms_s;
524
525
526
527
528
529
530 interval_ms_s = g_hash_table_lookup(action->meta, PCMK_META_INTERVAL);
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 pcmk__sched_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, pcmk__node_name(action->node));
559
560 } else if (pcmk__is_guest_or_bundle_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, pcmk__node_name(action->node));
565
566 } else if (!action->node->details->online) {
567 pcmk__sched_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 pcmk__sched_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 (!pcmk__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 (!pcmk__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 && !pcmk__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 pcmk__node_name(action->node),
718 pcmk__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 && pcmk__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 pcmk__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 pcmk__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 = pcmk__xe_create(scheduler->graph, "synapse");
855
856 crm_xml_add_int(syn, PCMK_XA_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, PCMK__XA_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 pcmk__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 pcmk__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 = pcmk__xe_create(syn, "action_set");
919 in = pcmk__xe_create(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 = pcmk__xe_create(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 || crm_config_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 || crm_config_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 pcmk__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 GHashTable *config_hash = scheduler->config_hash;
1008
1009 transition_id++;
1010 crm_trace("Creating transition graph %d", transition_id);
1011
1012 scheduler->graph = pcmk__xe_create(NULL, PCMK__XE_TRANSITION_GRAPH);
1013
1014 value = pcmk__cluster_option(config_hash, PCMK_OPT_CLUSTER_DELAY);
1015 crm_xml_add(scheduler->graph, PCMK_OPT_CLUSTER_DELAY, value);
1016
1017 value = pcmk__cluster_option(config_hash, PCMK_OPT_STONITH_TIMEOUT);
1018 crm_xml_add(scheduler->graph, PCMK_OPT_STONITH_TIMEOUT, value);
1019
1020 crm_xml_add(scheduler->graph, "failed-stop-offset", "INFINITY");
1021
1022 if (pcmk_is_set(scheduler->flags, pcmk_sched_start_failure_fatal)) {
1023 crm_xml_add(scheduler->graph, "failed-start-offset", "INFINITY");
1024 } else {
1025 crm_xml_add(scheduler->graph, "failed-start-offset", "1");
1026 }
1027
1028 value = pcmk__cluster_option(config_hash, PCMK_OPT_BATCH_LIMIT);
1029 crm_xml_add(scheduler->graph, PCMK_OPT_BATCH_LIMIT, value);
1030
1031 crm_xml_add_int(scheduler->graph, "transition_id", transition_id);
1032
1033 value = pcmk__cluster_option(config_hash, PCMK_OPT_MIGRATION_LIMIT);
1034 if ((pcmk__scan_ll(value, &limit, 0LL) == pcmk_rc_ok) && (limit > 0)) {
1035 crm_xml_add(scheduler->graph, PCMK_OPT_MIGRATION_LIMIT, value);
1036 }
1037
1038 if (scheduler->recheck_by > 0) {
1039 char *recheck_epoch = NULL;
1040
1041 recheck_epoch = crm_strdup_printf("%llu",
1042 (long long) scheduler->recheck_by);
1043 crm_xml_add(scheduler->graph, "recheck-by", recheck_epoch);
1044 free(recheck_epoch);
1045 }
1046
1047
1048
1049
1050
1051
1052
1053 for (iter = scheduler->resources; iter != NULL; iter = iter->next) {
1054 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1055
1056 pcmk__rsc_trace(rsc, "Processing actions for %s", rsc->id);
1057 rsc->cmds->add_actions_to_graph(rsc);
1058 }
1059
1060
1061 add_maintenance_update(scheduler);
1062
1063
1064 for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
1065 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1066
1067 if ((action->rsc != NULL)
1068 && (action->node != NULL)
1069 && action->node->details->shutdown
1070 && !pcmk_is_set(action->rsc->flags, pcmk_rsc_maintenance)
1071 && !pcmk_any_flags_set(action->flags,
1072 pcmk_action_optional|pcmk_action_runnable)
1073 && pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_none)) {
1074
1075
1076
1077
1078 if (pcmk_is_set(scheduler->flags, pcmk_sched_quorate)
1079 || (scheduler->no_quorum_policy == pcmk_no_quorum_ignore)) {
1080 const bool managed = pcmk_is_set(action->rsc->flags,
1081 pcmk_rsc_managed);
1082 const bool failed = pcmk_is_set(action->rsc->flags,
1083 pcmk_rsc_failed);
1084
1085 crm_crit("Cannot %s %s because of %s:%s%s (%s)",
1086 action->node->details->unclean? "fence" : "shut down",
1087 pcmk__node_name(action->node), action->rsc->id,
1088 (managed? " blocked" : " unmanaged"),
1089 (failed? " failed" : ""), action->uuid);
1090 }
1091 }
1092
1093 add_action_to_graph((gpointer) action, (gpointer) scheduler);
1094 }
1095
1096 crm_log_xml_trace(scheduler->graph, "graph");
1097 }