This source file includes following definitions.
- pcmk__clone_assign
- find_rsc_action
- order_instance_starts_stops
- clone_create_actions
- clone_internal_constraints
- pcmk__clone_apply_coloc_score
- pcmk__with_clone_colocations
- pcmk__clone_with_colocations
- clone_action_flags
- clone_rsc_location
- clone_expand
- rsc_known_on
- find_instance_on
- probe_anonymous_clone
- clone_create_probe
- clone_append_meta
- pcmk__clone_add_utilization
- pcmk__clone_shutdown_lock
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/msg_xml.h>
13 #include <pacemaker-internal.h>
14
15 #include "libpacemaker_private.h"
16
17
18
19
20
21
22
23
24
25
26 pe_node_t *
27 pcmk__clone_assign(pe_resource_t *rsc, const pe_node_t *prefer)
28 {
29 CRM_ASSERT(pe_rsc_is_clone(rsc));
30
31 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
32 return NULL;
33 }
34
35
36 if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
37 pe_rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
38 return NULL;
39 }
40 pe__set_resource_flags(rsc, pe_rsc_allocating);
41
42
43 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
44 pcmk__add_promotion_scores(rsc);
45 }
46
47
48
49
50
51 for (GList *iter = rsc->rsc_cons; iter != NULL; iter = iter->next) {
52 pcmk__colocation_t *constraint = (pcmk__colocation_t *) iter->data;
53
54 pe_rsc_trace(rsc, "%s: Assigning colocation %s primary %s first",
55 rsc->id, constraint->id, constraint->primary->id);
56 constraint->primary->cmds->assign(constraint->primary, prefer);
57 }
58
59
60
61
62
63 g_list_foreach(rsc->rsc_cons_lhs, pcmk__add_dependent_scores, rsc);
64
65 pe__show_node_weights(!pcmk_is_set(rsc->cluster->flags, pe_flag_show_scores),
66 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
67
68 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance);
69 pcmk__assign_instances(rsc, rsc->children, pe__clone_max(rsc),
70 pe__clone_node_max(rsc));
71
72 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
73 pcmk__set_instance_roles(rsc);
74 }
75
76 pe__clear_resource_flags(rsc, pe_rsc_provisional|pe_rsc_allocating);
77 pe_rsc_trace(rsc, "Assigned clone %s", rsc->id);
78 return NULL;
79 }
80
81 static pe_action_t *
82 find_rsc_action(pe_resource_t *rsc, const char *task)
83 {
84 pe_action_t *match = NULL;
85 GList *actions = pe__resource_actions(rsc, NULL, task, FALSE);
86
87 for (GList *item = actions; item != NULL; item = item->next) {
88 pe_action_t *op = (pe_action_t *) item->data;
89
90 if (!pcmk_is_set(op->flags, pe_action_optional)) {
91 if (match != NULL) {
92
93 match = NULL;
94 break;
95 }
96 match = op;
97 }
98 }
99 g_list_free(actions);
100 return match;
101 }
102
103
104
105
106
107
108
109 static void
110 order_instance_starts_stops(pe_resource_t *rsc)
111 {
112 pe_action_t *last_stop = NULL;
113 pe_action_t *last_start = NULL;
114
115
116 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
117
118 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
119 pe_resource_t *child = (pe_resource_t *) iter->data;
120 pe_action_t *action = NULL;
121
122
123
124 action = find_rsc_action(child, RSC_STOP);
125 if (action != NULL) {
126 if (last_stop != NULL) {
127 order_actions(action, last_stop, pe_order_optional);
128 }
129 last_stop = action;
130 }
131
132
133 action = find_rsc_action(child, RSC_START);
134 if (action != NULL) {
135 if (last_start != NULL) {
136 order_actions(last_start, action, pe_order_optional);
137 }
138 last_start = action;
139 }
140 }
141 }
142
143 void
144 clone_create_actions(pe_resource_t *rsc)
145 {
146 pe_rsc_debug(rsc, "Creating actions for clone %s", rsc->id);
147 pcmk__create_instance_actions(rsc, rsc->children);
148 if (pe__clone_is_ordered(rsc)) {
149 order_instance_starts_stops(rsc);
150 }
151 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
152 pcmk__create_promotable_actions(rsc);
153 }
154 }
155
156 void
157 clone_internal_constraints(pe_resource_t *rsc)
158 {
159 pe_resource_t *last_rsc = NULL;
160 GList *gIter;
161 bool ordered = pe__clone_is_ordered(rsc);
162
163 pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
164 pcmk__order_resource_actions(rsc, RSC_STOPPED, rsc, RSC_START,
165 pe_order_optional);
166 pcmk__order_resource_actions(rsc, RSC_START, rsc, RSC_STARTED,
167 pe_order_runnable_left);
168 pcmk__order_resource_actions(rsc, RSC_STOP, rsc, RSC_STOPPED,
169 pe_order_runnable_left);
170
171 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
172 pcmk__order_resource_actions(rsc, RSC_DEMOTED, rsc, RSC_STOP,
173 pe_order_optional);
174 pcmk__order_resource_actions(rsc, RSC_STARTED, rsc, RSC_PROMOTE,
175 pe_order_runnable_left);
176 }
177
178 if (ordered) {
179
180 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
181 }
182 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
183 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
184
185 child_rsc->cmds->internal_constraints(child_rsc);
186
187 pcmk__order_starts(rsc, child_rsc,
188 pe_order_runnable_left|pe_order_implies_first_printed);
189 pcmk__order_resource_actions(child_rsc, RSC_START, rsc, RSC_STARTED,
190 pe_order_implies_then_printed);
191 if (ordered && (last_rsc != NULL)) {
192 pcmk__order_starts(last_rsc, child_rsc, pe_order_optional);
193 }
194
195 pcmk__order_stops(rsc, child_rsc, pe_order_implies_first_printed);
196 pcmk__order_resource_actions(child_rsc, RSC_STOP, rsc, RSC_STOPPED,
197 pe_order_implies_then_printed);
198 if (ordered && (last_rsc != NULL)) {
199 pcmk__order_stops(child_rsc, last_rsc, pe_order_optional);
200 }
201
202 last_rsc = child_rsc;
203 }
204 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
205 pcmk__order_promotable_instances(rsc);
206 }
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 void
223 pcmk__clone_apply_coloc_score(pe_resource_t *dependent,
224 const pe_resource_t *primary,
225 const pcmk__colocation_t *colocation,
226 bool for_dependent)
227 {
228 GList *gIter = NULL;
229 gboolean do_interleave = FALSE;
230 const char *interleave_s = NULL;
231
232
233
234
235
236 CRM_ASSERT(!for_dependent);
237
238 CRM_CHECK((colocation != NULL) && (dependent != NULL) && (primary != NULL),
239 return);
240 CRM_CHECK(dependent->variant == pe_native, return);
241
242 pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
243 colocation->id, dependent->id, primary->id, colocation->score);
244
245 if (pcmk_is_set(primary->flags, pe_rsc_promotable)) {
246 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
247
248 pe_rsc_trace(primary, "%s is still provisional", primary->id);
249 return;
250
251 } else if (colocation->primary_role == RSC_ROLE_UNKNOWN) {
252
253 pe_rsc_trace(primary, "Handling %s as a clone colocation",
254 colocation->id);
255
256 } else if (pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
257
258 pcmk__update_dependent_with_promotable(primary, dependent,
259 colocation);
260 return;
261
262 } else if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
263
264 pcmk__update_promotable_dependent_priority(primary, dependent,
265 colocation);
266 return;
267 }
268 }
269
270
271 interleave_s = g_hash_table_lookup(colocation->dependent->meta,
272 XML_RSC_ATTR_INTERLEAVE);
273 if (crm_is_true(interleave_s)
274 && (colocation->dependent->variant > pe_group)) {
275
276
277
278 if (copies_per_node(colocation->dependent) != copies_per_node(colocation->primary)) {
279 pcmk__config_err("Cannot interleave %s and %s because they do not "
280 "support the same number of instances per node",
281 colocation->dependent->id,
282 colocation->primary->id);
283
284 } else {
285 do_interleave = TRUE;
286 }
287 }
288
289 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
290 pe_rsc_trace(primary, "%s is still provisional", primary->id);
291 return;
292
293 } else if (do_interleave) {
294 pe_resource_t *primary_instance = NULL;
295
296 primary_instance = pcmk__find_compatible_instance(dependent, primary,
297 RSC_ROLE_UNKNOWN,
298 false);
299 if (primary_instance != NULL) {
300 pe_rsc_debug(primary, "Pairing %s with %s",
301 dependent->id, primary_instance->id);
302 dependent->cmds->apply_coloc_score(dependent, primary_instance,
303 colocation, true);
304
305 } else if (colocation->score >= INFINITY) {
306 crm_notice("Cannot pair %s with instance of %s",
307 dependent->id, primary->id);
308 pcmk__assign_resource(dependent, NULL, true);
309
310 } else {
311 pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
312 dependent->id, primary->id);
313 }
314
315 return;
316
317 } else if (colocation->score >= INFINITY) {
318 GList *affected_nodes = NULL;
319
320 gIter = primary->children;
321 for (; gIter != NULL; gIter = gIter->next) {
322 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
323 pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
324
325 if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
326 pe_rsc_trace(primary, "Allowing %s: %s %d",
327 colocation->id, pe__node_name(chosen),
328 chosen->weight);
329 affected_nodes = g_list_prepend(affected_nodes, chosen);
330 }
331 }
332
333 node_list_exclude(dependent->allowed_nodes, affected_nodes, FALSE);
334 g_list_free(affected_nodes);
335 return;
336 }
337
338 gIter = primary->children;
339 for (; gIter != NULL; gIter = gIter->next) {
340 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
341
342 child_rsc->cmds->apply_coloc_score(dependent, child_rsc, colocation,
343 false);
344 }
345 }
346
347
348 void
349 pcmk__with_clone_colocations(const pe_resource_t *rsc,
350 const pe_resource_t *orig_rsc, GList **list)
351 {
352 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
353
354 if (rsc == orig_rsc) {
355 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs);
356 } else {
357 pcmk__add_collective_constraints(list, orig_rsc, rsc, true);
358 }
359 }
360
361
362 void
363 pcmk__clone_with_colocations(const pe_resource_t *rsc,
364 const pe_resource_t *orig_rsc, GList **list)
365 {
366 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
367
368 if (rsc == orig_rsc) {
369 pcmk__add_this_with_list(list, rsc->rsc_cons);
370 } else {
371 pcmk__add_collective_constraints(list, orig_rsc, rsc, false);
372 }
373 }
374
375 enum pe_action_flags
376 clone_action_flags(pe_action_t *action, const pe_node_t *node)
377 {
378 return pcmk__collective_action_flags(action, action->rsc->children, node);
379 }
380
381 void
382 clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
383 {
384 GList *gIter = rsc->children;
385
386 pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
387
388 pcmk__apply_location(rsc, constraint);
389
390 for (; gIter != NULL; gIter = gIter->next) {
391 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
392
393 child_rsc->cmds->apply_location(child_rsc, constraint);
394 }
395 }
396
397
398
399
400
401
402
403 void
404 clone_expand(pe_resource_t *rsc)
405 {
406 GList *gIter = NULL;
407
408 g_list_foreach(rsc->actions, (GFunc) rsc->cmds->action_flags, NULL);
409
410 pe__create_clone_notifications(rsc);
411
412
413
414 gIter = rsc->children;
415 for (; gIter != NULL; gIter = gIter->next) {
416 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
417
418 child_rsc->cmds->add_actions_to_graph(child_rsc);
419 }
420
421 pcmk__add_rsc_actions_to_graph(rsc);
422
423
424 pe__free_clone_notification_data(rsc);
425 }
426
427
428 static bool
429 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
430 {
431 if (rsc->children) {
432 for (GList *child_iter = rsc->children; child_iter != NULL;
433 child_iter = child_iter->next) {
434
435 pe_resource_t *child = (pe_resource_t *) child_iter->data;
436
437 if (rsc_known_on(child, node)) {
438 return TRUE;
439 }
440 }
441
442 } else if (rsc->known_on) {
443 GHashTableIter iter;
444 pe_node_t *known_node = NULL;
445
446 g_hash_table_iter_init(&iter, rsc->known_on);
447 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
448 if (node->details == known_node->details) {
449 return TRUE;
450 }
451 }
452 }
453 return FALSE;
454 }
455
456
457 static pe_resource_t *
458 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
459 {
460 for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
461 pe_resource_t *child = (pe_resource_t *) gIter->data;
462
463 if (rsc_known_on(child, node)) {
464 return child;
465 }
466 }
467 return NULL;
468 }
469
470
471 static bool
472 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
473 pe_working_set_t *data_set)
474 {
475
476 pe_resource_t *child = find_instance_on(rsc, node);
477
478
479 if (child == NULL) {
480 for (GList *child_iter = rsc->children; child_iter && !child;
481 child_iter = child_iter->next) {
482
483 pe_node_t *local_node = NULL;
484 pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
485
486 if (child_rsc) {
487 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
488 if (local_node && (local_node->details == node->details)) {
489 child = child_rsc;
490 }
491 }
492 }
493 }
494
495
496 if (child == NULL) {
497 child = rsc->children->data;
498 }
499 CRM_ASSERT(child);
500 return child->cmds->create_probe(child, node);
501 }
502
503
504
505
506
507
508
509
510
511
512
513 bool
514 clone_create_probe(pe_resource_t *rsc, pe_node_t *node)
515 {
516 CRM_ASSERT(rsc);
517
518 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
519 if (rsc->children == NULL) {
520 pe_warn("Clone %s has no children", rsc->id);
521 return false;
522 }
523
524 if (rsc->exclusive_discover) {
525 pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
526 if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
527
528
529
530
531
532
533
534 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
535
536
537 return false;
538 }
539 }
540
541 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
542 return pcmk__probe_resource_list(rsc->children, node);
543 } else {
544 return probe_anonymous_clone(rsc, node, rsc->cluster);
545 }
546 }
547
548 void
549 clone_append_meta(const pe_resource_t *rsc, xmlNode *xml)
550 {
551 char *name = NULL;
552
553 name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
554 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
555 free(name);
556
557 name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
558 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
559 free(name);
560
561 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
562 crm_xml_add_int(xml, name, pe__clone_max(rsc));
563 free(name);
564
565 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
566 crm_xml_add_int(xml, name, pe__clone_node_max(rsc));
567 free(name);
568
569 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
570 int promoted_max = pe__clone_promoted_max(rsc);
571 int promoted_node_max = pe__clone_promoted_node_max(rsc);
572
573 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_MAX);
574 crm_xml_add_int(xml, name, promoted_max);
575 free(name);
576
577 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_NODEMAX);
578 crm_xml_add_int(xml, name, promoted_node_max);
579 free(name);
580
581
582
583
584 name = crm_meta_name(PCMK_XA_PROMOTED_MAX_LEGACY);
585 crm_xml_add_int(xml, name, promoted_max);
586 free(name);
587
588 name = crm_meta_name(PCMK_XA_PROMOTED_NODE_MAX_LEGACY);
589 crm_xml_add_int(xml, name, promoted_node_max);
590 free(name);
591 }
592 }
593
594
595 void
596 pcmk__clone_add_utilization(const pe_resource_t *rsc,
597 const pe_resource_t *orig_rsc, GList *all_rscs,
598 GHashTable *utilization)
599 {
600 bool existing = false;
601 pe_resource_t *child = NULL;
602
603 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
604 return;
605 }
606
607
608 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
609 child = (pe_resource_t *) iter->data;
610 if (g_list_find(all_rscs, child)) {
611 existing = true;
612 } else {
613
614 for (GList *member_iter = child->children; member_iter != NULL;
615 member_iter = member_iter->next) {
616
617 pe_resource_t *member = (pe_resource_t *) member_iter->data;
618
619 if (g_list_find(all_rscs, member) != NULL) {
620
621 child->cmds->add_utilization(child, orig_rsc, all_rscs,
622 utilization);
623 existing = true;
624 break;
625 }
626 }
627 }
628 }
629
630 if (!existing && (rsc->children != NULL)) {
631
632 child = (pe_resource_t *) rsc->children->data;
633
634 child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
635 }
636 }
637
638
639 void
640 pcmk__clone_shutdown_lock(pe_resource_t *rsc)
641 {
642 return;
643 }