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