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 <crm/msg_xml.h>
13
14 #include <pacemaker-internal.h>
15
16 #define VARIANT_GROUP 1
17 #include <lib/pengine/variant.h>
18
19 pe_node_t *
20 pcmk__group_allocate(pe_resource_t *rsc, pe_node_t *prefer,
21 pe_working_set_t *data_set)
22 {
23 pe_node_t *node = NULL;
24 pe_node_t *group_node = NULL;
25 GListPtr gIter = NULL;
26 group_variant_data_t *group_data = NULL;
27
28 get_group_variant_data(group_data, rsc);
29
30 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
31 return rsc->allocated_to;
32 }
33 if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
34 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
35 return NULL;
36 }
37
38 if (group_data->first_child == NULL) {
39
40 pe__clear_resource_flags(rsc, pe_rsc_provisional);
41 return NULL;
42 }
43
44 pe__set_resource_flags(rsc, pe_rsc_allocating);
45 rsc->role = group_data->first_child->role;
46
47 group_data->first_child->rsc_cons =
48 g_list_concat(group_data->first_child->rsc_cons, rsc->rsc_cons);
49 rsc->rsc_cons = NULL;
50
51 group_data->last_child->rsc_cons_lhs =
52 g_list_concat(group_data->last_child->rsc_cons_lhs, rsc->rsc_cons_lhs);
53 rsc->rsc_cons_lhs = NULL;
54
55 pe__show_node_weights(!show_scores, rsc, __func__, rsc->allowed_nodes);
56
57 gIter = rsc->children;
58 for (; gIter != NULL; gIter = gIter->next) {
59 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
60
61 pe_rsc_trace(rsc, "Allocating group %s member %s",
62 rsc->id, child_rsc->id);
63 node = child_rsc->cmds->allocate(child_rsc, prefer, data_set);
64 if (group_node == NULL) {
65 group_node = node;
66 }
67 }
68
69 rsc->next_role = group_data->first_child->next_role;
70 pe__clear_resource_flags(rsc, pe_rsc_allocating|pe_rsc_provisional);
71
72 if (group_data->colocated) {
73 return group_node;
74 }
75 return NULL;
76 }
77
78 void group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child);
79
80 void
81 group_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
82 {
83 pe_action_t *op = NULL;
84 const char *value = NULL;
85 GListPtr gIter = rsc->children;
86
87 pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
88
89 for (; gIter != NULL; gIter = gIter->next) {
90 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
91
92 child_rsc->cmds->create_actions(child_rsc, data_set);
93 group_update_pseudo_status(rsc, child_rsc);
94 }
95
96 op = start_action(rsc, NULL, TRUE );
97 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
98
99 op = custom_action(rsc, started_key(rsc),
100 RSC_STARTED, NULL, TRUE , TRUE, data_set);
101 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
102
103 op = stop_action(rsc, NULL, TRUE );
104 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
105
106 op = custom_action(rsc, stopped_key(rsc),
107 RSC_STOPPED, NULL, TRUE , TRUE, data_set);
108 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
109
110 value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE);
111 if (crm_is_true(value)) {
112 op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set);
113 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
114
115 op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set);
116 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
117
118 op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set);
119 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
120
121 op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set);
122 pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
123 }
124 }
125
126 void
127 group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child)
128 {
129 GListPtr gIter = child->actions;
130 group_variant_data_t *group_data = NULL;
131
132 get_group_variant_data(group_data, parent);
133
134 if (group_data->ordered == FALSE) {
135
136 return;
137 }
138
139 if (group_data->child_stopping && group_data->child_starting) {
140 return;
141 }
142
143 for (; gIter != NULL; gIter = gIter->next) {
144 pe_action_t *action = (pe_action_t *) gIter->data;
145
146 if (pcmk_is_set(action->flags, pe_action_optional)) {
147 continue;
148 }
149 if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)
150 && pcmk_is_set(action->flags, pe_action_runnable)) {
151
152 group_data->child_stopping = TRUE;
153 pe_rsc_trace(action->rsc, "Based on %s the group is stopping", action->uuid);
154
155 } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)
156 && pcmk_is_set(action->flags, pe_action_runnable)) {
157 group_data->child_starting = TRUE;
158 pe_rsc_trace(action->rsc, "Based on %s the group is starting", action->uuid);
159 }
160 }
161 }
162
163 void
164 group_internal_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
165 {
166 GListPtr gIter = rsc->children;
167 pe_resource_t *last_rsc = NULL;
168 pe_resource_t *last_active = NULL;
169 pe_resource_t *top = uber_parent(rsc);
170 group_variant_data_t *group_data = NULL;
171
172 get_group_variant_data(group_data, rsc);
173
174 new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
175 new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
176 new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
177
178 for (; gIter != NULL; gIter = gIter->next) {
179 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
180 int stop = pe_order_none;
181 int stopped = pe_order_implies_then_printed;
182 int start = pe_order_implies_then | pe_order_runnable_left;
183 int started =
184 pe_order_runnable_left | pe_order_implies_then | pe_order_implies_then_printed;
185
186 child_rsc->cmds->internal_constraints(child_rsc, data_set);
187
188 if (last_rsc == NULL) {
189 if (group_data->ordered) {
190 pe__set_order_flags(stop, pe_order_optional);
191 stopped = pe_order_implies_then;
192 }
193
194 } else if (group_data->colocated) {
195 rsc_colocation_new("group:internal_colocation", NULL, INFINITY,
196 child_rsc, last_rsc, NULL, NULL, data_set);
197 }
198
199 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
200 new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE,
201 stop | pe_order_implies_first_printed, data_set);
202
203 new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set);
204
205 new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set);
206
207 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
208 pe_order_implies_first_printed, data_set);
209
210 }
211
212 order_start_start(rsc, child_rsc, pe_order_implies_first_printed);
213 order_stop_stop(rsc, child_rsc, stop | pe_order_implies_first_printed);
214
215 new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set);
216
217 new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set);
218
219 if (group_data->ordered == FALSE) {
220 order_start_start(rsc, child_rsc, start | pe_order_implies_first_printed);
221 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
222 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
223 start | pe_order_implies_first_printed, data_set);
224 }
225
226 } else if (last_rsc != NULL) {
227 child_rsc->restart_type = pe_restart_restart;
228
229 order_start_start(last_rsc, child_rsc, start);
230 order_stop_stop(child_rsc, last_rsc, pe_order_optional | pe_order_restart);
231
232 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
233 new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set);
234 new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_optional,
235 data_set);
236 }
237
238 } else {
239
240
241
242
243
244
245 int flags = pe_order_none;
246
247 order_start_start(rsc, child_rsc, flags);
248 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
249 new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, flags, data_set);
250 }
251
252 }
253
254
255
256
257 if (child_rsc->running_on) {
258 if (group_data->ordered
259 && last_rsc
260 && last_rsc->running_on == NULL && last_active && last_active->running_on) {
261 order_stop_stop(child_rsc, last_active, pe_order_optional);
262 }
263 last_active = child_rsc;
264 }
265
266 last_rsc = child_rsc;
267 }
268
269 if (group_data->ordered && last_rsc != NULL) {
270 int stop_stop_flags = pe_order_implies_then;
271 int stop_stopped_flags = pe_order_optional;
272
273 order_stop_stop(rsc, last_rsc, stop_stop_flags);
274 new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set);
275
276 if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
277 new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set);
278 new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set);
279 }
280 }
281 }
282
283 void
284 group_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
285 rsc_colocation_t *constraint,
286 pe_working_set_t *data_set)
287 {
288 GListPtr gIter = NULL;
289 group_variant_data_t *group_data = NULL;
290
291 if (rsc_lh == NULL) {
292 pe_err("rsc_lh was NULL for %s", constraint->id);
293 return;
294
295 } else if (rsc_rh == NULL) {
296 pe_err("rsc_rh was NULL for %s", constraint->id);
297 return;
298 }
299 if (constraint->score == 0) {
300 return;
301 }
302
303 gIter = rsc_lh->children;
304 pe_rsc_trace(rsc_lh, "Processing constraints from %s", rsc_lh->id);
305
306 get_group_variant_data(group_data, rsc_lh);
307
308 if (group_data->colocated) {
309 group_data->first_child->cmds->rsc_colocation_lh(group_data->first_child,
310 rsc_rh, constraint,
311 data_set);
312 return;
313
314 } else if (constraint->score >= INFINITY) {
315 pcmk__config_err("%s: Cannot perform mandatory colocation "
316 "between non-colocated group and %s",
317 rsc_lh->id, rsc_rh->id);
318 return;
319 }
320
321 for (; gIter != NULL; gIter = gIter->next) {
322 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
323
324 child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint,
325 data_set);
326 }
327 }
328
329 void
330 group_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
331 rsc_colocation_t *constraint,
332 pe_working_set_t *data_set)
333 {
334 GListPtr gIter = rsc_rh->children;
335 group_variant_data_t *group_data = NULL;
336
337 get_group_variant_data(group_data, rsc_rh);
338 CRM_CHECK(rsc_lh->variant == pe_native, return);
339
340 if (constraint->score == 0) {
341 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 GListPtr 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 GListPtr 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 GListPtr gIter = rsc->children;
455 GListPtr saved = constraint->node_list_rh;
456 GListPtr 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 (GListPtr 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 GListPtr 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 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
518
519 if (constraint->score == 0) {
520 continue;
521 }
522 nodes = pcmk__native_merge_weights(constraint->rsc_lh, rsc->id, nodes,
523 constraint->node_attribute,
524 constraint->score / (float) INFINITY,
525 flags);
526 }
527
528 pe__clear_resource_flags(rsc, pe_rsc_merging);
529 return nodes;
530 }
531
532 void
533 group_append_meta(pe_resource_t * rsc, xmlNode * xml)
534 {
535 }