This source file includes following definitions.
- can_run_instance
- ban_unavailable_allowed_nodes
- new_node_table
- apply_parent_colocations
- cmp_instance_by_colocation
- did_fail
- node_is_allowed
- pcmk__cmp_instance_number
- pcmk__cmp_instance
- increment_parent_count
- assign_instance
- assign_instance_early
- reset_allowed_node_counts
- preferred_node
- pcmk__assign_instances
- check_instance_state
- pcmk__create_instance_actions
- get_instance_list
- free_instance_list
- pcmk__instance_matches
- find_compatible_instance_on_node
- pcmk__find_compatible_instance
- unassign_if_mandatory
- find_instance_action
- orig_action_name
- update_interleaved_actions
- can_interleave_actions
- update_noninterleaved_actions
- pcmk__instance_update_ordered_actions
- pcmk__collective_action_flags
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <crm_internal.h>
15 #include <crm/common/xml.h>
16 #include <pacemaker-internal.h>
17 #include "libpacemaker_private.h"
18
19
20
21
22
23
24
25
26
27
28
29 static bool
30 can_run_instance(const pcmk_resource_t *instance, const pcmk_node_t *node,
31 int max_per_node)
32 {
33 pcmk_node_t *allowed_node = NULL;
34
35 if (pcmk_is_set(instance->flags, pcmk_rsc_removed)) {
36 pcmk__rsc_trace(instance, "%s cannot run on %s: orphaned",
37 instance->id, pcmk__node_name(node));
38 return false;
39 }
40
41 if (!pcmk__node_available(node, false, false)) {
42 pcmk__rsc_trace(instance,
43 "%s cannot run on %s: node cannot run resources",
44 instance->id, pcmk__node_name(node));
45 return false;
46 }
47
48 allowed_node = pcmk__top_allowed_node(instance, node);
49 if (allowed_node == NULL) {
50 crm_warn("%s cannot run on %s: node not allowed",
51 instance->id, pcmk__node_name(node));
52 return false;
53 }
54
55 if (allowed_node->weight < 0) {
56 pcmk__rsc_trace(instance,
57 "%s cannot run on %s: parent score is %s there",
58 instance->id, pcmk__node_name(node),
59 pcmk_readable_score(allowed_node->weight));
60 return false;
61 }
62
63 if (allowed_node->count >= max_per_node) {
64 pcmk__rsc_trace(instance,
65 "%s cannot run on %s: node already has %d instance%s",
66 instance->id, pcmk__node_name(node), max_per_node,
67 pcmk__plural_s(max_per_node));
68 return false;
69 }
70
71 pcmk__rsc_trace(instance, "%s can run on %s (%d already running)",
72 instance->id, pcmk__node_name(node), allowed_node->count);
73 return true;
74 }
75
76
77
78
79
80
81
82
83 static void
84 ban_unavailable_allowed_nodes(pcmk_resource_t *instance, int max_per_node)
85 {
86 if (instance->allowed_nodes != NULL) {
87 GHashTableIter iter;
88 pcmk_node_t *node = NULL;
89
90 g_hash_table_iter_init(&iter, instance->allowed_nodes);
91 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
92 if (!can_run_instance(instance, node, max_per_node)) {
93 pcmk__rsc_trace(instance, "Banning %s from unavailable node %s",
94 instance->id, pcmk__node_name(node));
95 node->weight = -PCMK_SCORE_INFINITY;
96 for (GList *child_iter = instance->children;
97 child_iter != NULL; child_iter = child_iter->next) {
98 pcmk_resource_t *child = child_iter->data;
99 pcmk_node_t *child_node = NULL;
100
101 child_node = g_hash_table_lookup(child->allowed_nodes,
102 node->details->id);
103 if (child_node != NULL) {
104 pcmk__rsc_trace(instance,
105 "Banning %s child %s "
106 "from unavailable node %s",
107 instance->id, child->id,
108 pcmk__node_name(node));
109 child_node->weight = -PCMK_SCORE_INFINITY;
110 }
111 }
112 }
113 }
114 }
115 }
116
117
118
119
120
121
122
123
124
125
126
127 static GHashTable *
128 new_node_table(pcmk_node_t *node)
129 {
130 GHashTable *table = pcmk__strkey_table(NULL, free);
131
132 node = pe__copy_node(node);
133 g_hash_table_insert(table, (gpointer) node->details->id, node);
134 return table;
135 }
136
137
138
139
140
141
142
143
144 static void
145 apply_parent_colocations(const pcmk_resource_t *rsc, GHashTable **nodes)
146 {
147 GList *colocations = pcmk__this_with_colocations(rsc);
148
149 for (const GList *iter = colocations; iter != NULL; iter = iter->next) {
150 const pcmk__colocation_t *colocation = iter->data;
151 pcmk_resource_t *other = colocation->primary;
152 float factor = colocation->score / (float) PCMK_SCORE_INFINITY;
153
154 other->cmds->add_colocated_node_scores(other, rsc, rsc->id, nodes,
155 colocation, factor,
156 pcmk__coloc_select_default);
157 }
158 g_list_free(colocations);
159 colocations = pcmk__with_this_colocations(rsc);
160
161 for (const GList *iter = colocations; iter != NULL; iter = iter->next) {
162 const pcmk__colocation_t *colocation = iter->data;
163 pcmk_resource_t *other = colocation->dependent;
164 float factor = colocation->score / (float) PCMK_SCORE_INFINITY;
165
166 if (!pcmk__colocation_has_influence(colocation, rsc)) {
167 continue;
168 }
169 other->cmds->add_colocated_node_scores(other, rsc, rsc->id, nodes,
170 colocation, factor,
171 pcmk__coloc_select_nonnegative);
172 }
173 g_list_free(colocations);
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 static int
192 cmp_instance_by_colocation(const pcmk_resource_t *instance1,
193 const pcmk_resource_t *instance2)
194 {
195 int rc = 0;
196 pcmk_node_t *node1 = NULL;
197 pcmk_node_t *node2 = NULL;
198 pcmk_node_t *current_node1 = pcmk__current_node(instance1);
199 pcmk_node_t *current_node2 = pcmk__current_node(instance2);
200 GHashTable *colocated_scores1 = NULL;
201 GHashTable *colocated_scores2 = NULL;
202
203 pcmk__assert((instance1 != NULL) && (instance1->parent != NULL)
204 && (instance2 != NULL) && (instance2->parent != NULL)
205 && (current_node1 != NULL) && (current_node2 != NULL));
206
207
208 colocated_scores1 = new_node_table(current_node1);
209 colocated_scores2 = new_node_table(current_node2);
210
211
212 apply_parent_colocations(instance1, &colocated_scores1);
213 apply_parent_colocations(instance2, &colocated_scores2);
214
215
216 node1 = g_hash_table_lookup(colocated_scores1, current_node1->details->id);
217 node2 = g_hash_table_lookup(colocated_scores2, current_node2->details->id);
218
219
220 if (node1->weight < node2->weight) {
221 crm_trace("Assign %s (%d on %s) after %s (%d on %s)",
222 instance1->id, node1->weight, pcmk__node_name(node1),
223 instance2->id, node2->weight, pcmk__node_name(node2));
224 rc = 1;
225
226 } else if (node1->weight > node2->weight) {
227 crm_trace("Assign %s (%d on %s) before %s (%d on %s)",
228 instance1->id, node1->weight, pcmk__node_name(node1),
229 instance2->id, node2->weight, pcmk__node_name(node2));
230 rc = -1;
231 }
232
233 g_hash_table_destroy(colocated_scores1);
234 g_hash_table_destroy(colocated_scores2);
235 return rc;
236 }
237
238
239
240
241
242
243
244
245
246 static bool
247 did_fail(const pcmk_resource_t *rsc)
248 {
249 if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
250 return true;
251 }
252 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
253 if (did_fail((const pcmk_resource_t *) iter->data)) {
254 return true;
255 }
256 }
257 return false;
258 }
259
260
261
262
263
264
265
266
267
268
269 static bool
270 node_is_allowed(const pcmk_resource_t *rsc, pcmk_node_t **node)
271 {
272 if (*node != NULL) {
273 pcmk_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes,
274 (*node)->details->id);
275
276 if ((allowed == NULL) || (allowed->weight < 0)) {
277 pcmk__rsc_trace(rsc, "%s: current location (%s) is unavailable",
278 rsc->id, pcmk__node_name(*node));
279 *node = NULL;
280 return false;
281 }
282 }
283 return true;
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297 gint
298 pcmk__cmp_instance_number(gconstpointer a, gconstpointer b)
299 {
300 const pcmk_resource_t *instance1 = (const pcmk_resource_t *) a;
301 const pcmk_resource_t *instance2 = (const pcmk_resource_t *) b;
302 char *div1 = NULL;
303 char *div2 = NULL;
304
305 pcmk__assert((instance1 != NULL) && (instance2 != NULL));
306
307
308 div1 = strrchr(instance1->id, ':');
309 if (div1 == NULL) {
310 div1 = strrchr(instance1->id, '-');
311 }
312 div2 = strrchr(instance2->id, ':');
313 if (div2 == NULL) {
314 div2 = strrchr(instance2->id, '-');
315 }
316 pcmk__assert((div1 != NULL) && (div2 != NULL));
317
318 return (gint) (strtol(div1 + 1, NULL, 10) - strtol(div2 + 1, NULL, 10));
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346 gint
347 pcmk__cmp_instance(gconstpointer a, gconstpointer b)
348 {
349 int rc = 0;
350 pcmk_node_t *node1 = NULL;
351 pcmk_node_t *node2 = NULL;
352 unsigned int nnodes1 = 0;
353 unsigned int nnodes2 = 0;
354
355 bool can1 = true;
356 bool can2 = true;
357
358 const pcmk_resource_t *instance1 = (const pcmk_resource_t *) a;
359 const pcmk_resource_t *instance2 = (const pcmk_resource_t *) b;
360
361 pcmk__assert((instance1 != NULL) && (instance2 != NULL));
362
363 node1 = instance1->fns->active_node(instance1, &nnodes1, NULL);
364 node2 = instance2->fns->active_node(instance2, &nnodes2, NULL);
365
366
367
368
369 if ((nnodes1 > 0) && (nnodes2 > 0)) {
370 if (nnodes1 < nnodes2) {
371 crm_trace("Assign %s (active on %d) before %s (active on %d): "
372 "less multiply active",
373 instance1->id, nnodes1, instance2->id, nnodes2);
374 return -1;
375
376 } else if (nnodes1 > nnodes2) {
377 crm_trace("Assign %s (active on %d) after %s (active on %d): "
378 "more multiply active",
379 instance1->id, nnodes1, instance2->id, nnodes2);
380 return 1;
381 }
382 }
383
384
385
386
387 can1 = node_is_allowed(instance1, &node1);
388 can2 = node_is_allowed(instance2, &node2);
389 if (can1 && !can2) {
390 crm_trace("Assign %s before %s: not active on a disallowed node",
391 instance1->id, instance2->id);
392 return -1;
393
394 } else if (!can1 && can2) {
395 crm_trace("Assign %s after %s: active on a disallowed node",
396 instance1->id, instance2->id);
397 return 1;
398 }
399
400
401 if (instance1->priority > instance2->priority) {
402 crm_trace("Assign %s before %s: priority (%d > %d)",
403 instance1->id, instance2->id,
404 instance1->priority, instance2->priority);
405 return -1;
406
407 } else if (instance1->priority < instance2->priority) {
408 crm_trace("Assign %s after %s: priority (%d < %d)",
409 instance1->id, instance2->id,
410 instance1->priority, instance2->priority);
411 return 1;
412 }
413
414
415 if ((node1 == NULL) && (node2 == NULL)) {
416 crm_trace("No assignment preference for %s vs. %s: inactive",
417 instance1->id, instance2->id);
418 return 0;
419
420 } else if (node1 == NULL) {
421 crm_trace("Assign %s after %s: active", instance1->id, instance2->id);
422 return 1;
423
424 } else if (node2 == NULL) {
425 crm_trace("Assign %s before %s: active", instance1->id, instance2->id);
426 return -1;
427 }
428
429
430 can1 = pcmk__node_available(node1, false, false);
431 can2 = pcmk__node_available(node2, false, false);
432 if (can1 && !can2) {
433 crm_trace("Assign %s before %s: current node can run resources",
434 instance1->id, instance2->id);
435 return -1;
436
437 } else if (!can1 && can2) {
438 crm_trace("Assign %s after %s: current node can't run resources",
439 instance1->id, instance2->id);
440 return 1;
441 }
442
443
444 node1 = pcmk__top_allowed_node(instance1, node1);
445 node2 = pcmk__top_allowed_node(instance2, node2);
446 if ((node1 == NULL) && (node2 == NULL)) {
447 crm_trace("No assignment preference for %s vs. %s: "
448 "parent not allowed on either instance's current node",
449 instance1->id, instance2->id);
450 return 0;
451
452 } else if (node1 == NULL) {
453 crm_trace("Assign %s after %s: parent not allowed on current node",
454 instance1->id, instance2->id);
455 return 1;
456
457 } else if (node2 == NULL) {
458 crm_trace("Assign %s before %s: parent allowed on current node",
459 instance1->id, instance2->id);
460 return -1;
461 }
462
463
464 if (node1->count < node2->count) {
465 crm_trace("Assign %s before %s: fewer active instances on current node",
466 instance1->id, instance2->id);
467 return -1;
468
469 } else if (node1->count > node2->count) {
470 crm_trace("Assign %s after %s: more active instances on current node",
471 instance1->id, instance2->id);
472 return 1;
473 }
474
475
476 can1 = did_fail(instance1);
477 can2 = did_fail(instance2);
478 if (!can1 && can2) {
479 crm_trace("Assign %s before %s: not failed",
480 instance1->id, instance2->id);
481 return -1;
482 } else if (can1 && !can2) {
483 crm_trace("Assign %s after %s: failed",
484 instance1->id, instance2->id);
485 return 1;
486 }
487
488
489 rc = cmp_instance_by_colocation(instance1, instance2);
490 if (rc != 0) {
491 return rc;
492 }
493
494
495 rc = pcmk__cmp_instance_number(instance1, instance2);
496 if (rc < 0) {
497 crm_trace("Assign %s before %s: instance number",
498 instance1->id, instance2->id);
499 } else if (rc > 0) {
500 crm_trace("Assign %s after %s: instance number",
501 instance1->id, instance2->id);
502 } else {
503 crm_trace("No assignment preference for %s vs. %s",
504 instance1->id, instance2->id);
505 }
506 return rc;
507 }
508
509
510
511
512
513
514
515
516
517
518
519
520 static void
521 increment_parent_count(pcmk_resource_t *instance,
522 const pcmk_node_t *assigned_to)
523 {
524 pcmk_node_t *allowed = NULL;
525
526 if (assigned_to == NULL) {
527 return;
528 }
529 allowed = pcmk__top_allowed_node(instance, assigned_to);
530
531 if (allowed == NULL) {
532
533
534
535
536 CRM_LOG_ASSERT(!pcmk_is_set(instance->flags, pcmk_rsc_managed));
537
538 } else {
539 allowed->count++;
540 }
541 }
542
543
544
545
546
547
548
549
550
551
552
553
554
555 static const pcmk_node_t *
556 assign_instance(pcmk_resource_t *instance, const pcmk_node_t *prefer,
557 int max_per_node)
558 {
559 pcmk_node_t *chosen = NULL;
560
561 pcmk__rsc_trace(instance, "Assigning %s (preferring %s)", instance->id,
562 ((prefer == NULL)? "no node" : prefer->details->uname));
563
564 if (pcmk_is_set(instance->flags, pcmk_rsc_assigning)) {
565 pcmk__rsc_debug(instance,
566 "Assignment loop detected involving %s colocations",
567 instance->id);
568 return NULL;
569 }
570 ban_unavailable_allowed_nodes(instance, max_per_node);
571
572
573 chosen = instance->cmds->assign(instance, prefer, (prefer == NULL));
574 increment_parent_count(instance, chosen);
575 return chosen;
576 }
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591 static bool
592 assign_instance_early(const pcmk_resource_t *rsc, pcmk_resource_t *instance,
593 const pcmk_node_t *current, int max_per_node,
594 int available)
595 {
596 const pcmk_node_t *chosen = NULL;
597 int reserved = 0;
598
599 pcmk_resource_t *parent = instance->parent;
600 GHashTable *allowed_orig = NULL;
601 GHashTable *allowed_orig_parent = parent->allowed_nodes;
602 const pcmk_node_t *allowed_node = NULL;
603
604 pcmk__rsc_trace(instance, "Trying to assign %s to its current node %s",
605 instance->id, pcmk__node_name(current));
606
607 allowed_node = g_hash_table_lookup(instance->allowed_nodes,
608 current->details->id);
609 if (!pcmk__node_available(allowed_node, true, false)) {
610 pcmk__rsc_info(instance,
611 "Not assigning %s to current node %s: unavailable",
612 instance->id, pcmk__node_name(current));
613 return false;
614 }
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634 pcmk__copy_node_tables(instance, &allowed_orig);
635
636
637 parent->allowed_nodes = pcmk__copy_node_table(parent->allowed_nodes);
638
639 while (reserved < available) {
640 chosen = assign_instance(instance, current, max_per_node);
641
642 if (pcmk__same_node(chosen, current)) {
643
644 break;
645 }
646
647
648 pcmk__rsc_debug(instance, "Rolling back node scores for %s",
649 instance->id);
650 pcmk__restore_node_tables(instance, allowed_orig);
651
652 if (chosen == NULL) {
653
654 pcmk__rsc_info(instance,
655 "Not assigning %s to current node %s: unavailable",
656 instance->id, pcmk__node_name(current));
657 pcmk__set_rsc_flags(instance, pcmk_rsc_unassigned);
658 break;
659 }
660
661
662 pcmk__rsc_debug(instance,
663 "Not assigning %s to current node %s: %s is better",
664 instance->id, pcmk__node_name(current),
665 pcmk__node_name(chosen));
666
667
668 if (++reserved >= available) {
669 pcmk__rsc_info(instance,
670 "Not assigning %s to current node %s: "
671 "other assignments are more important",
672 instance->id, pcmk__node_name(current));
673
674 } else {
675 pcmk__rsc_debug(instance,
676 "Reserved an instance of %s for %s. Retrying "
677 "assignment of %s to %s",
678 rsc->id, pcmk__node_name(chosen), instance->id,
679 pcmk__node_name(current));
680 }
681
682
683 pcmk__unassign_resource(instance);
684 chosen = NULL;
685 }
686
687 g_hash_table_destroy(allowed_orig);
688
689
690 g_hash_table_destroy(parent->allowed_nodes);
691 parent->allowed_nodes = allowed_orig_parent;
692
693 if (chosen == NULL) {
694
695 return false;
696 }
697 pcmk__rsc_trace(instance, "Assigned %s to current node %s",
698 instance->id, pcmk__node_name(current));
699 increment_parent_count(instance, chosen);
700 return true;
701 }
702
703
704
705
706
707
708
709
710
711 static unsigned int
712 reset_allowed_node_counts(pcmk_resource_t *rsc)
713 {
714 unsigned int available_nodes = 0;
715 pcmk_node_t *node = NULL;
716 GHashTableIter iter;
717
718 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
719 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
720 node->count = 0;
721 if (pcmk__node_available(node, false, false)) {
722 available_nodes++;
723 }
724 }
725 return available_nodes;
726 }
727
728
729
730
731
732
733
734
735
736
737 static const pcmk_node_t *
738 preferred_node(const pcmk_resource_t *instance, int optimal_per_node)
739 {
740 const pcmk_node_t *node = NULL;
741 const pcmk_node_t *parent_node = NULL;
742
743
744 if ((instance->running_on == NULL)
745 || !pcmk_is_set(instance->flags, pcmk_rsc_unassigned)
746 || pcmk_is_set(instance->flags, pcmk_rsc_failed)) {
747 return NULL;
748 }
749
750
751 node = pcmk__current_node(instance);
752 if (!pcmk__node_available(node, true, false)) {
753 pcmk__rsc_trace(instance, "Not assigning %s to %s early (unavailable)",
754 instance->id, pcmk__node_name(node));
755 return NULL;
756 }
757
758
759 parent_node = pcmk__top_allowed_node(instance, node);
760 if ((parent_node != NULL) && (parent_node->count >= optimal_per_node)) {
761 pcmk__rsc_trace(instance,
762 "Not assigning %s to %s early "
763 "(optimal instances already assigned)",
764 instance->id, pcmk__node_name(node));
765 return NULL;
766 }
767
768 return node;
769 }
770
771
772
773
774
775
776
777
778
779
780 void
781 pcmk__assign_instances(pcmk_resource_t *collective, GList *instances,
782 int max_total, int max_per_node)
783 {
784
785 unsigned int available_nodes = reset_allowed_node_counts(collective);
786
787 int optimal_per_node = 0;
788 int assigned = 0;
789 GList *iter = NULL;
790 pcmk_resource_t *instance = NULL;
791 const pcmk_node_t *current = NULL;
792
793 if (available_nodes > 0) {
794 optimal_per_node = max_total / available_nodes;
795 }
796 if (optimal_per_node < 1) {
797 optimal_per_node = 1;
798 }
799
800 pcmk__rsc_debug(collective,
801 "Assigning up to %d %s instance%s to up to %u node%s "
802 "(at most %d per host, %d optimal)",
803 max_total, collective->id, pcmk__plural_s(max_total),
804 available_nodes, pcmk__plural_s(available_nodes),
805 max_per_node, optimal_per_node);
806
807
808 for (iter = instances; (iter != NULL) && (assigned < max_total);
809 iter = iter->next) {
810 int available = max_total - assigned;
811
812 instance = iter->data;
813 if (!pcmk_is_set(instance->flags, pcmk_rsc_unassigned)) {
814 continue;
815 }
816
817 current = preferred_node(instance, optimal_per_node);
818 if ((current != NULL)
819 && assign_instance_early(collective, instance, current,
820 max_per_node, available)) {
821 assigned++;
822 }
823 }
824
825 pcmk__rsc_trace(collective, "Assigned %d of %d instance%s to current node",
826 assigned, max_total, pcmk__plural_s(max_total));
827
828 for (iter = instances; iter != NULL; iter = iter->next) {
829 instance = (pcmk_resource_t *) iter->data;
830
831 if (!pcmk_is_set(instance->flags, pcmk_rsc_unassigned)) {
832 continue;
833 }
834
835 if (instance->running_on != NULL) {
836 current = pcmk__current_node(instance);
837 if (pcmk__top_allowed_node(instance, current) == NULL) {
838 const char *unmanaged = "";
839
840 if (!pcmk_is_set(instance->flags, pcmk_rsc_managed)) {
841 unmanaged = "Unmanaged resource ";
842 }
843 crm_notice("%s%s is running on %s which is no longer allowed",
844 unmanaged, instance->id, pcmk__node_name(current));
845 }
846 }
847
848 if (assigned >= max_total) {
849 pcmk__rsc_debug(collective,
850 "Not assigning %s because maximum %d instances "
851 "already assigned",
852 instance->id, max_total);
853 resource_location(instance, NULL, -PCMK_SCORE_INFINITY,
854 "collective_limit_reached", collective->cluster);
855
856 } else if (assign_instance(instance, NULL, max_per_node) != NULL) {
857 assigned++;
858 }
859 }
860
861 pcmk__rsc_debug(collective, "Assigned %d of %d possible instance%s of %s",
862 assigned, max_total, pcmk__plural_s(max_total),
863 collective->id);
864 }
865
866 enum instance_state {
867 instance_starting = (1 << 0),
868 instance_stopping = (1 << 1),
869
870
871
872
873
874
875 instance_restarting = (1 << 2),
876
877 instance_active = (1 << 3),
878
879 instance_all = instance_starting|instance_stopping
880 |instance_restarting|instance_active,
881 };
882
883
884
885
886
887
888
889
890 static void
891 check_instance_state(const pcmk_resource_t *instance, uint32_t *state)
892 {
893 const GList *iter = NULL;
894 uint32_t instance_state = 0;
895
896
897 if (pcmk_all_flags_set(*state, instance_all)) {
898 return;
899 }
900
901
902 if (instance->variant > pcmk_rsc_variant_primitive) {
903 for (iter = instance->children;
904 (iter != NULL) && !pcmk_all_flags_set(*state, instance_all);
905 iter = iter->next) {
906 check_instance_state((const pcmk_resource_t *) iter->data, state);
907 }
908 return;
909 }
910
911
912
913 if (instance->running_on != NULL) {
914 instance_state |= instance_active;
915 }
916
917
918 for (iter = instance->actions;
919 (iter != NULL) && !pcmk_all_flags_set(instance_state,
920 instance_starting
921 |instance_stopping);
922 iter = iter->next) {
923
924 const pcmk_action_t *action = (const pcmk_action_t *) iter->data;
925 const bool optional = pcmk_is_set(action->flags, pcmk_action_optional);
926
927 if (pcmk__str_eq(PCMK_ACTION_START, action->task, pcmk__str_none)) {
928 if (!optional
929 && pcmk_is_set(action->flags, pcmk_action_runnable)) {
930
931 pcmk__rsc_trace(instance, "Instance is starting due to %s",
932 action->uuid);
933 instance_state |= instance_starting;
934 } else {
935 pcmk__rsc_trace(instance, "%s doesn't affect %s state (%s)",
936 action->uuid, instance->id,
937 (optional? "optional" : "unrunnable"));
938 }
939
940 } else if (pcmk__str_eq(PCMK_ACTION_STOP, action->task,
941 pcmk__str_none)) {
942
943
944
945
946 if (!optional
947 && pcmk_any_flags_set(action->flags, pcmk_action_pseudo
948 |pcmk_action_runnable)) {
949 pcmk__rsc_trace(instance, "Instance is stopping due to %s",
950 action->uuid);
951 instance_state |= instance_stopping;
952 } else {
953 pcmk__rsc_trace(instance, "%s doesn't affect %s state (%s)",
954 action->uuid, instance->id,
955 (optional? "optional" : "unrunnable"));
956 }
957 }
958 }
959
960 if (pcmk_all_flags_set(instance_state,
961 instance_starting|instance_stopping)) {
962 instance_state |= instance_restarting;
963 }
964 *state |= instance_state;
965 }
966
967
968
969
970
971
972
973
974 void
975 pcmk__create_instance_actions(pcmk_resource_t *collective, GList *instances)
976 {
977 uint32_t state = 0;
978
979 pcmk_action_t *stop = NULL;
980 pcmk_action_t *stopped = NULL;
981
982 pcmk_action_t *start = NULL;
983 pcmk_action_t *started = NULL;
984
985 pcmk__rsc_trace(collective, "Creating collective instance actions for %s",
986 collective->id);
987
988
989 for (GList *iter = instances; iter != NULL; iter = iter->next) {
990 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
991
992 instance->cmds->create_actions(instance);
993 check_instance_state(instance, &state);
994 }
995
996
997 start = pe__new_rsc_pseudo_action(collective, PCMK_ACTION_START,
998 !pcmk_is_set(state, instance_starting),
999 true);
1000 started = pe__new_rsc_pseudo_action(collective, PCMK_ACTION_RUNNING,
1001 !pcmk_is_set(state, instance_starting),
1002 false);
1003 started->priority = PCMK_SCORE_INFINITY;
1004 if (pcmk_any_flags_set(state, instance_active|instance_starting)) {
1005 pcmk__set_action_flags(started, pcmk_action_runnable);
1006 }
1007
1008
1009 stop = pe__new_rsc_pseudo_action(collective, PCMK_ACTION_STOP,
1010 !pcmk_is_set(state, instance_stopping),
1011 true);
1012 stopped = pe__new_rsc_pseudo_action(collective, PCMK_ACTION_STOPPED,
1013 !pcmk_is_set(state, instance_stopping),
1014 true);
1015 stopped->priority = PCMK_SCORE_INFINITY;
1016 if (!pcmk_is_set(state, instance_restarting)) {
1017 pcmk__set_action_flags(stop, pcmk_action_migratable);
1018 }
1019
1020 if (pcmk__is_clone(collective)) {
1021 pe__create_clone_notif_pseudo_ops(collective, start, started, stop,
1022 stopped);
1023 }
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037 static inline GList *
1038 get_instance_list(const pcmk_resource_t *rsc)
1039 {
1040 if (pcmk__is_bundle(rsc)) {
1041 return pe__bundle_containers(rsc);
1042 } else {
1043 return rsc->children;
1044 }
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054 static inline void
1055 free_instance_list(const pcmk_resource_t *rsc, GList *list)
1056 {
1057 if (list != rsc->children) {
1058 g_list_free(list);
1059 }
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 bool
1076 pcmk__instance_matches(const pcmk_resource_t *instance, const pcmk_node_t *node,
1077 enum rsc_role_e role, bool current)
1078 {
1079 pcmk_node_t *instance_node = NULL;
1080
1081 CRM_CHECK((instance != NULL) && (node != NULL), return false);
1082
1083 if ((role != pcmk_role_unknown)
1084 && (role != instance->fns->state(instance, current))) {
1085 pcmk__rsc_trace(instance,
1086 "%s is not a compatible instance (role is not %s)",
1087 instance->id, pcmk_role_text(role));
1088 return false;
1089 }
1090
1091 if (!is_set_recursive(instance, pcmk_rsc_blocked, true)) {
1092
1093 instance_node = instance->fns->location(instance, NULL, current);
1094 }
1095
1096 if (instance_node == NULL) {
1097 pcmk__rsc_trace(instance,
1098 "%s is not a compatible instance "
1099 "(not assigned to a node)",
1100 instance->id);
1101 return false;
1102 }
1103
1104 if (!pcmk__same_node(instance_node, node)) {
1105 pcmk__rsc_trace(instance,
1106 "%s is not a compatible instance "
1107 "(assigned to %s not %s)",
1108 instance->id, pcmk__node_name(instance_node),
1109 pcmk__node_name(node));
1110 return false;
1111 }
1112
1113 return true;
1114 }
1115
1116 #define display_role(r) \
1117 (((r) == pcmk_role_unknown)? "matching" : pcmk_role_text(r))
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 static pcmk_resource_t *
1133 find_compatible_instance_on_node(const pcmk_resource_t *match_rsc,
1134 const pcmk_resource_t *rsc,
1135 const pcmk_node_t *node, enum rsc_role_e role,
1136 bool current)
1137 {
1138 GList *instances = NULL;
1139
1140 instances = get_instance_list(rsc);
1141 for (GList *iter = instances; iter != NULL; iter = iter->next) {
1142 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1143
1144 if (pcmk__instance_matches(instance, node, role, current)) {
1145 pcmk__rsc_trace(match_rsc,
1146 "Found %s %s instance %s compatible with %s on %s",
1147 display_role(role), rsc->id, instance->id,
1148 match_rsc->id, pcmk__node_name(node));
1149 free_instance_list(rsc, instances);
1150 return instance;
1151 }
1152 }
1153 free_instance_list(rsc, instances);
1154
1155 pcmk__rsc_trace(match_rsc,
1156 "No %s %s instance found compatible with %s on %s",
1157 display_role(role), rsc->id, match_rsc->id,
1158 pcmk__node_name(node));
1159 return NULL;
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175 pcmk_resource_t *
1176 pcmk__find_compatible_instance(const pcmk_resource_t *match_rsc,
1177 const pcmk_resource_t *rsc, enum rsc_role_e role,
1178 bool current)
1179 {
1180 pcmk_resource_t *instance = NULL;
1181 GList *nodes = NULL;
1182 const pcmk_node_t *node = NULL;
1183
1184
1185 node = match_rsc->fns->location(match_rsc, NULL, current);
1186 if (node != NULL) {
1187 return find_compatible_instance_on_node(match_rsc, rsc, node, role,
1188 current);
1189 }
1190
1191
1192 nodes = pcmk__sort_nodes(g_hash_table_get_values(match_rsc->allowed_nodes),
1193 NULL);
1194 for (GList *iter = nodes; (iter != NULL) && (instance == NULL);
1195 iter = iter->next) {
1196 instance = find_compatible_instance_on_node(match_rsc, rsc,
1197 (pcmk_node_t *) iter->data,
1198 role, current);
1199 }
1200
1201 if (instance == NULL) {
1202 pcmk__rsc_debug(rsc, "No %s instance found compatible with %s",
1203 rsc->id, match_rsc->id);
1204 }
1205 g_list_free(nodes);
1206 return instance;
1207 }
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221 static bool
1222 unassign_if_mandatory(const pcmk_action_t *first, const pcmk_action_t *then,
1223 pcmk_resource_t *then_instance, uint32_t type,
1224 bool current)
1225 {
1226
1227 if (current) {
1228 pcmk__rsc_trace(then->rsc,
1229 "%s has no instance to order before stopping "
1230 "or demoting %s",
1231 first->rsc->id, then_instance->id);
1232
1233
1234
1235
1236 } else if (pcmk_any_flags_set(type, pcmk__ar_unrunnable_first_blocks
1237 |pcmk__ar_first_implies_then)) {
1238 pcmk__rsc_info(then->rsc,
1239 "Inhibiting %s from being active "
1240 "because there is no %s instance to interleave",
1241 then_instance->id, first->rsc->id);
1242 return pcmk__assign_resource(then_instance, NULL, true, true);
1243 }
1244 return false;
1245 }
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262 static pcmk_action_t *
1263 find_instance_action(const pcmk_action_t *action, const pcmk_resource_t *instance,
1264 const char *action_name, const pcmk_node_t *node,
1265 bool for_first)
1266 {
1267 const pcmk_resource_t *rsc = NULL;
1268 pcmk_action_t *matching_action = NULL;
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285 if ((for_first && !pcmk__str_any_of(action->task, PCMK_ACTION_STOP,
1286 PCMK_ACTION_STOPPED, NULL))
1287
1288 || (!for_first && pcmk__str_any_of(action->task, PCMK_ACTION_PROMOTE,
1289 PCMK_ACTION_PROMOTED,
1290 PCMK_ACTION_DEMOTE,
1291 PCMK_ACTION_DEMOTED, NULL))) {
1292
1293 rsc = pe__get_rsc_in_container(instance);
1294 }
1295 if (rsc == NULL) {
1296 rsc = instance;
1297 } else {
1298 node = NULL;
1299 }
1300
1301 matching_action = find_first_action(rsc->actions, NULL, action_name, node);
1302 if (matching_action != NULL) {
1303 return matching_action;
1304 }
1305
1306 if (pcmk_is_set(instance->flags, pcmk_rsc_removed)
1307 || pcmk__str_any_of(action_name, PCMK_ACTION_STOP, PCMK_ACTION_DEMOTE,
1308 NULL)) {
1309 crm_trace("No %s action found for %s%s",
1310 action_name,
1311 pcmk_is_set(instance->flags, pcmk_rsc_removed)? "orphan " : "",
1312 instance->id);
1313 } else {
1314 crm_err("No %s action found for %s to interleave (bug?)",
1315 action_name, instance->id);
1316 }
1317 return NULL;
1318 }
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333 static const char *
1334 orig_action_name(const pcmk_action_t *action)
1335 {
1336
1337 const pcmk_resource_t *instance = action->rsc->children->data;
1338
1339 char *action_type = NULL;
1340 const char *action_name = action->task;
1341 enum action_tasks orig_task = pcmk_action_unspecified;
1342
1343 if (pcmk__strcase_any_of(action->task, PCMK_ACTION_NOTIFY,
1344 PCMK_ACTION_NOTIFIED, NULL)) {
1345
1346 CRM_CHECK(parse_op_key(action->uuid, NULL, &action_type, NULL),
1347 return pcmk_action_text(pcmk_action_unspecified));
1348 action_name = strstr(action_type, "_notify_");
1349 CRM_CHECK(action_name != NULL,
1350 return pcmk_action_text(pcmk_action_unspecified));
1351 action_name += strlen("_notify_");
1352 }
1353 orig_task = get_complex_task(instance, action_name);
1354 free(action_type);
1355 return pcmk_action_text(orig_task);
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378 static uint32_t
1379 update_interleaved_actions(pcmk_action_t *first, pcmk_action_t *then,
1380 const pcmk_node_t *node, uint32_t filter,
1381 uint32_t type)
1382 {
1383 GList *instances = NULL;
1384 uint32_t changed = pcmk__updated_none;
1385 const char *orig_first_task = orig_action_name(first);
1386
1387
1388 bool current = pcmk__ends_with(first->uuid, "_" PCMK_ACTION_STOPPED "_0")
1389 || pcmk__ends_with(first->uuid,
1390 "_" PCMK_ACTION_DEMOTED "_0");
1391
1392
1393 instances = get_instance_list(then->rsc);
1394 for (GList *iter = instances; iter != NULL; iter = iter->next) {
1395 pcmk_resource_t *first_instance = NULL;
1396 pcmk_resource_t *then_instance = iter->data;
1397
1398 pcmk_action_t *first_action = NULL;
1399 pcmk_action_t *then_action = NULL;
1400
1401
1402 first_instance = pcmk__find_compatible_instance(then_instance,
1403 first->rsc,
1404 pcmk_role_unknown,
1405 current);
1406
1407 if (first_instance == NULL) {
1408 if (unassign_if_mandatory(first, then, then_instance, type,
1409 current)) {
1410 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
1411 }
1412 continue;
1413 }
1414
1415 first_action = find_instance_action(first, first_instance,
1416 orig_first_task, node, true);
1417 if (first_action == NULL) {
1418 continue;
1419 }
1420
1421 then_action = find_instance_action(then, then_instance, then->task,
1422 node, false);
1423 if (then_action == NULL) {
1424 continue;
1425 }
1426
1427 if (order_actions(first_action, then_action, type)) {
1428 pcmk__set_updated_flags(changed, first,
1429 pcmk__updated_first|pcmk__updated_then);
1430 }
1431
1432 changed |= then_instance->cmds->update_ordered_actions(
1433 first_action, then_action, node,
1434 first_instance->cmds->action_flags(first_action, node), filter,
1435 type, then->rsc->cluster);
1436 }
1437 free_instance_list(then->rsc, instances);
1438 return changed;
1439 }
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450 static bool
1451 can_interleave_actions(const pcmk_action_t *first, const pcmk_action_t *then)
1452 {
1453 bool interleave = false;
1454 pcmk_resource_t *rsc = NULL;
1455
1456 if ((first->rsc == NULL) || (then->rsc == NULL)) {
1457 crm_trace("Not interleaving %s with %s: not resource actions",
1458 first->uuid, then->uuid);
1459 return false;
1460 }
1461
1462 if (first->rsc == then->rsc) {
1463 crm_trace("Not interleaving %s with %s: same resource",
1464 first->uuid, then->uuid);
1465 return false;
1466 }
1467
1468 if ((first->rsc->variant < pcmk_rsc_variant_clone)
1469 || (then->rsc->variant < pcmk_rsc_variant_clone)) {
1470 crm_trace("Not interleaving %s with %s: not clones or bundles",
1471 first->uuid, then->uuid);
1472 return false;
1473 }
1474
1475 if (pcmk__ends_with(then->uuid, "_stop_0")
1476 || pcmk__ends_with(then->uuid, "_demote_0")) {
1477 rsc = first->rsc;
1478 } else {
1479 rsc = then->rsc;
1480 }
1481
1482 interleave = crm_is_true(g_hash_table_lookup(rsc->meta,
1483 PCMK_META_INTERLEAVE));
1484 pcmk__rsc_trace(rsc, "'%s then %s' will %sbe interleaved (based on %s)",
1485 first->uuid, then->uuid, (interleave? "" : "not "),
1486 rsc->id);
1487 return interleave;
1488 }
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512 static uint32_t
1513 update_noninterleaved_actions(pcmk_resource_t *instance, pcmk_action_t *first,
1514 const pcmk_action_t *then, const pcmk_node_t *node,
1515 uint32_t flags, uint32_t filter, uint32_t type)
1516 {
1517 pcmk_action_t *instance_action = NULL;
1518 uint32_t instance_flags = 0;
1519 uint32_t changed = pcmk__updated_none;
1520
1521
1522 instance_action = find_first_action(instance->actions, NULL, then->task,
1523 node);
1524 if (instance_action == NULL) {
1525 return changed;
1526 }
1527
1528
1529 instance_flags = instance->cmds->action_flags(instance_action, node);
1530 if (!pcmk_is_set(instance_flags, pcmk_action_runnable)) {
1531 return changed;
1532 }
1533
1534
1535 changed = instance->cmds->update_ordered_actions(first, instance_action,
1536 node, flags, filter, type,
1537 instance->cluster);
1538
1539
1540 if (pcmk_is_set(changed, pcmk__updated_then)) {
1541 for (GList *after_iter = instance_action->actions_after;
1542 after_iter != NULL; after_iter = after_iter->next) {
1543 pcmk__related_action_t *after = after_iter->data;
1544
1545 pcmk__update_action_for_orderings(after->action, instance->cluster);
1546 }
1547 }
1548
1549 return changed;
1550 }
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575 uint32_t
1576 pcmk__instance_update_ordered_actions(pcmk_action_t *first, pcmk_action_t *then,
1577 const pcmk_node_t *node, uint32_t flags,
1578 uint32_t filter, uint32_t type,
1579 pcmk_scheduler_t *scheduler)
1580 {
1581 pcmk__assert((first != NULL) && (then != NULL) && (scheduler != NULL));
1582
1583 if (then->rsc == NULL) {
1584 return pcmk__updated_none;
1585
1586 } else if (can_interleave_actions(first, then)) {
1587 return update_interleaved_actions(first, then, node, filter, type);
1588
1589 } else {
1590 uint32_t changed = pcmk__updated_none;
1591 GList *instances = get_instance_list(then->rsc);
1592
1593
1594 changed |= pcmk__update_ordered_actions(first, then, node, flags,
1595 filter, type, scheduler);
1596
1597
1598 for (GList *iter = instances; iter != NULL; iter = iter->next) {
1599 pcmk_resource_t *instance = iter->data;
1600
1601 changed |= update_noninterleaved_actions(instance, first, then,
1602 node, flags, filter, type);
1603 }
1604 free_instance_list(then->rsc, instances);
1605 return changed;
1606 }
1607 }
1608
1609 #define pe__clear_action_summary_flags(flags, action, flag) do { \
1610 flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
1611 "Action summary", action->rsc->id, \
1612 flags, flag, #flag); \
1613 } while (0)
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625 uint32_t
1626 pcmk__collective_action_flags(pcmk_action_t *action, const GList *instances,
1627 const pcmk_node_t *node)
1628 {
1629 bool any_runnable = false;
1630 const char *action_name = orig_action_name(action);
1631
1632
1633 uint32_t flags = pcmk_action_optional
1634 |pcmk_action_runnable
1635 |pcmk_action_pseudo;
1636
1637 for (const GList *iter = instances; iter != NULL; iter = iter->next) {
1638 const pcmk_resource_t *instance = iter->data;
1639 const pcmk_node_t *instance_node = NULL;
1640 pcmk_action_t *instance_action = NULL;
1641 uint32_t instance_flags;
1642
1643
1644 if (pcmk__is_primitive(instance)) {
1645 instance_node = node;
1646 }
1647
1648 instance_action = find_first_action(instance->actions, NULL,
1649 action_name, instance_node);
1650 if (instance_action == NULL) {
1651 pcmk__rsc_trace(action->rsc, "%s has no %s action on %s",
1652 instance->id, action_name, pcmk__node_name(node));
1653 continue;
1654 }
1655
1656 pcmk__rsc_trace(action->rsc, "%s has %s for %s on %s",
1657 instance->id, instance_action->uuid, action_name,
1658 pcmk__node_name(node));
1659
1660 instance_flags = instance->cmds->action_flags(instance_action, node);
1661
1662
1663 if (pcmk_is_set(flags, pcmk_action_optional)
1664 && !pcmk_is_set(instance_flags, pcmk_action_optional)) {
1665 pcmk__rsc_trace(instance, "%s is mandatory because %s is",
1666 action->uuid, instance_action->uuid);
1667 pe__clear_action_summary_flags(flags, action,
1668 pcmk_action_optional);
1669 pcmk__clear_action_flags(action, pcmk_action_optional);
1670 }
1671
1672
1673 if (pcmk_is_set(instance_flags, pcmk_action_runnable)) {
1674 any_runnable = true;
1675 }
1676 }
1677
1678 if (!any_runnable) {
1679 pcmk__rsc_trace(action->rsc,
1680 "%s is not runnable because no instance can run %s",
1681 action->uuid, action_name);
1682 pe__clear_action_summary_flags(flags, action, pcmk_action_runnable);
1683 if (node == NULL) {
1684 pcmk__clear_action_flags(action, pcmk_action_runnable);
1685 }
1686 }
1687
1688 return flags;
1689 }