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