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