This source file includes following definitions.
- invert_action
- get_ordering_type
- get_ordering_symmetry
- ordering_flags_for_kind
- get_ordering_resource
- get_minimum_first_instances
- clone_min_ordering
- inverse_ordering
- unpack_simple_rsc_order
- pcmk__new_ordering
- unpack_order_set
- order_rsc_sets
- unpack_order_tags
- pcmk__unpack_ordering
- ordering_is_invalid
- pcmk__disable_invalid_orderings
- pcmk__order_stops_before_shutdown
- find_actions_by_task
- order_resource_actions_after
- rsc_order_first
- block_colocation_dependents
- update_action_for_orderings
- pcmk__apply_orderings
- pcmk__order_after_each
- pcmk__promotable_restart_ordering
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <inttypes.h>
13 #include <stdbool.h>
14 #include <glib.h>
15
16 #include <crm/crm.h>
17 #include <pacemaker-internal.h>
18 #include "libpacemaker_private.h"
19
20 enum pe_order_kind {
21 pe_order_kind_optional,
22 pe_order_kind_mandatory,
23 pe_order_kind_serialize,
24 };
25
26 enum ordering_symmetry {
27 ordering_asymmetric,
28 ordering_symmetric,
29 ordering_symmetric_inverse,
30 };
31
32 #define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
33 __rsc = pcmk__find_constraint_resource(scheduler->resources, \
34 __name); \
35 if (__rsc == NULL) { \
36 pcmk__config_err("%s: No resource found for %s", __set, __name);\
37 return pcmk_rc_unpack_error; \
38 } \
39 } while (0)
40
41 static const char *
42 invert_action(const char *action)
43 {
44 if (pcmk__str_eq(action, PCMK_ACTION_START, pcmk__str_none)) {
45 return PCMK_ACTION_STOP;
46
47 } else if (pcmk__str_eq(action, PCMK_ACTION_STOP, pcmk__str_none)) {
48 return PCMK_ACTION_START;
49
50 } else if (pcmk__str_eq(action, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
51 return PCMK_ACTION_DEMOTE;
52
53 } else if (pcmk__str_eq(action, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
54 return PCMK_ACTION_PROMOTE;
55
56 } else if (pcmk__str_eq(action, PCMK_ACTION_PROMOTED, pcmk__str_none)) {
57 return PCMK_ACTION_DEMOTED;
58
59 } else if (pcmk__str_eq(action, PCMK_ACTION_DEMOTED, pcmk__str_none)) {
60 return PCMK_ACTION_PROMOTED;
61
62 } else if (pcmk__str_eq(action, PCMK_ACTION_RUNNING, pcmk__str_none)) {
63 return PCMK_ACTION_STOPPED;
64
65 } else if (pcmk__str_eq(action, PCMK_ACTION_STOPPED, pcmk__str_none)) {
66 return PCMK_ACTION_RUNNING;
67 }
68 crm_warn("Unknown action '%s' specified in order constraint", action);
69 return NULL;
70 }
71
72 static enum pe_order_kind
73 get_ordering_type(const xmlNode *xml_obj)
74 {
75 enum pe_order_kind kind_e = pe_order_kind_mandatory;
76 const char *kind = crm_element_value(xml_obj, XML_ORDER_ATTR_KIND);
77
78 if (kind == NULL) {
79 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
80
81 kind_e = pe_order_kind_mandatory;
82
83 if (score) {
84
85 int score_i = char2score(score);
86
87 if (score_i == 0) {
88 kind_e = pe_order_kind_optional;
89 }
90 pe_warn_once(pcmk__wo_order_score,
91 "Support for 'score' in rsc_order is deprecated "
92 "and will be removed in a future release "
93 "(use 'kind' instead)");
94 }
95
96 } else if (pcmk__str_eq(kind, "Mandatory", pcmk__str_none)) {
97 kind_e = pe_order_kind_mandatory;
98
99 } else if (pcmk__str_eq(kind, "Optional", pcmk__str_none)) {
100 kind_e = pe_order_kind_optional;
101
102 } else if (pcmk__str_eq(kind, "Serialize", pcmk__str_none)) {
103 kind_e = pe_order_kind_serialize;
104
105 } else {
106 pcmk__config_err("Resetting '" XML_ORDER_ATTR_KIND "' for constraint "
107 "%s to 'Mandatory' because '%s' is not valid",
108 pcmk__s(ID(xml_obj), "missing ID"), kind);
109 }
110 return kind_e;
111 }
112
113
114
115
116
117
118
119
120
121
122
123
124 static enum ordering_symmetry
125 get_ordering_symmetry(const xmlNode *xml_obj, enum pe_order_kind parent_kind,
126 const char *parent_symmetrical_s)
127 {
128 int rc = pcmk_rc_ok;
129 bool symmetric = false;
130 enum pe_order_kind kind = parent_kind;
131
132
133 if ((crm_element_value(xml_obj, XML_ORDER_ATTR_KIND) != NULL)
134 || (crm_element_value(xml_obj, XML_RULE_ATTR_SCORE) != NULL)) {
135 kind = get_ordering_type(xml_obj);
136 }
137
138
139 rc = pcmk__xe_get_bool_attr(xml_obj, XML_CONS_ATTR_SYMMETRICAL, &symmetric);
140
141 if (rc != pcmk_rc_ok && parent_symmetrical_s != NULL) {
142 symmetric = crm_is_true(parent_symmetrical_s);
143 rc = pcmk_rc_ok;
144 }
145
146 if (rc == pcmk_rc_ok) {
147 if (symmetric) {
148 if (kind == pe_order_kind_serialize) {
149 pcmk__config_warn("Ignoring " XML_CONS_ATTR_SYMMETRICAL
150 " for '%s' because not valid with "
151 XML_ORDER_ATTR_KIND " of 'Serialize'",
152 ID(xml_obj));
153 } else {
154 return ordering_symmetric;
155 }
156 }
157 return ordering_asymmetric;
158 }
159
160
161 if (kind == pe_order_kind_serialize) {
162 return ordering_asymmetric;
163 }
164 return ordering_symmetric;
165 }
166
167
168
169
170
171
172
173
174
175
176
177 static uint32_t
178 ordering_flags_for_kind(enum pe_order_kind kind, const char *first,
179 enum ordering_symmetry symmetry)
180 {
181 uint32_t flags = pcmk__ar_none;
182
183 switch (kind) {
184 case pe_order_kind_optional:
185 pe__set_order_flags(flags, pcmk__ar_ordered);
186 break;
187
188 case pe_order_kind_serialize:
189
190
191
192
193 pe__set_order_flags(flags, pcmk__ar_serialize);
194 break;
195
196 case pe_order_kind_mandatory:
197 pe__set_order_flags(flags, pcmk__ar_ordered);
198 switch (symmetry) {
199 case ordering_asymmetric:
200 pe__set_order_flags(flags, pcmk__ar_asymmetric);
201 break;
202
203 case ordering_symmetric:
204 pe__set_order_flags(flags, pcmk__ar_first_implies_then);
205 if (pcmk__strcase_any_of(first, PCMK_ACTION_START,
206 PCMK_ACTION_PROMOTE, NULL)) {
207 pe__set_order_flags(flags,
208 pcmk__ar_unrunnable_first_blocks);
209 }
210 break;
211
212 case ordering_symmetric_inverse:
213 pe__set_order_flags(flags, pcmk__ar_then_implies_first);
214 break;
215 }
216 break;
217 }
218 return flags;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 static pcmk_resource_t *
235 get_ordering_resource(const xmlNode *xml, const char *resource_attr,
236 const char *instance_attr,
237 const pcmk_scheduler_t *scheduler)
238 {
239
240 pcmk_resource_t *rsc = NULL;
241 const char *rsc_id = crm_element_value(xml, resource_attr);
242 const char *instance_id = crm_element_value(xml, instance_attr);
243
244 if (rsc_id == NULL) {
245 pcmk__config_err("Ignoring constraint '%s' without %s",
246 ID(xml), resource_attr);
247 return NULL;
248 }
249
250 rsc = pcmk__find_constraint_resource(scheduler->resources, rsc_id);
251 if (rsc == NULL) {
252 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
253 "does not exist", ID(xml), rsc_id);
254 return NULL;
255 }
256
257 if (instance_id != NULL) {
258 pe_warn_once(pcmk__wo_order_inst,
259 "Support for " XML_ORDER_ATTR_FIRST_INSTANCE " and "
260 XML_ORDER_ATTR_THEN_INSTANCE " is deprecated and will be "
261 "removed in a future release.");
262
263 if (!pe_rsc_is_clone(rsc)) {
264 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
265 "is not a clone but instance '%s' was requested",
266 ID(xml), rsc_id, instance_id);
267 return NULL;
268 }
269 rsc = find_clone_instance(rsc, instance_id);
270 if (rsc == NULL) {
271 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
272 "does not have an instance '%s'",
273 "'%s'", ID(xml), rsc_id, instance_id);
274 return NULL;
275 }
276 }
277 return rsc;
278 }
279
280
281
282
283
284
285
286
287
288
289 static int
290 get_minimum_first_instances(const pcmk_resource_t *rsc, const xmlNode *xml)
291 {
292 const char *clone_min = NULL;
293 bool require_all = false;
294
295 if (!pe_rsc_is_clone(rsc)) {
296 return 0;
297 }
298
299 clone_min = g_hash_table_lookup(rsc->meta, PCMK_META_CLONE_MIN);
300 if (clone_min != NULL) {
301 int clone_min_int = 0;
302
303 pcmk__scan_min_int(clone_min, &clone_min_int, 0);
304 return clone_min_int;
305 }
306
307
308
309
310 if (pcmk__xe_get_bool_attr(xml, "require-all", &require_all) != ENODATA) {
311 pe_warn_once(pcmk__wo_require_all,
312 "Support for require-all in ordering constraints "
313 "is deprecated and will be removed in a future release"
314 " (use clone-min clone meta-attribute instead)");
315 if (!require_all) {
316 return 1;
317 }
318 }
319
320 return 0;
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335 static void
336 clone_min_ordering(const char *id,
337 pcmk_resource_t *rsc_first, const char *action_first,
338 pcmk_resource_t *rsc_then, const char *action_then,
339 uint32_t flags, int clone_min)
340 {
341
342 char *task = crm_strdup_printf(PCMK_ACTION_CLONE_ONE_OR_MORE ":%s", id);
343 pcmk_action_t *clone_min_met = get_pseudo_op(task, rsc_first->cluster);
344
345 free(task);
346
347
348
349
350 clone_min_met->required_runnable_before = clone_min;
351 pe__set_action_flags(clone_min_met, pcmk_action_min_runnable);
352
353
354 for (GList *iter = rsc_first->children; iter != NULL; iter = iter->next) {
355 pcmk_resource_t *child = iter->data;
356
357 pcmk__new_ordering(child, pcmk__op_key(child->id, action_first, 0),
358 NULL, NULL, NULL, clone_min_met,
359 pcmk__ar_min_runnable
360 |pcmk__ar_first_implies_then_graphed,
361 rsc_first->cluster);
362 }
363
364
365 pcmk__new_ordering(NULL, NULL, clone_min_met, rsc_then,
366 pcmk__op_key(rsc_then->id, action_then, 0),
367 NULL, flags|pcmk__ar_unrunnable_first_blocks,
368 rsc_first->cluster);
369 }
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 #define handle_restart_type(rsc, kind, flag, flags) do { \
385 if (((kind) == pe_order_kind_optional) \
386 && ((rsc)->restart_type == pe_restart_restart)) { \
387 pe__set_order_flags((flags), (flag)); \
388 } \
389 } while (0)
390
391
392
393
394
395
396
397
398
399
400
401
402 static void
403 inverse_ordering(const char *id, enum pe_order_kind kind,
404 pcmk_resource_t *rsc_first, const char *action_first,
405 pcmk_resource_t *rsc_then, const char *action_then)
406 {
407 action_then = invert_action(action_then);
408 action_first = invert_action(action_first);
409 if ((action_then == NULL) || (action_first == NULL)) {
410 pcmk__config_warn("Cannot invert constraint '%s' "
411 "(please specify inverse manually)", id);
412 } else {
413 uint32_t flags = ordering_flags_for_kind(kind, action_first,
414 ordering_symmetric_inverse);
415
416 handle_restart_type(rsc_then, kind, pcmk__ar_then_implies_first, flags);
417 pcmk__order_resource_actions(rsc_then, action_then, rsc_first,
418 action_first, flags);
419 }
420 }
421
422 static void
423 unpack_simple_rsc_order(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
424 {
425 pcmk_resource_t *rsc_then = NULL;
426 pcmk_resource_t *rsc_first = NULL;
427 int min_required_before = 0;
428 enum pe_order_kind kind = pe_order_kind_mandatory;
429 uint32_t flags = pcmk__ar_none;
430 enum ordering_symmetry symmetry;
431
432 const char *action_then = NULL;
433 const char *action_first = NULL;
434 const char *id = NULL;
435
436 CRM_CHECK(xml_obj != NULL, return);
437
438 id = crm_element_value(xml_obj, XML_ATTR_ID);
439 if (id == NULL) {
440 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
441 xml_obj->name);
442 return;
443 }
444
445 rsc_first = get_ordering_resource(xml_obj, XML_ORDER_ATTR_FIRST,
446 XML_ORDER_ATTR_FIRST_INSTANCE,
447 scheduler);
448 if (rsc_first == NULL) {
449 return;
450 }
451
452 rsc_then = get_ordering_resource(xml_obj, XML_ORDER_ATTR_THEN,
453 XML_ORDER_ATTR_THEN_INSTANCE,
454 scheduler);
455 if (rsc_then == NULL) {
456 return;
457 }
458
459 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
460 if (action_first == NULL) {
461 action_first = PCMK_ACTION_START;
462 }
463
464 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
465 if (action_then == NULL) {
466 action_then = action_first;
467 }
468
469 kind = get_ordering_type(xml_obj);
470
471 symmetry = get_ordering_symmetry(xml_obj, kind, NULL);
472 flags = ordering_flags_for_kind(kind, action_first, symmetry);
473
474 handle_restart_type(rsc_then, kind, pcmk__ar_first_implies_then, flags);
475
476
477
478
479
480
481 min_required_before = get_minimum_first_instances(rsc_first, xml_obj);
482 if (min_required_before > 0) {
483 clone_min_ordering(id, rsc_first, action_first, rsc_then, action_then,
484 flags, min_required_before);
485 } else {
486 pcmk__order_resource_actions(rsc_first, action_first, rsc_then,
487 action_then, flags);
488 }
489
490 if (symmetry == ordering_symmetric) {
491 inverse_ordering(id, kind, rsc_first, action_first,
492 rsc_then, action_then);
493 }
494 }
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 void
525 pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_action_task,
526 pcmk_action_t *first_action, pcmk_resource_t *then_rsc,
527 char *then_action_task, pcmk_action_t *then_action,
528 uint32_t flags, pcmk_scheduler_t *sched)
529 {
530 pe__ordering_t *order = NULL;
531
532
533 CRM_CHECK(((first_action != NULL) || (first_rsc != NULL))
534 && ((then_action != NULL) || (then_rsc != NULL)),
535 free(first_action_task); free(then_action_task); return);
536
537 if ((first_rsc == NULL) && (first_action != NULL)) {
538 first_rsc = first_action->rsc;
539 }
540 if ((then_rsc == NULL) && (then_action != NULL)) {
541 then_rsc = then_action->rsc;
542 }
543
544 order = calloc(1, sizeof(pe__ordering_t));
545 CRM_ASSERT(order != NULL);
546
547 order->id = sched->order_id++;
548 order->flags = flags;
549 order->lh_rsc = first_rsc;
550 order->rh_rsc = then_rsc;
551 order->lh_action = first_action;
552 order->rh_action = then_action;
553 order->lh_action_task = first_action_task;
554 order->rh_action_task = then_action_task;
555
556 if ((order->lh_action_task == NULL) && (first_action != NULL)) {
557 order->lh_action_task = strdup(first_action->uuid);
558 }
559
560 if ((order->rh_action_task == NULL) && (then_action != NULL)) {
561 order->rh_action_task = strdup(then_action->uuid);
562 }
563
564 if ((order->lh_rsc == NULL) && (first_action != NULL)) {
565 order->lh_rsc = first_action->rsc;
566 }
567
568 if ((order->rh_rsc == NULL) && (then_action != NULL)) {
569 order->rh_rsc = then_action->rsc;
570 }
571
572 pe_rsc_trace(first_rsc, "Created ordering %d for %s then %s",
573 (sched->order_id - 1),
574 pcmk__s(order->lh_action_task, "an underspecified action"),
575 pcmk__s(order->rh_action_task, "an underspecified action"));
576
577 sched->ordering_constraints = g_list_prepend(sched->ordering_constraints,
578 order);
579 pcmk__order_migration_equivalents(order);
580 }
581
582
583
584
585
586
587
588
589
590
591
592 static int
593 unpack_order_set(const xmlNode *set, enum pe_order_kind parent_kind,
594 const char *parent_symmetrical_s, pcmk_scheduler_t *scheduler)
595 {
596 GList *set_iter = NULL;
597 GList *resources = NULL;
598
599 pcmk_resource_t *last = NULL;
600 pcmk_resource_t *resource = NULL;
601
602 int local_kind = parent_kind;
603 bool sequential = false;
604 uint32_t flags = pcmk__ar_ordered;
605 enum ordering_symmetry symmetry;
606
607 char *key = NULL;
608 const char *id = ID(set);
609 const char *action = crm_element_value(set, "action");
610 const char *sequential_s = crm_element_value(set, "sequential");
611 const char *kind_s = crm_element_value(set, XML_ORDER_ATTR_KIND);
612
613 if (action == NULL) {
614 action = PCMK_ACTION_START;
615 }
616
617 if (kind_s) {
618 local_kind = get_ordering_type(set);
619 }
620 if (sequential_s == NULL) {
621 sequential_s = "1";
622 }
623
624 sequential = crm_is_true(sequential_s);
625
626 symmetry = get_ordering_symmetry(set, parent_kind, parent_symmetrical_s);
627 flags = ordering_flags_for_kind(local_kind, action, symmetry);
628
629 for (const xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
630 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
631
632 EXPAND_CONSTRAINT_IDREF(id, resource, ID(xml_rsc));
633 resources = g_list_append(resources, resource);
634 }
635
636 if (pcmk__list_of_1(resources)) {
637 crm_trace("Single set: %s", id);
638 goto done;
639 }
640
641 set_iter = resources;
642 while (set_iter != NULL) {
643 resource = (pcmk_resource_t *) set_iter->data;
644 set_iter = set_iter->next;
645
646 key = pcmk__op_key(resource->id, action, 0);
647
648 if (local_kind == pe_order_kind_serialize) {
649
650
651 for (GList *iter = set_iter; iter != NULL; iter = iter->next) {
652 pcmk_resource_t *then_rsc = iter->data;
653 char *then_key = pcmk__op_key(then_rsc->id, action, 0);
654
655 pcmk__new_ordering(resource, strdup(key), NULL, then_rsc,
656 then_key, NULL, flags, scheduler);
657 }
658
659 } else if (sequential) {
660 if (last != NULL) {
661 pcmk__order_resource_actions(last, action, resource, action,
662 flags);
663 }
664 last = resource;
665 }
666 free(key);
667 }
668
669 if (symmetry == ordering_asymmetric) {
670 goto done;
671 }
672
673 last = NULL;
674 action = invert_action(action);
675
676 flags = ordering_flags_for_kind(local_kind, action,
677 ordering_symmetric_inverse);
678
679 set_iter = resources;
680 while (set_iter != NULL) {
681 resource = (pcmk_resource_t *) set_iter->data;
682 set_iter = set_iter->next;
683
684 if (sequential) {
685 if (last != NULL) {
686 pcmk__order_resource_actions(resource, action, last, action,
687 flags);
688 }
689 last = resource;
690 }
691 }
692
693 done:
694 g_list_free(resources);
695 return pcmk_rc_ok;
696 }
697
698
699
700
701
702
703
704
705
706
707
708
709
710 static int
711 order_rsc_sets(const char *id, const xmlNode *set1, const xmlNode *set2,
712 enum pe_order_kind kind, pcmk_scheduler_t *scheduler,
713 enum ordering_symmetry symmetry)
714 {
715
716 const xmlNode *xml_rsc = NULL;
717 const xmlNode *xml_rsc_2 = NULL;
718
719 pcmk_resource_t *rsc_1 = NULL;
720 pcmk_resource_t *rsc_2 = NULL;
721
722 const char *action_1 = crm_element_value(set1, "action");
723 const char *action_2 = crm_element_value(set2, "action");
724
725 uint32_t flags = pcmk__ar_none;
726
727 bool require_all = true;
728
729 (void) pcmk__xe_get_bool_attr(set1, "require-all", &require_all);
730
731 if (action_1 == NULL) {
732 action_1 = PCMK_ACTION_START;
733 }
734
735 if (action_2 == NULL) {
736 action_2 = PCMK_ACTION_START;
737 }
738
739 if (symmetry == ordering_symmetric_inverse) {
740 action_1 = invert_action(action_1);
741 action_2 = invert_action(action_2);
742 }
743
744 if (pcmk__str_eq(PCMK_ACTION_STOP, action_1, pcmk__str_none)
745 || pcmk__str_eq(PCMK_ACTION_DEMOTE, action_1, pcmk__str_none)) {
746
747
748
749
750
751 require_all = true;
752 }
753
754 flags = ordering_flags_for_kind(kind, action_1, symmetry);
755
756
757
758
759 if (!require_all) {
760 char *task = crm_strdup_printf(PCMK_ACTION_ONE_OR_MORE ":%s", ID(set1));
761 pcmk_action_t *unordered_action = get_pseudo_op(task, scheduler);
762
763 free(task);
764 pe__set_action_flags(unordered_action, pcmk_action_min_runnable);
765
766 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
767 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
768
769 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
770
771
772
773
774
775 pcmk__new_ordering(rsc_1, pcmk__op_key(rsc_1->id, action_1, 0),
776 NULL, NULL, NULL, unordered_action,
777 pcmk__ar_min_runnable
778 |pcmk__ar_first_implies_then_graphed,
779 scheduler);
780 }
781 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
782 xml_rsc_2 != NULL; xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
783
784 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
785
786
787
788
789
790 pcmk__new_ordering(NULL, NULL, unordered_action,
791 rsc_2, pcmk__op_key(rsc_2->id, action_2, 0),
792 NULL, flags|pcmk__ar_unrunnable_first_blocks,
793 scheduler);
794 }
795
796 return pcmk_rc_ok;
797 }
798
799 if (pcmk__xe_attr_is_true(set1, "sequential")) {
800 if (symmetry == ordering_symmetric_inverse) {
801
802 xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
803 if (xml_rsc != NULL) {
804 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
805 }
806
807 } else {
808
809 const char *rid = NULL;
810
811 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
812 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
813
814 rid = ID(xml_rsc);
815 }
816 EXPAND_CONSTRAINT_IDREF(id, rsc_1, rid);
817 }
818 }
819
820 if (pcmk__xe_attr_is_true(set2, "sequential")) {
821 if (symmetry == ordering_symmetric_inverse) {
822
823 const char *rid = NULL;
824
825 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
826 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
827
828 rid = ID(xml_rsc);
829 }
830 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
831
832 } else {
833
834 xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
835 if (xml_rsc != NULL) {
836 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
837 }
838 }
839 }
840
841 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
842 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2, flags);
843
844 } else if (rsc_1 != NULL) {
845 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
846 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
847
848 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
849 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2,
850 flags);
851 }
852
853 } else if (rsc_2 != NULL) {
854 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
855 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
856
857 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
858 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2,
859 flags);
860 }
861
862 } else {
863 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
864 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
865
866 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
867
868 for (xmlNode *xml_rsc_2 = first_named_child(set2,
869 XML_TAG_RESOURCE_REF);
870 xml_rsc_2 != NULL; xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
871
872 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
873 pcmk__order_resource_actions(rsc_1, action_1, rsc_2,
874 action_2, flags);
875 }
876 }
877 }
878
879 return pcmk_rc_ok;
880 }
881
882
883
884
885
886
887
888
889
890
891
892
893 static int
894 unpack_order_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
895 const pcmk_scheduler_t *scheduler)
896 {
897 const char *id_first = NULL;
898 const char *id_then = NULL;
899 const char *action_first = NULL;
900 const char *action_then = NULL;
901
902 pcmk_resource_t *rsc_first = NULL;
903 pcmk_resource_t *rsc_then = NULL;
904 pcmk_tag_t *tag_first = NULL;
905 pcmk_tag_t *tag_then = NULL;
906
907 xmlNode *rsc_set_first = NULL;
908 xmlNode *rsc_set_then = NULL;
909 bool any_sets = false;
910
911
912 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
913 if (*expanded_xml != NULL) {
914 crm_log_xml_trace(*expanded_xml, "Expanded rsc_order");
915 return pcmk_rc_ok;
916 }
917
918 id_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST);
919 id_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN);
920 if ((id_first == NULL) || (id_then == NULL)) {
921 return pcmk_rc_ok;
922 }
923
924 if (!pcmk__valid_resource_or_tag(scheduler, id_first, &rsc_first,
925 &tag_first)) {
926 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
927 "valid resource or tag", ID(xml_obj), id_first);
928 return pcmk_rc_unpack_error;
929 }
930
931 if (!pcmk__valid_resource_or_tag(scheduler, id_then, &rsc_then,
932 &tag_then)) {
933 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
934 "valid resource or tag", ID(xml_obj), id_then);
935 return pcmk_rc_unpack_error;
936 }
937
938 if ((rsc_first != NULL) && (rsc_then != NULL)) {
939
940 return pcmk_rc_ok;
941 }
942
943 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
944 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
945
946 *expanded_xml = copy_xml(xml_obj);
947
948
949 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set_first, XML_ORDER_ATTR_FIRST,
950 true, scheduler)) {
951 free_xml(*expanded_xml);
952 *expanded_xml = NULL;
953 return pcmk_rc_unpack_error;
954 }
955
956 if (rsc_set_first != NULL) {
957 if (action_first != NULL) {
958
959 crm_xml_add(rsc_set_first, "action", action_first);
960 xml_remove_prop(*expanded_xml, XML_ORDER_ATTR_FIRST_ACTION);
961 }
962 any_sets = true;
963 }
964
965
966 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set_then, XML_ORDER_ATTR_THEN,
967 true, scheduler)) {
968 free_xml(*expanded_xml);
969 *expanded_xml = NULL;
970 return pcmk_rc_unpack_error;
971 }
972
973 if (rsc_set_then != NULL) {
974 if (action_then != NULL) {
975
976 crm_xml_add(rsc_set_then, "action", action_then);
977 xml_remove_prop(*expanded_xml, XML_ORDER_ATTR_THEN_ACTION);
978 }
979 any_sets = true;
980 }
981
982 if (any_sets) {
983 crm_log_xml_trace(*expanded_xml, "Expanded rsc_order");
984 } else {
985 free_xml(*expanded_xml);
986 *expanded_xml = NULL;
987 }
988
989 return pcmk_rc_ok;
990 }
991
992
993
994
995
996
997
998
999 void
1000 pcmk__unpack_ordering(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
1001 {
1002 xmlNode *set = NULL;
1003 xmlNode *last = NULL;
1004
1005 xmlNode *orig_xml = NULL;
1006 xmlNode *expanded_xml = NULL;
1007
1008 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
1009 const char *invert = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL);
1010 enum pe_order_kind kind = get_ordering_type(xml_obj);
1011
1012 enum ordering_symmetry symmetry = get_ordering_symmetry(xml_obj, kind,
1013 NULL);
1014
1015
1016 if (unpack_order_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
1017 return;
1018 }
1019 if (expanded_xml != NULL) {
1020 orig_xml = xml_obj;
1021 xml_obj = expanded_xml;
1022 }
1023
1024
1025 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET);
1026 set != NULL; set = crm_next_same_xml(set)) {
1027
1028 set = expand_idref(set, scheduler->input);
1029 if ((set == NULL)
1030 || (unpack_order_set(set, kind, invert, scheduler) != pcmk_rc_ok)) {
1031
1032 if (expanded_xml != NULL) {
1033 free_xml(expanded_xml);
1034 }
1035 return;
1036 }
1037
1038 if (last != NULL) {
1039
1040 if (order_rsc_sets(id, last, set, kind, scheduler,
1041 symmetry) != pcmk_rc_ok) {
1042 if (expanded_xml != NULL) {
1043 free_xml(expanded_xml);
1044 }
1045 return;
1046 }
1047
1048 if ((symmetry == ordering_symmetric)
1049 && (order_rsc_sets(id, set, last, kind, scheduler,
1050 ordering_symmetric_inverse) != pcmk_rc_ok)) {
1051 if (expanded_xml != NULL) {
1052 free_xml(expanded_xml);
1053 }
1054 return;
1055 }
1056
1057 }
1058 last = set;
1059 }
1060
1061 if (expanded_xml) {
1062 free_xml(expanded_xml);
1063 xml_obj = orig_xml;
1064 }
1065
1066
1067 if (last == NULL) {
1068 return unpack_simple_rsc_order(xml_obj, scheduler);
1069 }
1070 }
1071
1072 static bool
1073 ordering_is_invalid(pcmk_action_t *action, pcmk__related_action_t *input)
1074 {
1075
1076
1077
1078 if (!pcmk_is_set(input->type, pcmk__ar_guest_allowed)
1079 && (input->action->rsc != NULL)
1080 && pcmk__rsc_corresponds_to_guest(action->rsc, input->action->node)) {
1081
1082 crm_warn("Invalid ordering constraint between %s and %s",
1083 input->action->rsc->id, action->rsc->id);
1084 return true;
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094 if (((uint32_t) input->type == pcmk__ar_if_on_same_node_or_target)
1095 && (action->rsc != NULL)
1096 && pcmk__str_eq(action->task, PCMK_ACTION_MIGRATE_TO, pcmk__str_none)
1097 && pcmk__graph_has_loop(action, action, input)) {
1098 return true;
1099 }
1100
1101 return false;
1102 }
1103
1104 void
1105 pcmk__disable_invalid_orderings(pcmk_scheduler_t *scheduler)
1106 {
1107 for (GList *iter = scheduler->actions; iter != NULL; iter = iter->next) {
1108 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1109 pcmk__related_action_t *input = NULL;
1110
1111 for (GList *input_iter = action->actions_before;
1112 input_iter != NULL; input_iter = input_iter->next) {
1113
1114 input = input_iter->data;
1115 if (ordering_is_invalid(action, input)) {
1116 input->type = (enum pe_ordering) pcmk__ar_none;
1117 }
1118 }
1119 }
1120 }
1121
1122
1123
1124
1125
1126
1127
1128
1129 void
1130 pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
1131 {
1132 for (GList *iter = node->details->data_set->actions;
1133 iter != NULL; iter = iter->next) {
1134
1135 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1136
1137
1138 if (!pe__same_node(action->node, node)
1139 || !pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_none)) {
1140 continue;
1141 }
1142
1143
1144
1145 if (pcmk_is_set(action->rsc->flags, pcmk_rsc_maintenance)) {
1146 pe_rsc_trace(action->rsc,
1147 "Not ordering %s before shutdown of %s because "
1148 "resource in maintenance mode",
1149 action->uuid, pe__node_name(node));
1150 continue;
1151
1152 } else if (node->details->maintenance) {
1153 pe_rsc_trace(action->rsc,
1154 "Not ordering %s before shutdown of %s because "
1155 "node in maintenance mode",
1156 action->uuid, pe__node_name(node));
1157 continue;
1158 }
1159
1160
1161
1162
1163
1164 if (!pcmk_any_flags_set(action->rsc->flags,
1165 pcmk_rsc_managed|pcmk_rsc_blocked)) {
1166 pe_rsc_trace(action->rsc,
1167 "Not ordering %s before shutdown of %s because "
1168 "resource is unmanaged or blocked",
1169 action->uuid, pe__node_name(node));
1170 continue;
1171 }
1172
1173 pe_rsc_trace(action->rsc, "Ordering %s before shutdown of %s",
1174 action->uuid, pe__node_name(node));
1175 pe__clear_action_flags(action, pcmk_action_optional);
1176 pcmk__new_ordering(action->rsc, NULL, action, NULL,
1177 strdup(PCMK_ACTION_DO_SHUTDOWN), shutdown_op,
1178 pcmk__ar_ordered|pcmk__ar_unrunnable_first_blocks,
1179 node->details->data_set);
1180 }
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193 static GList *
1194 find_actions_by_task(const pcmk_resource_t *rsc, const char *original_key)
1195 {
1196
1197 GList *list = find_actions(rsc->actions, original_key, NULL);
1198
1199 if (list == NULL) {
1200
1201 char *key = NULL;
1202 char *task = NULL;
1203 guint interval_ms = 0;
1204
1205 if (parse_op_key(original_key, NULL, &task, &interval_ms)) {
1206 key = pcmk__op_key(rsc->id, task, interval_ms);
1207 list = find_actions(rsc->actions, key, NULL);
1208 free(key);
1209 free(task);
1210 } else {
1211 crm_err("Invalid operation key (bug?): %s", original_key);
1212 }
1213 }
1214 return list;
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225 static void
1226 order_resource_actions_after(pcmk_action_t *first_action,
1227 const pcmk_resource_t *rsc, pe__ordering_t *order)
1228 {
1229 GList *then_actions = NULL;
1230 uint32_t flags = pcmk__ar_none;
1231
1232 CRM_CHECK((rsc != NULL) && (order != NULL), return);
1233
1234 flags = order->flags;
1235 pe_rsc_trace(rsc, "Applying ordering %d for 'then' resource %s",
1236 order->id, rsc->id);
1237
1238 if (order->rh_action != NULL) {
1239 then_actions = g_list_prepend(NULL, order->rh_action);
1240
1241 } else {
1242 then_actions = find_actions_by_task(rsc, order->rh_action_task);
1243 }
1244
1245 if (then_actions == NULL) {
1246 pe_rsc_trace(rsc, "Ignoring ordering %d: no %s actions found for %s",
1247 order->id, order->rh_action_task, rsc->id);
1248 return;
1249 }
1250
1251 if ((first_action != NULL) && (first_action->rsc == rsc)
1252 && pcmk_is_set(first_action->flags, pcmk_action_migration_abort)) {
1253
1254 pe_rsc_trace(rsc,
1255 "Detected dangling migration ordering (%s then %s %s)",
1256 first_action->uuid, order->rh_action_task, rsc->id);
1257 pe__clear_order_flags(flags, pcmk__ar_first_implies_then);
1258 }
1259
1260 if ((first_action == NULL)
1261 && !pcmk_is_set(flags, pcmk__ar_first_implies_then)) {
1262
1263 pe_rsc_debug(rsc,
1264 "Ignoring ordering %d for %s: No first action found",
1265 order->id, rsc->id);
1266 g_list_free(then_actions);
1267 return;
1268 }
1269
1270 for (GList *iter = then_actions; iter != NULL; iter = iter->next) {
1271 pcmk_action_t *then_action_iter = (pcmk_action_t *) iter->data;
1272
1273 if (first_action != NULL) {
1274 order_actions(first_action, then_action_iter, flags);
1275 } else {
1276 pe__clear_action_flags(then_action_iter, pcmk_action_runnable);
1277 crm_warn("%s of %s is unrunnable because there is no %s of %s "
1278 "to order it after", then_action_iter->task, rsc->id,
1279 order->lh_action_task, order->lh_rsc->id);
1280 }
1281 }
1282
1283 g_list_free(then_actions);
1284 }
1285
1286 static void
1287 rsc_order_first(pcmk_resource_t *first_rsc, pe__ordering_t *order)
1288 {
1289 GList *first_actions = NULL;
1290 pcmk_action_t *first_action = order->lh_action;
1291 pcmk_resource_t *then_rsc = order->rh_rsc;
1292
1293 CRM_ASSERT(first_rsc != NULL);
1294 pe_rsc_trace(first_rsc, "Applying ordering constraint %d (first: %s)",
1295 order->id, first_rsc->id);
1296
1297 if (first_action != NULL) {
1298 first_actions = g_list_prepend(NULL, first_action);
1299
1300 } else {
1301 first_actions = find_actions_by_task(first_rsc, order->lh_action_task);
1302 }
1303
1304 if ((first_actions == NULL) && (first_rsc == then_rsc)) {
1305 pe_rsc_trace(first_rsc,
1306 "Ignoring constraint %d: first (%s for %s) not found",
1307 order->id, order->lh_action_task, first_rsc->id);
1308
1309 } else if (first_actions == NULL) {
1310 char *key = NULL;
1311 char *op_type = NULL;
1312 guint interval_ms = 0;
1313
1314 parse_op_key(order->lh_action_task, NULL, &op_type, &interval_ms);
1315 key = pcmk__op_key(first_rsc->id, op_type, interval_ms);
1316
1317 if ((first_rsc->fns->state(first_rsc, TRUE) == pcmk_role_stopped)
1318 && pcmk__str_eq(op_type, PCMK_ACTION_STOP, pcmk__str_none)) {
1319 free(key);
1320 pe_rsc_trace(first_rsc,
1321 "Ignoring constraint %d: first (%s for %s) not found",
1322 order->id, order->lh_action_task, first_rsc->id);
1323
1324 } else if ((first_rsc->fns->state(first_rsc,
1325 TRUE) == pcmk_role_unpromoted)
1326 && pcmk__str_eq(op_type, PCMK_ACTION_DEMOTE,
1327 pcmk__str_none)) {
1328 free(key);
1329 pe_rsc_trace(first_rsc,
1330 "Ignoring constraint %d: first (%s for %s) not found",
1331 order->id, order->lh_action_task, first_rsc->id);
1332
1333 } else {
1334 pe_rsc_trace(first_rsc,
1335 "Creating first (%s for %s) for constraint %d ",
1336 order->lh_action_task, first_rsc->id, order->id);
1337 first_action = custom_action(first_rsc, key, op_type, NULL, TRUE,
1338 first_rsc->cluster);
1339 first_actions = g_list_prepend(NULL, first_action);
1340 }
1341
1342 free(op_type);
1343 }
1344
1345 if (then_rsc == NULL) {
1346 if (order->rh_action == NULL) {
1347 pe_rsc_trace(first_rsc, "Ignoring constraint %d: then not found",
1348 order->id);
1349 return;
1350 }
1351 then_rsc = order->rh_action->rsc;
1352 }
1353 for (GList *iter = first_actions; iter != NULL; iter = iter->next) {
1354 first_action = iter->data;
1355
1356 if (then_rsc == NULL) {
1357 order_actions(first_action, order->rh_action, order->flags);
1358
1359 } else {
1360 order_resource_actions_after(first_action, then_rsc, order);
1361 }
1362 }
1363
1364 g_list_free(first_actions);
1365 }
1366
1367
1368 static void
1369 block_colocation_dependents(gpointer data, gpointer user_data)
1370 {
1371 pcmk__block_colocation_dependents(data);
1372 }
1373
1374
1375 static void
1376 update_action_for_orderings(gpointer data, gpointer user_data)
1377 {
1378 pcmk__update_action_for_orderings((pcmk_action_t *) data,
1379 (pcmk_scheduler_t *) user_data);
1380 }
1381
1382
1383
1384
1385
1386
1387
1388 void
1389 pcmk__apply_orderings(pcmk_scheduler_t *sched)
1390 {
1391 crm_trace("Applying ordering constraints");
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405 sched->ordering_constraints = g_list_reverse(sched->ordering_constraints);
1406
1407 for (GList *iter = sched->ordering_constraints;
1408 iter != NULL; iter = iter->next) {
1409
1410 pe__ordering_t *order = iter->data;
1411 pcmk_resource_t *rsc = order->lh_rsc;
1412
1413 if (rsc != NULL) {
1414 rsc_order_first(rsc, order);
1415 continue;
1416 }
1417
1418 rsc = order->rh_rsc;
1419 if (rsc != NULL) {
1420 order_resource_actions_after(order->lh_action, rsc, order);
1421
1422 } else {
1423 crm_trace("Applying ordering constraint %d (non-resource actions)",
1424 order->id);
1425 order_actions(order->lh_action, order->rh_action, order->flags);
1426 }
1427 }
1428
1429 g_list_foreach(sched->actions, block_colocation_dependents, NULL);
1430
1431 crm_trace("Ordering probes");
1432 pcmk__order_probes(sched);
1433
1434 crm_trace("Updating %d actions", g_list_length(sched->actions));
1435 g_list_foreach(sched->actions, update_action_for_orderings, sched);
1436
1437 pcmk__disable_invalid_orderings(sched);
1438 }
1439
1440
1441
1442
1443
1444
1445
1446
1447 void
1448 pcmk__order_after_each(pcmk_action_t *after, GList *list)
1449 {
1450 const char *after_desc = (after->task == NULL)? after->uuid : after->task;
1451
1452 for (GList *iter = list; iter != NULL; iter = iter->next) {
1453 pcmk_action_t *before = (pcmk_action_t *) iter->data;
1454 const char *before_desc = before->task? before->task : before->uuid;
1455
1456 crm_debug("Ordering %s on %s before %s on %s",
1457 before_desc, pe__node_name(before->node),
1458 after_desc, pe__node_name(after->node));
1459 order_actions(before, after, pcmk__ar_ordered);
1460 }
1461 }
1462
1463
1464
1465
1466
1467
1468
1469 void
1470 pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
1471 {
1472
1473 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOPPED,
1474 rsc, PCMK_ACTION_START,
1475 pcmk__ar_ordered);
1476 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOPPED,
1477 rsc, PCMK_ACTION_PROMOTE,
1478 pcmk__ar_ordered);
1479
1480
1481 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTED,
1482 rsc, PCMK_ACTION_STOP,
1483 pcmk__ar_ordered);
1484 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTED,
1485 rsc, PCMK_ACTION_START,
1486 pcmk__ar_ordered);
1487 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTED,
1488 rsc, PCMK_ACTION_PROMOTE,
1489 pcmk__ar_ordered);
1490
1491
1492 pcmk__order_resource_actions(rsc, PCMK_ACTION_RUNNING,
1493 rsc, PCMK_ACTION_PROMOTE,
1494 pcmk__ar_ordered);
1495
1496
1497 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTE,
1498 rsc, PCMK_ACTION_DEMOTED,
1499 pcmk__ar_ordered);
1500 }