This source file includes following definitions.
- pcmk__group_assign
- create_group_pseudo_op
- pcmk__group_create_actions
- member_internal_constraints
- pcmk__group_internal_constraints
- colocate_group_with
- colocate_with_group
- pcmk__group_apply_coloc_score
- pcmk__group_action_flags
- pcmk__group_update_ordered_actions
- pcmk__group_apply_location
- pcmk__group_colocated_resources
- pcmk__with_group_colocations
- pcmk__group_with_colocations
- pcmk__group_add_colocated_node_scores
- pcmk__group_add_utilization
- pcmk__group_shutdown_lock
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13
14 #include <crm/msg_xml.h>
15
16 #include <pacemaker-internal.h>
17 #include "libpacemaker_private.h"
18
19
20
21
22
23
24
25
26
27
28 pe_node_t *
29 pcmk__group_assign(pe_resource_t *rsc, const pe_node_t *prefer)
30 {
31 pe_node_t *first_assigned_node = NULL;
32 pe_resource_t *first_member = NULL;
33
34 CRM_ASSERT(rsc != NULL);
35
36 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
37 return rsc->allocated_to;
38 }
39 if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
40 pe_rsc_debug(rsc, "Assignment dependency loop detected involving %s",
41 rsc->id);
42 return NULL;
43 }
44
45 if (rsc->children == NULL) {
46
47 pe__clear_resource_flags(rsc, pe_rsc_provisional);
48 return NULL;
49 }
50
51 pe__set_resource_flags(rsc, pe_rsc_allocating);
52 first_member = (pe_resource_t *) rsc->children->data;
53 rsc->role = first_member->role;
54
55 pe__show_node_weights(!pcmk_is_set(rsc->cluster->flags, pe_flag_show_scores),
56 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
57
58 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
59 pe_resource_t *member = (pe_resource_t *) iter->data;
60 pe_node_t *node = NULL;
61
62 pe_rsc_trace(rsc, "Assigning group %s member %s",
63 rsc->id, member->id);
64 node = member->cmds->assign(member, prefer);
65 if (first_assigned_node == NULL) {
66 first_assigned_node = node;
67 }
68 }
69
70 pe__set_next_role(rsc, first_member->next_role, "first group member");
71 pe__clear_resource_flags(rsc, pe_rsc_allocating|pe_rsc_provisional);
72
73 if (!pe__group_flag_is_set(rsc, pe__group_colocated)) {
74 return NULL;
75 }
76 return first_assigned_node;
77 }
78
79
80
81
82
83
84
85
86
87
88 static pe_action_t *
89 create_group_pseudo_op(pe_resource_t *group, const char *action)
90 {
91 pe_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
92 action, NULL, TRUE, TRUE, group->cluster);
93 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
94 return op;
95 }
96
97
98
99
100
101
102
103 void
104 pcmk__group_create_actions(pe_resource_t *rsc)
105 {
106 CRM_ASSERT(rsc != NULL);
107
108 pe_rsc_trace(rsc, "Creating actions for group %s", rsc->id);
109
110
111 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
112 pe_resource_t *member = (pe_resource_t *) iter->data;
113
114 member->cmds->create_actions(member);
115 }
116
117
118 create_group_pseudo_op(rsc, RSC_START);
119 create_group_pseudo_op(rsc, RSC_STARTED);
120 create_group_pseudo_op(rsc, RSC_STOP);
121 create_group_pseudo_op(rsc, RSC_STOPPED);
122 if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE))) {
123 create_group_pseudo_op(rsc, RSC_DEMOTE);
124 create_group_pseudo_op(rsc, RSC_DEMOTED);
125 create_group_pseudo_op(rsc, RSC_PROMOTE);
126 create_group_pseudo_op(rsc, RSC_PROMOTED);
127 }
128 }
129
130
131 struct member_data {
132
133 bool ordered;
134 bool colocated;
135 bool promotable;
136
137 pe_resource_t *last_active;
138 pe_resource_t *previous_member;
139 };
140
141
142
143
144
145
146
147
148 static void
149 member_internal_constraints(gpointer data, gpointer user_data)
150 {
151 pe_resource_t *member = (pe_resource_t *) data;
152 struct member_data *member_data = (struct member_data *) user_data;
153
154
155 uint32_t down_flags = pe_order_implies_first_printed;
156
157
158 uint32_t post_down_flags = pe_order_implies_then_printed;
159
160
161 member->cmds->internal_constraints(member);
162
163 if (member_data->previous_member == NULL) {
164
165 if (member_data->ordered) {
166 pe__set_order_flags(down_flags, pe_order_optional);
167 post_down_flags = pe_order_implies_then;
168 }
169
170 } else if (member_data->colocated) {
171
172 pcmk__new_colocation("group:internal_colocation", NULL, INFINITY,
173 member, member_data->previous_member, NULL, NULL,
174 pcmk_is_set(member->flags, pe_rsc_critical),
175 member->cluster);
176 }
177
178 if (member_data->promotable) {
179
180 pcmk__order_resource_actions(member->parent, RSC_DEMOTE,
181 member, RSC_DEMOTE, down_flags);
182 pcmk__order_resource_actions(member, RSC_DEMOTE,
183 member->parent, RSC_DEMOTED,
184 post_down_flags);
185
186
187 pcmk__order_resource_actions(member, RSC_PROMOTE,
188 member->parent, RSC_PROMOTED,
189 pe_order_runnable_left
190 |pe_order_implies_then
191 |pe_order_implies_then_printed);
192 pcmk__order_resource_actions(member->parent, RSC_PROMOTE,
193 member, RSC_PROMOTE,
194 pe_order_implies_first_printed);
195 }
196
197
198 pcmk__order_stops(member->parent, member, down_flags);
199 pcmk__order_resource_actions(member, RSC_STOP, member->parent, RSC_STOPPED,
200 post_down_flags);
201
202
203 pcmk__order_starts(member->parent, member, pe_order_implies_first_printed);
204 pcmk__order_resource_actions(member, RSC_START, member->parent, RSC_STARTED,
205 pe_order_runnable_left
206 |pe_order_implies_then
207 |pe_order_implies_then_printed);
208
209 if (!member_data->ordered) {
210 pcmk__order_starts(member->parent, member,
211 pe_order_implies_then
212 |pe_order_runnable_left
213 |pe_order_implies_first_printed);
214 if (member_data->promotable) {
215 pcmk__order_resource_actions(member->parent, RSC_PROMOTE, member,
216 RSC_PROMOTE,
217 pe_order_implies_then
218 |pe_order_runnable_left
219 |pe_order_implies_first_printed);
220 }
221
222 } else if (member_data->previous_member == NULL) {
223 pcmk__order_starts(member->parent, member, pe_order_none);
224 if (member_data->promotable) {
225 pcmk__order_resource_actions(member->parent, RSC_PROMOTE, member,
226 RSC_PROMOTE, pe_order_none);
227 }
228
229 } else {
230
231
232 pcmk__order_starts(member_data->previous_member, member,
233 pe_order_implies_then|pe_order_runnable_left);
234 pcmk__order_stops(member, member_data->previous_member,
235 pe_order_optional|pe_order_restart);
236
237
238
239
240
241
242
243 if ((member->running_on != NULL)
244 && (member_data->previous_member->running_on == NULL)) {
245 pcmk__order_resource_actions(member, RSC_STOP,
246 member_data->previous_member, RSC_START,
247 pe_order_implies_first
248 |pe_order_runnable_left);
249 }
250
251 if (member_data->promotable) {
252 pcmk__order_resource_actions(member_data->previous_member,
253 RSC_PROMOTE, member, RSC_PROMOTE,
254 pe_order_implies_then
255 |pe_order_runnable_left);
256 pcmk__order_resource_actions(member, RSC_DEMOTE,
257 member_data->previous_member,
258 RSC_DEMOTE, pe_order_optional);
259 }
260 }
261
262
263 if (member->running_on != NULL) {
264 if (member_data->ordered && (member_data->previous_member != NULL)
265 && (member_data->previous_member->running_on == NULL)
266 && (member_data->last_active != NULL)
267 && (member_data->last_active->running_on != NULL)) {
268 pcmk__order_stops(member, member_data->last_active, pe_order_optional);
269 }
270 member_data->last_active = member;
271 }
272
273 member_data->previous_member = member;
274 }
275
276
277
278
279
280
281
282 void
283 pcmk__group_internal_constraints(pe_resource_t *rsc)
284 {
285 struct member_data member_data = { false, };
286
287 CRM_ASSERT(rsc != NULL);
288
289
290
291
292 pcmk__order_resource_actions(rsc, RSC_STOP, rsc, RSC_STOPPED,
293 pe_order_runnable_left);
294 pcmk__order_resource_actions(rsc, RSC_STOPPED, rsc, RSC_START,
295 pe_order_optional);
296 pcmk__order_resource_actions(rsc, RSC_START, rsc, RSC_STARTED,
297 pe_order_runnable_left);
298
299 member_data.ordered = pe__group_flag_is_set(rsc, pe__group_ordered);
300 member_data.colocated = pe__group_flag_is_set(rsc, pe__group_colocated);
301 member_data.promotable = pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
302 pe_rsc_promotable);
303 g_list_foreach(rsc->children, member_internal_constraints, &member_data);
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318 static void
319 colocate_group_with(pe_resource_t *dependent, const pe_resource_t *primary,
320 const pcmk__colocation_t *colocation)
321 {
322 pe_resource_t *member = NULL;
323
324 if (dependent->children == NULL) {
325 return;
326 }
327
328 pe_rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
329 colocation->id, dependent->id, primary->id);
330
331 if (pe__group_flag_is_set(dependent, pe__group_colocated)) {
332
333 member = (pe_resource_t *) dependent->children->data;
334 member->cmds->apply_coloc_score(member, primary, colocation, true);
335 return;
336 }
337
338 if (colocation->score >= INFINITY) {
339 pcmk__config_err("%s: Cannot perform mandatory colocation between "
340 "non-colocated group and %s",
341 dependent->id, primary->id);
342 return;
343 }
344
345
346 for (GList *iter = dependent->children; iter != NULL; iter = iter->next) {
347 member = (pe_resource_t *) iter->data;
348 member->cmds->apply_coloc_score(member, primary, colocation, true);
349 }
350 }
351
352
353
354
355
356
357
358
359
360
361
362
363
364 static void
365 colocate_with_group(pe_resource_t *dependent, const pe_resource_t *primary,
366 const pcmk__colocation_t *colocation)
367 {
368 pe_resource_t *member = NULL;
369
370 pe_rsc_trace(primary,
371 "Processing colocation %s (%s with group %s) for primary",
372 colocation->id, dependent->id, primary->id);
373
374 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
375 return;
376 }
377
378 if (pe__group_flag_is_set(primary, pe__group_colocated)) {
379
380 if (colocation->score >= INFINITY) {
381
382
383
384
385 member = pe__last_group_member(primary);
386 } else if (primary->children != NULL) {
387
388
389
390
391 member = (pe_resource_t *) primary->children->data;
392 }
393 if (member == NULL) {
394 return;
395 }
396
397 member->cmds->apply_coloc_score(dependent, member, colocation, false);
398 return;
399 }
400
401 if (colocation->score >= INFINITY) {
402 pcmk__config_err("%s: Cannot perform mandatory colocation with"
403 " non-colocated group %s",
404 dependent->id, primary->id);
405 return;
406 }
407
408
409 for (GList *iter = primary->children; iter != NULL; iter = iter->next) {
410 member = (pe_resource_t *) iter->data;
411 member->cmds->apply_coloc_score(dependent, member, colocation, false);
412 }
413 }
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428 void
429 pcmk__group_apply_coloc_score(pe_resource_t *dependent,
430 const pe_resource_t *primary,
431 const pcmk__colocation_t *colocation,
432 bool for_dependent)
433 {
434 CRM_ASSERT((dependent != NULL) && (primary != NULL)
435 && (colocation != NULL));
436
437 if (for_dependent) {
438 colocate_group_with(dependent, primary, colocation);
439
440 } else {
441
442 CRM_ASSERT(dependent->variant == pe_native);
443
444 colocate_with_group(dependent, primary, colocation);
445 }
446 }
447
448
449
450
451
452
453
454
455
456
457 enum pe_action_flags
458 pcmk__group_action_flags(pe_action_t *action, const pe_node_t *node)
459 {
460
461 enum pe_action_flags flags = pe_action_optional
462 |pe_action_runnable
463 |pe_action_pseudo;
464
465 CRM_ASSERT(action != NULL);
466
467
468 for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
469 pe_resource_t *member = (pe_resource_t *) iter->data;
470
471
472 enum action_tasks task = get_complex_task(member, action->task);
473 const char *task_s = task2text(task);
474 pe_action_t *member_action = find_first_action(member->actions, NULL,
475 task_s, node);
476
477 if (member_action != NULL) {
478 enum pe_action_flags member_flags;
479
480 member_flags = member->cmds->action_flags(member_action, node);
481
482
483 if (pcmk_is_set(flags, pe_action_optional)
484 && !pcmk_is_set(member_flags, pe_action_optional)) {
485 pe_rsc_trace(action->rsc, "%s is mandatory because %s is",
486 action->uuid, member_action->uuid);
487 pe__clear_raw_action_flags(flags, "group action",
488 pe_action_optional);
489 pe__clear_action_flags(action, pe_action_optional);
490 }
491
492
493 if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
494 && pcmk_is_set(flags, pe_action_runnable)
495 && !pcmk_is_set(member_flags, pe_action_runnable)) {
496
497 pe_rsc_trace(action->rsc, "%s is unrunnable because %s is",
498 action->uuid, member_action->uuid);
499 pe__clear_raw_action_flags(flags, "group action",
500 pe_action_runnable);
501 pe__clear_action_flags(action, pe_action_runnable);
502 }
503
504
505
506
507 } else if ((task != stop_rsc) && (task != action_demote)) {
508 pe_rsc_trace(action->rsc,
509 "%s is not runnable because %s will not %s",
510 action->uuid, member->id, task_s);
511 pe__clear_raw_action_flags(flags, "group action",
512 pe_action_runnable);
513 }
514 }
515
516 return flags;
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 uint32_t
542 pcmk__group_update_ordered_actions(pe_action_t *first, pe_action_t *then,
543 const pe_node_t *node, uint32_t flags,
544 uint32_t filter, uint32_t type,
545 pe_working_set_t *data_set)
546 {
547 uint32_t changed = pcmk__updated_none;
548
549 CRM_ASSERT((first != NULL) && (then != NULL) && (data_set != NULL));
550
551
552 CRM_ASSERT(then->rsc != NULL);
553
554
555 changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
556 type, data_set);
557
558
559 for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
560 pe_resource_t *member = (pe_resource_t *) iter->data;
561
562 pe_action_t *member_action = find_first_action(member->actions, NULL,
563 then->task, node);
564
565 if (member_action != NULL) {
566 changed |= member->cmds->update_ordered_actions(first,
567 member_action, node,
568 flags, filter, type,
569 data_set);
570 }
571 }
572 return changed;
573 }
574
575
576
577
578
579
580
581
582 void
583 pcmk__group_apply_location(pe_resource_t *rsc, pe__location_t *location)
584 {
585 GList *node_list_orig = NULL;
586 GList *node_list_copy = NULL;
587 bool reset_scores = true;
588
589 CRM_ASSERT((rsc != NULL) && (location != NULL));
590
591 node_list_orig = location->node_list_rh;
592 node_list_copy = pcmk__copy_node_list(node_list_orig, true);
593 reset_scores = pe__group_flag_is_set(rsc, pe__group_colocated);
594
595
596 pcmk__apply_location(rsc, location);
597
598
599 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
600 pe_resource_t *member = (pe_resource_t *) iter->data;
601
602 member->cmds->apply_location(member, location);
603
604 if (reset_scores) {
605
606
607
608
609 reset_scores = false;
610 location->node_list_rh = node_list_copy;
611 }
612 }
613
614 location->node_list_rh = node_list_orig;
615 g_list_free_full(node_list_copy, free);
616 }
617
618
619 GList *
620 pcmk__group_colocated_resources(const pe_resource_t *rsc,
621 const pe_resource_t *orig_rsc,
622 GList *colocated_rscs)
623 {
624 const pe_resource_t *member = NULL;
625
626 CRM_ASSERT(rsc != NULL);
627
628 if (orig_rsc == NULL) {
629 orig_rsc = rsc;
630 }
631
632 if (pe__group_flag_is_set(rsc, pe__group_colocated)
633 || pe_rsc_is_clone(rsc->parent)) {
634
635
636
637
638 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
639 for (const GList *iter = rsc->children;
640 iter != NULL; iter = iter->next) {
641
642 member = (const pe_resource_t *) iter->data;
643 colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
644 colocated_rscs);
645 }
646
647 } else if (rsc->children != NULL) {
648
649
650
651 colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc, colocated_rscs);
652 }
653
654 return colocated_rscs;
655 }
656
657
658 void
659 pcmk__with_group_colocations(const pe_resource_t *rsc,
660 const pe_resource_t *orig_rsc, GList **list)
661
662 {
663 CRM_CHECK((rsc != NULL) && (rsc->variant == pe_group)
664 && (orig_rsc != NULL) && (list != NULL),
665 return);
666
667
668 if (rsc->children == NULL) {
669 return;
670 }
671
672
673
674
675
676 if ((rsc == orig_rsc) || (orig_rsc == pe__last_group_member(rsc))) {
677 crm_trace("Adding 'with %s' colocations to list for %s",
678 rsc->id, orig_rsc->id);
679 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs);
680 if (rsc->parent != NULL) {
681 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc,
682 list);
683 }
684 }
685 }
686
687
688 void
689 pcmk__group_with_colocations(const pe_resource_t *rsc,
690 const pe_resource_t *orig_rsc, GList **list)
691 {
692 CRM_CHECK((rsc != NULL) && (rsc->variant == pe_group)
693 && (orig_rsc != NULL) && (list != NULL),
694 return);
695
696
697 if (rsc->children == NULL) {
698 return;
699 }
700
701
702
703
704 if ((rsc == orig_rsc)
705 || (orig_rsc == (const pe_resource_t *) rsc->children->data)) {
706 crm_trace("Adding '%s with' colocations to list for %s",
707 rsc->id, orig_rsc->id);
708 pcmk__add_this_with_list(list, rsc->rsc_cons);
709 if (rsc->parent != NULL) {
710 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc,
711 list);
712 }
713 return;
714 }
715
716
717
718
719
720
721 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
722 const pe_resource_t *member = (const pe_resource_t *) iter->data;
723
724 if (orig_rsc == member) {
725 break;
726 }
727
728 if (!pcmk_is_set(member->flags, pe_rsc_managed)) {
729 crm_trace("Adding mandatory '%s with' colocations to list for "
730 "member %s because earlier member %s is unmanaged",
731 rsc->id, orig_rsc->id, member->id);
732 for (const GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
733 cons_iter = cons_iter->next) {
734 const pcmk__colocation_t *colocation = NULL;
735
736 colocation = (const pcmk__colocation_t *) cons_iter->data;
737 if (colocation->score == INFINITY) {
738 pcmk__add_this_with(list, colocation);
739 }
740 }
741
742 break;
743 }
744 }
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764 void
765 pcmk__group_add_colocated_node_scores(pe_resource_t *rsc, const char *log_id,
766 GHashTable **nodes, const char *attr,
767 float factor, uint32_t flags)
768 {
769 pe_resource_t *member = NULL;
770
771 CRM_CHECK((rsc != NULL) && (nodes != NULL), return);
772
773 if (log_id == NULL) {
774 log_id = rsc->id;
775 }
776
777
778 if (pcmk_is_set(rsc->flags, pe_rsc_merging)) {
779 pe_rsc_info(rsc, "%s: Breaking dependency loop at %s",
780 log_id, rsc->id);
781 return;
782 }
783 pe__set_resource_flags(rsc, pe_rsc_merging);
784
785
786 if (rsc->children == NULL) {
787 return;
788 }
789
790
791
792
793
794
795
796
797
798
799
800 if (*nodes == NULL) {
801 member = pe__last_group_member(rsc);
802 } else {
803 member = rsc->children->data;
804 }
805 pe_rsc_trace(rsc, "%s: Merging scores from group %s using member %s "
806 "(at %.6f)", log_id, rsc->id, member->id, factor);
807 member->cmds->add_colocated_node_scores(member, log_id, nodes, attr, factor,
808 flags);
809 pe__clear_resource_flags(rsc, pe_rsc_merging);
810 }
811
812
813 void
814 pcmk__group_add_utilization(const pe_resource_t *rsc,
815 const pe_resource_t *orig_rsc, GList *all_rscs,
816 GHashTable *utilization)
817 {
818 pe_resource_t *member = NULL;
819
820 CRM_ASSERT((rsc != NULL) && (orig_rsc != NULL) && (utilization != NULL));
821
822 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
823 return;
824 }
825
826 pe_rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
827 orig_rsc->id, rsc->id);
828 if (pe__group_flag_is_set(rsc, pe__group_colocated)
829 || pe_rsc_is_clone(rsc->parent)) {
830
831 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
832 member = (pe_resource_t *) iter->data;
833
834 if (pcmk_is_set(member->flags, pe_rsc_provisional)
835 && (g_list_find(all_rscs, member) == NULL)) {
836 member->cmds->add_utilization(member, orig_rsc, all_rscs,
837 utilization);
838 }
839 }
840
841 } else if (rsc->children != NULL) {
842
843 member = (pe_resource_t *) rsc->children->data;
844 if ((member != NULL)
845 && pcmk_is_set(member->flags, pe_rsc_provisional)
846 && (g_list_find(all_rscs, member) == NULL)) {
847
848 member->cmds->add_utilization(member, orig_rsc, all_rscs,
849 utilization);
850 }
851 }
852 }
853
854
855 void
856 pcmk__group_shutdown_lock(pe_resource_t *rsc)
857 {
858 CRM_ASSERT(rsc != NULL);
859
860 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
861 pe_resource_t *member = (pe_resource_t *) iter->data;
862
863 member->cmds->shutdown_lock(member);
864 }
865 }