This source file includes following definitions.
- pcmk__clone_assign
- pcmk__clone_create_actions
- pcmk__clone_internal_constraints
- can_interleave
- pcmk__clone_apply_coloc_score
- pcmk__with_clone_colocations
- pcmk__clone_with_colocations
- pcmk__clone_action_flags
- pcmk__clone_apply_location
- call_action_flags
- pcmk__clone_add_actions_to_graph
- rsc_probed_on
- find_probed_instance_on
- probe_anonymous_clone
- pcmk__clone_create_probe
- pcmk__clone_add_graph_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/common/xml.h>
13 #include <pacemaker-internal.h>
14
15 #include "libpacemaker_private.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 pcmk_node_t *
37 pcmk__clone_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
38 bool stop_if_fail)
39 {
40 GList *colocations = NULL;
41
42 pcmk__assert(pcmk__is_clone(rsc));
43
44 if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
45 return NULL;
46 }
47
48
49 if (pcmk_is_set(rsc->flags, pcmk_rsc_assigning)) {
50 pcmk__rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
51 return NULL;
52 }
53 pcmk__set_rsc_flags(rsc, pcmk_rsc_assigning);
54
55
56 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
57 pcmk__add_promotion_scores(rsc);
58 }
59
60
61 colocations = pcmk__this_with_colocations(rsc);
62 for (GList *iter = colocations; iter != NULL; iter = iter->next) {
63 pcmk__colocation_t *constraint = (pcmk__colocation_t *) iter->data;
64
65 pcmk__rsc_trace(rsc, "%s: Assigning colocation %s primary %s first",
66 rsc->id, constraint->id, constraint->primary->id);
67 constraint->primary->cmds->assign(constraint->primary, prefer,
68 stop_if_fail);
69 }
70 g_list_free(colocations);
71
72
73 colocations = pcmk__with_this_colocations(rsc);
74 g_list_foreach(colocations, pcmk__add_dependent_scores, rsc);
75 g_list_free(colocations);
76
77 pe__show_node_scores(!pcmk_is_set(rsc->cluster->flags,
78 pcmk_sched_output_scores),
79 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
80
81 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance);
82 pcmk__assign_instances(rsc, rsc->children, pe__clone_max(rsc),
83 pe__clone_node_max(rsc));
84
85 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
86 pcmk__set_instance_roles(rsc);
87 }
88
89 pcmk__clear_rsc_flags(rsc, pcmk_rsc_unassigned|pcmk_rsc_assigning);
90 pcmk__rsc_trace(rsc, "Assigned clone %s", rsc->id);
91 return NULL;
92 }
93
94
95
96
97
98
99
100 void
101 pcmk__clone_create_actions(pcmk_resource_t *rsc)
102 {
103 pcmk__assert(pcmk__is_clone(rsc));
104
105 pcmk__rsc_trace(rsc, "Creating actions for clone %s", rsc->id);
106 pcmk__create_instance_actions(rsc, rsc->children);
107 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
108 pcmk__create_promotable_actions(rsc);
109 }
110 }
111
112
113
114
115
116
117
118 void
119 pcmk__clone_internal_constraints(pcmk_resource_t *rsc)
120 {
121 bool ordered = false;
122
123 pcmk__assert(pcmk__is_clone(rsc));
124
125 pcmk__rsc_trace(rsc, "Creating internal constraints for clone %s", rsc->id);
126
127
128 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOPPED,
129 rsc, PCMK_ACTION_START,
130 pcmk__ar_ordered);
131 pcmk__order_resource_actions(rsc, PCMK_ACTION_START,
132 rsc, PCMK_ACTION_RUNNING,
133 pcmk__ar_unrunnable_first_blocks);
134 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP,
135 rsc, PCMK_ACTION_STOPPED,
136 pcmk__ar_unrunnable_first_blocks);
137
138
139 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
140 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTED,
141 rsc, PCMK_ACTION_STOP,
142 pcmk__ar_ordered);
143 pcmk__order_resource_actions(rsc, PCMK_ACTION_RUNNING,
144 rsc, PCMK_ACTION_PROMOTE,
145 pcmk__ar_unrunnable_first_blocks);
146 }
147
148 ordered = pe__clone_is_ordered(rsc);
149 if (ordered) {
150
151
152
153
154 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
155 }
156 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
157 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
158
159 instance->cmds->internal_constraints(instance);
160
161
162 pcmk__order_starts(rsc, instance, pcmk__ar_unrunnable_first_blocks
163 |pcmk__ar_then_implies_first_graphed);
164 pcmk__order_resource_actions(instance, PCMK_ACTION_START,
165 rsc, PCMK_ACTION_RUNNING,
166 pcmk__ar_first_implies_then_graphed);
167
168
169 pcmk__order_stops(rsc, instance, pcmk__ar_then_implies_first_graphed);
170 pcmk__order_resource_actions(instance, PCMK_ACTION_STOP,
171 rsc, PCMK_ACTION_STOPPED,
172 pcmk__ar_first_implies_then_graphed);
173
174
175
176
177
178 if (ordered) {
179 for (GList *later = iter->next;
180 later != NULL; later = later->next) {
181 pcmk__order_starts(instance, (pcmk_resource_t *) later->data,
182 pcmk__ar_ordered);
183 pcmk__order_stops((pcmk_resource_t *) later->data, instance,
184 pcmk__ar_ordered);
185 }
186 }
187 }
188 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
189 pcmk__order_promotable_instances(rsc);
190 }
191 }
192
193
194
195
196
197
198
199
200
201 static bool
202 can_interleave(const pcmk__colocation_t *colocation)
203 {
204 const pcmk_resource_t *dependent = colocation->dependent;
205
206
207 if (dependent->variant <= pcmk_rsc_variant_group) {
208 return false;
209 }
210
211
212 if (!crm_is_true(g_hash_table_lookup(dependent->meta,
213 PCMK_META_INTERLEAVE))) {
214 return false;
215 }
216
217
218
219
220 if (dependent->fns->max_per_node(dependent)
221 != colocation->primary->fns->max_per_node(colocation->primary)) {
222 pcmk__config_err("Cannot interleave %s and %s because they do not "
223 "support the same number of instances per node",
224 dependent->id, colocation->primary->id);
225 return false;
226 }
227
228 return true;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 int
247 pcmk__clone_apply_coloc_score(pcmk_resource_t *dependent,
248 const pcmk_resource_t *primary,
249 const pcmk__colocation_t *colocation,
250 bool for_dependent)
251 {
252 const GList *iter = NULL;
253 int priority_delta = 0;
254
255
256
257
258
259 pcmk__assert(!for_dependent && (colocation != NULL)
260 && pcmk__is_clone(primary) && pcmk__is_primitive(dependent));
261
262 if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
263 pcmk__rsc_trace(primary,
264 "Delaying processing colocation %s "
265 "because cloned primary %s is still provisional",
266 colocation->id, primary->id);
267 return 0;
268 }
269
270 pcmk__rsc_trace(primary, "Processing colocation %s (%s with clone %s @%s)",
271 colocation->id, dependent->id, primary->id,
272 pcmk_readable_score(colocation->score));
273
274
275 if (pcmk_is_set(primary->flags, pcmk_rsc_promotable)
276 && (colocation->primary_role != pcmk_role_unknown)) {
277
278 if (pcmk_is_set(dependent->flags, pcmk_rsc_unassigned)) {
279
280 pcmk__update_dependent_with_promotable(primary, dependent,
281 colocation);
282 return 0;
283 }
284
285 if (colocation->dependent_role == pcmk_role_promoted) {
286
287 return pcmk__update_promotable_dependent_priority(primary,
288 dependent,
289 colocation);
290 }
291 }
292
293
294 if (can_interleave(colocation)) {
295 const pcmk_resource_t *primary_instance = NULL;
296
297 primary_instance = pcmk__find_compatible_instance(dependent, primary,
298 pcmk_role_unknown,
299 false);
300 if (primary_instance != NULL) {
301 pcmk__rsc_debug(primary, "Interleaving %s with %s",
302 dependent->id, primary_instance->id);
303
304 return dependent->cmds->apply_coloc_score(dependent,
305 primary_instance,
306 colocation, true);
307 }
308
309 if (colocation->score >= PCMK_SCORE_INFINITY) {
310 crm_notice("%s cannot run because it cannot interleave with "
311 "any instance of %s", dependent->id, primary->id);
312 pcmk__assign_resource(dependent, NULL, true, true);
313
314 } else {
315 pcmk__rsc_debug(primary,
316 "%s will not colocate with %s "
317 "because no instance can interleave with it",
318 dependent->id, primary->id);
319 }
320
321 return 0;
322 }
323
324
325 if (colocation->score >= PCMK_SCORE_INFINITY) {
326 GList *primary_nodes = NULL;
327
328
329 for (iter = primary->children; iter != NULL; iter = iter->next) {
330 const pcmk_resource_t *instance = iter->data;
331 pcmk_node_t *chosen = instance->fns->location(instance, NULL, 0);
332
333 if ((chosen != NULL)
334 && !is_set_recursive(instance, pcmk_rsc_blocked, TRUE)) {
335 pcmk__rsc_trace(primary, "Allowing %s: %s %d",
336 colocation->id, pcmk__node_name(chosen),
337 chosen->weight);
338 primary_nodes = g_list_prepend(primary_nodes, chosen);
339 }
340 }
341 pcmk__colocation_intersect_nodes(dependent, primary, colocation,
342 primary_nodes, false);
343 g_list_free(primary_nodes);
344 return 0;
345 }
346
347
348 for (iter = primary->children; iter != NULL; iter = iter->next) {
349 const pcmk_resource_t *instance = iter->data;
350 int instance_delta = instance->cmds->apply_coloc_score(dependent,
351 instance,
352 colocation,
353 false);
354
355 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
356 }
357 return priority_delta;
358 }
359
360
361 void
362 pcmk__with_clone_colocations(const pcmk_resource_t *rsc,
363 const pcmk_resource_t *orig_rsc, GList **list)
364 {
365 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
366
367 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
368
369 if (rsc->parent != NULL) {
370 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc, list);
371 }
372 }
373
374
375 void
376 pcmk__clone_with_colocations(const pcmk_resource_t *rsc,
377 const pcmk_resource_t *orig_rsc, GList **list)
378 {
379 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
380
381 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
382
383 if (rsc->parent != NULL) {
384 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc, list);
385 }
386 }
387
388
389
390
391
392
393
394
395
396
397 uint32_t
398 pcmk__clone_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
399 {
400 pcmk__assert((action != NULL) && pcmk__is_clone(action->rsc));
401
402 return pcmk__collective_action_flags(action, action->rsc->children, node);
403 }
404
405
406
407
408
409
410
411
412 void
413 pcmk__clone_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
414 {
415 CRM_CHECK((location != NULL) && pcmk__is_clone(rsc), return);
416
417 pcmk__apply_location(rsc, location);
418
419 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
420 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
421
422 instance->cmds->apply_location(instance, location);
423 }
424 }
425
426
427 static void
428 call_action_flags(gpointer data, gpointer user_data)
429 {
430 pcmk_resource_t *rsc = user_data;
431
432 rsc->cmds->action_flags((pcmk_action_t *) data, NULL);
433 }
434
435
436
437
438
439
440
441 void
442 pcmk__clone_add_actions_to_graph(pcmk_resource_t *rsc)
443 {
444 pcmk__assert(pcmk__is_clone(rsc));
445
446 g_list_foreach(rsc->actions, call_action_flags, rsc);
447 pe__create_clone_notifications(rsc);
448
449 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
450 pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
451
452 child_rsc->cmds->add_actions_to_graph(child_rsc);
453 }
454
455 pcmk__add_rsc_actions_to_graph(rsc);
456 pe__free_clone_notification_data(rsc);
457 }
458
459
460
461
462
463
464
465
466
467
468
469 static bool
470 rsc_probed_on(const pcmk_resource_t *rsc, const pcmk_node_t *node)
471 {
472 if (rsc->children != NULL) {
473 for (GList *child_iter = rsc->children; child_iter != NULL;
474 child_iter = child_iter->next) {
475
476 pcmk_resource_t *child = (pcmk_resource_t *) child_iter->data;
477
478 if (rsc_probed_on(child, node)) {
479 return true;
480 }
481 }
482 return false;
483 }
484
485 if (rsc->known_on != NULL) {
486 GHashTableIter iter;
487 pcmk_node_t *known_node = NULL;
488
489 g_hash_table_iter_init(&iter, rsc->known_on);
490 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
491 if (pcmk__same_node(node, known_node)) {
492 return true;
493 }
494 }
495 }
496 return false;
497 }
498
499
500
501
502
503
504
505
506
507
508
509 static pcmk_resource_t *
510 find_probed_instance_on(const pcmk_resource_t *clone, const pcmk_node_t *node)
511 {
512 for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
513 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
514
515 if (rsc_probed_on(instance, node)) {
516 return instance;
517 }
518 }
519 return NULL;
520 }
521
522
523
524
525
526
527
528
529 static bool
530 probe_anonymous_clone(pcmk_resource_t *clone, pcmk_node_t *node)
531 {
532
533 pcmk_resource_t *child = find_probed_instance_on(clone, node);
534
535
536 for (GList *iter = clone->children; (iter != NULL) && (child == NULL);
537 iter = iter->next) {
538 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
539 const pcmk_node_t *instance_node = NULL;
540
541 instance_node = instance->fns->location(instance, NULL, 0);
542 if (pcmk__same_node(instance_node, node)) {
543 child = instance;
544 }
545 }
546
547
548 if (child == NULL) {
549 child = clone->children->data;
550 }
551
552
553 return child->cmds->create_probe(child, node);
554 }
555
556
557
558
559
560
561
562
563
564
565 bool
566 pcmk__clone_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
567 {
568 pcmk__assert((node != NULL) && pcmk__is_clone(rsc));
569
570 if (rsc->exclusive_discover) {
571
572
573
574
575
576
577
578
579
580 pcmk_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes,
581 node->details->id);
582
583 if ((allowed == NULL)
584 || (allowed->rsc_discover_mode != pcmk_probe_exclusive)) {
585
586
587
588
589 pcmk__rsc_trace(rsc,
590 "Skipping probe for %s on %s because resource has "
591 "exclusive discovery but is not allowed on node",
592 rsc->id, pcmk__node_name(node));
593 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
594 return false;
595 }
596 }
597
598 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
599 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
600 return pcmk__probe_resource_list(rsc->children, node);
601 } else {
602 return probe_anonymous_clone(rsc, node);
603 }
604 }
605
606
607
608
609
610
611
612
613
614
615 void
616 pcmk__clone_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
617 {
618 char *name = NULL;
619
620 pcmk__assert(pcmk__is_clone(rsc) && (xml != NULL));
621
622 name = crm_meta_name(PCMK_META_GLOBALLY_UNIQUE);
623 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
624 free(name);
625
626 name = crm_meta_name(PCMK_META_NOTIFY);
627 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk_rsc_notify));
628 free(name);
629
630 name = crm_meta_name(PCMK_META_CLONE_MAX);
631 crm_xml_add_int(xml, name, pe__clone_max(rsc));
632 free(name);
633
634 name = crm_meta_name(PCMK_META_CLONE_NODE_MAX);
635 crm_xml_add_int(xml, name, pe__clone_node_max(rsc));
636 free(name);
637
638 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
639 int promoted_max = pe__clone_promoted_max(rsc);
640 int promoted_node_max = pe__clone_promoted_node_max(rsc);
641
642 name = crm_meta_name(PCMK_META_PROMOTED_MAX);
643 crm_xml_add_int(xml, name, promoted_max);
644 free(name);
645
646 name = crm_meta_name(PCMK_META_PROMOTED_NODE_MAX);
647 crm_xml_add_int(xml, name, promoted_node_max);
648 free(name);
649
650
651
652
653 name = crm_meta_name(PCMK__META_PROMOTED_MAX_LEGACY);
654 crm_xml_add_int(xml, name, promoted_max);
655 free(name);
656
657 name = crm_meta_name(PCMK__META_PROMOTED_NODE_MAX_LEGACY);
658 crm_xml_add_int(xml, name, promoted_node_max);
659 free(name);
660 }
661 }
662
663
664 void
665 pcmk__clone_add_utilization(const pcmk_resource_t *rsc,
666 const pcmk_resource_t *orig_rsc, GList *all_rscs,
667 GHashTable *utilization)
668 {
669 bool existing = false;
670 pcmk_resource_t *child = NULL;
671
672 pcmk__assert(pcmk__is_clone(rsc) && (orig_rsc != NULL)
673 && (utilization != NULL));
674
675 if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
676 return;
677 }
678
679
680 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
681 child = (pcmk_resource_t *) iter->data;
682 if (g_list_find(all_rscs, child)) {
683 existing = true;
684 } else {
685
686 for (GList *member_iter = child->children; member_iter != NULL;
687 member_iter = member_iter->next) {
688
689 pcmk_resource_t *member = (pcmk_resource_t *) member_iter->data;
690
691 if (g_list_find(all_rscs, member) != NULL) {
692
693 child->cmds->add_utilization(child, orig_rsc, all_rscs,
694 utilization);
695 existing = true;
696 break;
697 }
698 }
699 }
700 }
701
702 if (!existing && (rsc->children != NULL)) {
703
704 child = (pcmk_resource_t *) rsc->children->data;
705
706 child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
707 }
708 }
709
710
711 void
712 pcmk__clone_shutdown_lock(pcmk_resource_t *rsc)
713 {
714 pcmk__assert(pcmk__is_clone(rsc));
715 return;
716 }