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