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