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