This source file includes following definitions.
- expand_group_colocations
- pcmk__group_allocate
- group_create_actions
- group_update_pseudo_status
- group_internal_constraints
- group_rsc_colocation_lh
- group_rsc_colocation_rh
- group_action_flags
- group_update_actions
- group_rsc_location
- group_expand
- pcmk__group_merge_weights
- group_append_meta
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
18 #define VARIANT_GROUP 1
19 #include <lib/pengine/variant.h>
20
21
22
23
24
25
26
27 static void
28 expand_group_colocations(pe_resource_t *rsc)
29 {
30 group_variant_data_t *group_data = NULL;
31 pe_resource_t *member = NULL;
32 bool any_unmanaged = false;
33
34 get_group_variant_data(group_data, rsc);
35
36
37 member = group_data->first_child;
38 member->rsc_cons = g_list_concat(member->rsc_cons, rsc->rsc_cons);
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 any_unmanaged = !pcmk_is_set(member->flags, pe_rsc_managed);
55 for (GList *item = rsc->children->next; item != NULL; item = item->next) {
56 member = item->data;
57 if (any_unmanaged) {
58 for (GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
59 cons_iter = cons_iter->next) {
60
61 pcmk__colocation_t *constraint = (pcmk__colocation_t *) cons_iter->data;
62
63 if (constraint->score == INFINITY) {
64 member->rsc_cons = g_list_prepend(member->rsc_cons, constraint);
65 }
66 }
67 } else if (!pcmk_is_set(member->flags, pe_rsc_managed)) {
68 any_unmanaged = true;
69 }
70 }
71
72 rsc->rsc_cons = NULL;
73
74
75 member = group_data->last_child;
76 member->rsc_cons_lhs = g_list_concat(member->rsc_cons_lhs,
77 rsc->rsc_cons_lhs);
78 rsc->rsc_cons_lhs = NULL;
79 }
80
81 pe_node_t *
82 pcmk__group_allocate(pe_resource_t *rsc, pe_node_t *prefer,
83 pe_working_set_t *data_set)
84 {
85 pe_node_t *node = NULL;
86 pe_node_t *group_node = NULL;
87 GList *gIter = NULL;
88 group_variant_data_t *group_data = NULL;
89
90 get_group_variant_data(group_data, rsc);
91
92 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
93 return rsc->allocated_to;
94 }
95 if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
96 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
97 return NULL;
98 }
99
100 if (group_data->first_child == NULL) {
101
102 pe__clear_resource_flags(rsc, pe_rsc_provisional);
103 return NULL;
104 }
105
106 pe__set_resource_flags(rsc, pe_rsc_allocating);
107 rsc->role = group_data->first_child->role;
108
109 expand_group_colocations(rsc);
110
111 pe__show_node_weights(!pcmk_is_set(data_set->flags, pe_flag_show_scores),
112 rsc, __func__, rsc->allowed_nodes, data_set);
113
114 gIter = rsc->children;
115 for (; gIter != NULL; gIter = gIter->next) {
116 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
117
118 pe_rsc_trace(rsc, "Allocating group %s member %s",
119 rsc->id, child_rsc->id);
120 node = child_rsc->cmds->allocate(child_rsc, prefer, data_set);
121 if (group_node == NULL) {
122 group_node = node;
123 }
124 }
125
126 pe__set_next_role(rsc, group_data->first_child->next_role,
127 "first group member");
128 pe__clear_resource_flags(rsc, pe_rsc_allocating|pe_rsc_provisional);
129
130 if (group_data->colocated) {
131 return group_node;
132 }
133 return NULL;
134 }
135
136 void group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child);
137
138 void
139 group_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
140 {
141 pe_action_t *op = NULL;
142 const char *value = NULL;
143 GList *gIter = rsc->children;
144
145 pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
146
147 for (; gIter != NULL; gIter = gIter->next) {
148 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
149
150 child_rsc->cmds->create_actions(child_rsc, data_set);
151 group_update_pseudo_status(rsc, child_rsc);
152 }
153
154 op = start_action(rsc, NULL, TRUE );
155 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
156
157 op = custom_action(rsc, started_key(rsc),
158 RSC_STARTED, NULL, TRUE , TRUE, data_set);
159 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
160
161 op = stop_action(rsc, NULL, TRUE );
162 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
163
164 op = custom_action(rsc, stopped_key(rsc),
165 RSC_STOPPED, NULL, TRUE , TRUE, data_set);
166 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
167
168 value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE);
169 if (crm_is_true(value)) {
170 op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set);
171 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
172
173 op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set);
174 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
175
176 op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set);
177 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
178
179 op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set);
180 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
181 }
182 }
183
184 void
185 group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child)
186 {
187 GList *gIter = child->actions;
188 group_variant_data_t *group_data = NULL;
189
190 get_group_variant_data(group_data, parent);
191
192 if (group_data->ordered == FALSE) {
193
194 return;
195 }
196
197 if (group_data->child_stopping && group_data->child_starting) {
198 return;
199 }
200
201 for (; gIter != NULL; gIter = gIter->next) {
202 pe_action_t *action = (pe_action_t *) gIter->data;
203
204 if (pcmk_is_set(action->flags, pe_action_optional)) {
205 continue;
206 }
207 if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)
208 && pcmk_is_set(action->flags, pe_action_runnable)) {
209
210 group_data->child_stopping = TRUE;
211 pe_rsc_trace(action->rsc, "Based on %s the group is stopping", action->uuid);
212
213 } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)
214 && pcmk_is_set(action->flags, pe_action_runnable)) {
215 group_data->child_starting = TRUE;
216 pe_rsc_trace(action->rsc, "Based on %s the group is starting", action->uuid);
217 }
218 }
219 }
220
221 void
222 group_internal_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
223 {
224 GList *gIter = rsc->children;
225 pe_resource_t *last_rsc = NULL;
226 pe_resource_t *last_active = NULL;
227 pe_resource_t *top = uber_parent(rsc);
228 group_variant_data_t *group_data = NULL;
229
230 get_group_variant_data(group_data, rsc);
231
232 new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
233 new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
234 new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
235
236 for (; gIter != NULL; gIter = gIter->next) {
237 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
238 int stop = pe_order_none;
239 int stopped = pe_order_implies_then_printed;
240 int start = pe_order_implies_then | pe_order_runnable_left;
241 int started =
242 pe_order_runnable_left | pe_order_implies_then | pe_order_implies_then_printed;
243
244 child_rsc->cmds->internal_constraints(child_rsc, data_set);
245
246 if (last_rsc == NULL) {
247 if (group_data->ordered) {
248 pe__set_order_flags(stop, pe_order_optional);
249 stopped = pe_order_implies_then;
250 }
251
252 } else if (group_data->colocated) {
253 pcmk__new_colocation("group:internal_colocation", NULL, INFINITY,
254 child_rsc, last_rsc, NULL, NULL,
255 pcmk_is_set(child_rsc->flags, pe_rsc_critical),
256 data_set);
257 }
258
259 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
260 new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE,
261 stop | pe_order_implies_first_printed, data_set);
262
263 new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set);
264
265 new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set);
266
267 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
268 pe_order_implies_first_printed, data_set);
269
270 }
271
272 order_start_start(rsc, child_rsc, pe_order_implies_first_printed);
273 order_stop_stop(rsc, child_rsc, stop | pe_order_implies_first_printed);
274
275 new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set);
276
277 new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set);
278
279 if (group_data->ordered == FALSE) {
280 order_start_start(rsc, child_rsc, start | pe_order_implies_first_printed);
281 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
282 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
283 start | pe_order_implies_first_printed, data_set);
284 }
285
286 } else if (last_rsc != NULL) {
287 order_start_start(last_rsc, child_rsc, start);
288 order_stop_stop(child_rsc, last_rsc, pe_order_optional | pe_order_restart);
289
290 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
291 new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set);
292 new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_optional,
293 data_set);
294 }
295
296 } else {
297 order_start_start(rsc, child_rsc, pe_order_none);
298 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
299 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
300 pe_order_none, data_set);
301 }
302 }
303
304
305
306
307 if (child_rsc->running_on) {
308 if (group_data->ordered
309 && last_rsc
310 && last_rsc->running_on == NULL && last_active && last_active->running_on) {
311 order_stop_stop(child_rsc, last_active, pe_order_optional);
312 }
313 last_active = child_rsc;
314 }
315
316 last_rsc = child_rsc;
317 }
318
319 if (group_data->ordered && last_rsc != NULL) {
320 int stop_stop_flags = pe_order_implies_then;
321 int stop_stopped_flags = pe_order_optional;
322
323 order_stop_stop(rsc, last_rsc, stop_stop_flags);
324 new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set);
325
326 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
327 new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set);
328 new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set);
329 }
330 }
331 }
332
333 void
334 group_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
335 pcmk__colocation_t *constraint,
336 pe_working_set_t *data_set)
337 {
338 GList *gIter = NULL;
339 group_variant_data_t *group_data = NULL;
340
341 if (rsc_lh == NULL) {
342 pe_err("rsc_lh was NULL for %s", constraint->id);
343 return;
344
345 } else if (rsc_rh == NULL) {
346 pe_err("rsc_rh was NULL for %s", constraint->id);
347 return;
348 }
349
350 gIter = rsc_lh->children;
351 pe_rsc_trace(rsc_lh, "Processing constraints from %s", rsc_lh->id);
352
353 get_group_variant_data(group_data, rsc_lh);
354
355 if (group_data->colocated) {
356 group_data->first_child->cmds->rsc_colocation_lh(group_data->first_child,
357 rsc_rh, constraint,
358 data_set);
359 return;
360
361 } else if (constraint->score >= INFINITY) {
362 pcmk__config_err("%s: Cannot perform mandatory colocation "
363 "between non-colocated group and %s",
364 rsc_lh->id, rsc_rh->id);
365 return;
366 }
367
368 for (; gIter != NULL; gIter = gIter->next) {
369 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
370
371 child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint,
372 data_set);
373 }
374 }
375
376 void
377 group_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
378 pcmk__colocation_t *constraint,
379 pe_working_set_t *data_set)
380 {
381 GList *gIter = rsc_rh->children;
382 group_variant_data_t *group_data = NULL;
383
384 get_group_variant_data(group_data, rsc_rh);
385 CRM_CHECK(rsc_lh->variant == pe_native, return);
386
387 pe_rsc_trace(rsc_rh, "Processing RH %s of constraint %s (LH is %s)",
388 rsc_rh->id, constraint->id, rsc_lh->id);
389
390 if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
391 return;
392
393 } else if (group_data->colocated && group_data->first_child) {
394 if (constraint->score >= INFINITY) {
395
396 group_data->last_child->cmds->rsc_colocation_rh(rsc_lh,
397 group_data->last_child,
398 constraint,
399 data_set);
400 } else {
401
402 group_data->first_child->cmds->rsc_colocation_rh(rsc_lh,
403 group_data->first_child,
404 constraint,
405 data_set);
406 }
407
408 return;
409
410 } else if (constraint->score >= INFINITY) {
411 pcmk__config_err("%s: Cannot perform mandatory colocation with"
412 " non-colocated group %s", rsc_lh->id, rsc_rh->id);
413 return;
414 }
415
416 for (; gIter != NULL; gIter = gIter->next) {
417 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
418
419 child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
420 data_set);
421 }
422 }
423
424 enum pe_action_flags
425 group_action_flags(pe_action_t * action, pe_node_t * node)
426 {
427 GList *gIter = NULL;
428 enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
429
430 for (gIter = action->rsc->children; gIter != NULL; gIter = gIter->next) {
431 pe_resource_t *child = (pe_resource_t *) gIter->data;
432 enum action_tasks task = get_complex_task(child, action->task, TRUE);
433 const char *task_s = task2text(task);
434 pe_action_t *child_action = find_first_action(child->actions, NULL, task_s, node);
435
436 if (child_action) {
437 enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
438
439 if (pcmk_is_set(flags, pe_action_optional)
440 && !pcmk_is_set(child_flags, pe_action_optional)) {
441 pe_rsc_trace(action->rsc, "%s is mandatory because of %s", action->uuid,
442 child_action->uuid);
443 pe__clear_raw_action_flags(flags, "group action",
444 pe_action_optional);
445 pe__clear_action_flags(action, pe_action_optional);
446 }
447 if (!pcmk__str_eq(task_s, action->task, pcmk__str_casei)
448 && pcmk_is_set(flags, pe_action_runnable)
449 && !pcmk_is_set(child_flags, pe_action_runnable)) {
450
451 pe_rsc_trace(action->rsc, "%s is not runnable because of %s", action->uuid,
452 child_action->uuid);
453 pe__clear_raw_action_flags(flags, "group action",
454 pe_action_runnable);
455 pe__clear_action_flags(action, pe_action_runnable);
456 }
457
458 } else if (task != stop_rsc && task != action_demote) {
459 pe_rsc_trace(action->rsc, "%s is not runnable because of %s (not found in %s)",
460 action->uuid, task_s, child->id);
461 pe__clear_raw_action_flags(flags, "group action",
462 pe_action_runnable);
463 }
464 }
465
466 return flags;
467 }
468
469 enum pe_graph_flags
470 group_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node,
471 enum pe_action_flags flags, enum pe_action_flags filter,
472 enum pe_ordering type, pe_working_set_t *data_set)
473 {
474 GList *gIter = then->rsc->children;
475 enum pe_graph_flags changed = pe_graph_none;
476
477 CRM_ASSERT(then->rsc != NULL);
478 changed |= native_update_actions(first, then, node, flags, filter, type,
479 data_set);
480
481 for (; gIter != NULL; gIter = gIter->next) {
482 pe_resource_t *child = (pe_resource_t *) gIter->data;
483 pe_action_t *child_action = find_first_action(child->actions, NULL, then->task, node);
484
485 if (child_action) {
486 changed |= child->cmds->update_actions(first, child_action, node,
487 flags, filter, type,
488 data_set);
489 }
490 }
491
492 return changed;
493 }
494
495 void
496 group_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
497 {
498 GList *gIter = rsc->children;
499 GList *saved = constraint->node_list_rh;
500 GList *zero = pcmk__copy_node_list(constraint->node_list_rh, true);
501 gboolean reset_scores = TRUE;
502 group_variant_data_t *group_data = NULL;
503
504 get_group_variant_data(group_data, rsc);
505
506 pe_rsc_debug(rsc, "Processing rsc_location %s for %s", constraint->id, rsc->id);
507
508 native_rsc_location(rsc, constraint);
509
510 for (; gIter != NULL; gIter = gIter->next) {
511 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
512
513 child_rsc->cmds->rsc_location(child_rsc, constraint);
514 if (group_data->colocated && reset_scores) {
515 reset_scores = FALSE;
516 constraint->node_list_rh = zero;
517 }
518 }
519
520 constraint->node_list_rh = saved;
521 g_list_free_full(zero, free);
522 }
523
524 void
525 group_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
526 {
527 CRM_CHECK(rsc != NULL, return);
528
529 pe_rsc_trace(rsc, "Processing actions from %s", rsc->id);
530 native_expand(rsc, data_set);
531
532 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
533 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
534
535 child_rsc->cmds->expand(child_rsc, data_set);
536 }
537 }
538
539 GHashTable *
540 pcmk__group_merge_weights(pe_resource_t *rsc, const char *rhs,
541 GHashTable *nodes, const char *attr, float factor,
542 uint32_t flags)
543 {
544 GList *gIter = rsc->rsc_cons_lhs;
545 group_variant_data_t *group_data = NULL;
546
547 get_group_variant_data(group_data, rsc);
548
549 if (pcmk_is_set(rsc->flags, pe_rsc_merging)) {
550 pe_rsc_info(rsc, "Breaking dependency loop with %s at %s", rsc->id, rhs);
551 return nodes;
552 }
553
554 pe__set_resource_flags(rsc, pe_rsc_merging);
555
556 nodes =
557 group_data->first_child->cmds->merge_weights(group_data->first_child, rhs, nodes, attr,
558 factor, flags);
559
560 for (; gIter != NULL; gIter = gIter->next) {
561 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
562
563 nodes = pcmk__native_merge_weights(constraint->rsc_lh, rsc->id, nodes,
564 constraint->node_attribute,
565 constraint->score / (float) INFINITY,
566 flags);
567 }
568
569 pe__clear_resource_flags(rsc, pe_rsc_merging);
570 return nodes;
571 }
572
573 void
574 group_append_meta(pe_resource_t * rsc, xmlNode * xml)
575 {
576 }