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 CRM_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 CRM_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 CRM_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 CRM_ASSERT(!for_dependent);
260
261 CRM_ASSERT((colocation != NULL) && pcmk__is_clone(primary)
262 && pcmk__is_primitive(dependent));
263
264 if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
265 pcmk__rsc_trace(primary,
266 "Delaying processing colocation %s "
267 "because cloned primary %s is still provisional",
268 colocation->id, primary->id);
269 return 0;
270 }
271
272 pcmk__rsc_trace(primary, "Processing colocation %s (%s with clone %s @%s)",
273 colocation->id, dependent->id, primary->id,
274 pcmk_readable_score(colocation->score));
275
276
277 if (pcmk_is_set(primary->flags, pcmk_rsc_promotable)
278 && (colocation->primary_role != pcmk_role_unknown)) {
279
280 if (pcmk_is_set(dependent->flags, pcmk_rsc_unassigned)) {
281
282 pcmk__update_dependent_with_promotable(primary, dependent,
283 colocation);
284 return 0;
285 }
286
287 if (colocation->dependent_role == pcmk_role_promoted) {
288
289 return pcmk__update_promotable_dependent_priority(primary,
290 dependent,
291 colocation);
292 }
293 }
294
295
296 if (can_interleave(colocation)) {
297 const pcmk_resource_t *primary_instance = NULL;
298
299 primary_instance = pcmk__find_compatible_instance(dependent, primary,
300 pcmk_role_unknown,
301 false);
302 if (primary_instance != NULL) {
303 pcmk__rsc_debug(primary, "Interleaving %s with %s",
304 dependent->id, primary_instance->id);
305
306 return dependent->cmds->apply_coloc_score(dependent,
307 primary_instance,
308 colocation, true);
309 }
310
311 if (colocation->score >= PCMK_SCORE_INFINITY) {
312 crm_notice("%s cannot run because it cannot interleave with "
313 "any instance of %s", dependent->id, primary->id);
314 pcmk__assign_resource(dependent, NULL, true, true);
315
316 } else {
317 pcmk__rsc_debug(primary,
318 "%s will not colocate with %s "
319 "because no instance can interleave with it",
320 dependent->id, primary->id);
321 }
322
323 return 0;
324 }
325
326
327 if (colocation->score >= PCMK_SCORE_INFINITY) {
328 GList *primary_nodes = NULL;
329
330
331 for (iter = primary->children; iter != NULL; iter = iter->next) {
332 const pcmk_resource_t *instance = iter->data;
333 pcmk_node_t *chosen = instance->fns->location(instance, NULL, 0);
334
335 if ((chosen != NULL)
336 && !is_set_recursive(instance, pcmk_rsc_blocked, TRUE)) {
337 pcmk__rsc_trace(primary, "Allowing %s: %s %d",
338 colocation->id, pcmk__node_name(chosen),
339 chosen->weight);
340 primary_nodes = g_list_prepend(primary_nodes, chosen);
341 }
342 }
343 pcmk__colocation_intersect_nodes(dependent, primary, colocation,
344 primary_nodes, false);
345 g_list_free(primary_nodes);
346 return 0;
347 }
348
349
350 for (iter = primary->children; iter != NULL; iter = iter->next) {
351 const pcmk_resource_t *instance = iter->data;
352 int instance_delta = instance->cmds->apply_coloc_score(dependent,
353 instance,
354 colocation,
355 false);
356
357 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
358 }
359 return priority_delta;
360 }
361
362
363 void
364 pcmk__with_clone_colocations(const pcmk_resource_t *rsc,
365 const pcmk_resource_t *orig_rsc, GList **list)
366 {
367 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
368
369 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
370
371 if (rsc->parent != NULL) {
372 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc, list);
373 }
374 }
375
376
377 void
378 pcmk__clone_with_colocations(const pcmk_resource_t *rsc,
379 const pcmk_resource_t *orig_rsc, GList **list)
380 {
381 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
382
383 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
384
385 if (rsc->parent != NULL) {
386 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc, list);
387 }
388 }
389
390
391
392
393
394
395
396
397
398
399 uint32_t
400 pcmk__clone_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
401 {
402 CRM_ASSERT((action != NULL) && pcmk__is_clone(action->rsc));
403
404 return pcmk__collective_action_flags(action, action->rsc->children, node);
405 }
406
407
408
409
410
411
412
413
414 void
415 pcmk__clone_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
416 {
417 CRM_CHECK((location != NULL) && pcmk__is_clone(rsc), return);
418
419 pcmk__apply_location(rsc, location);
420
421 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
422 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
423
424 instance->cmds->apply_location(instance, location);
425 }
426 }
427
428
429 static void
430 call_action_flags(gpointer data, gpointer user_data)
431 {
432 pcmk_resource_t *rsc = user_data;
433
434 rsc->cmds->action_flags((pcmk_action_t *) data, NULL);
435 }
436
437
438
439
440
441
442
443 void
444 pcmk__clone_add_actions_to_graph(pcmk_resource_t *rsc)
445 {
446 CRM_ASSERT(pcmk__is_clone(rsc));
447
448 g_list_foreach(rsc->actions, call_action_flags, rsc);
449 pe__create_clone_notifications(rsc);
450
451 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
452 pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
453
454 child_rsc->cmds->add_actions_to_graph(child_rsc);
455 }
456
457 pcmk__add_rsc_actions_to_graph(rsc);
458 pe__free_clone_notification_data(rsc);
459 }
460
461
462
463
464
465
466
467
468
469
470
471 static bool
472 rsc_probed_on(const pcmk_resource_t *rsc, const pcmk_node_t *node)
473 {
474 if (rsc->children != NULL) {
475 for (GList *child_iter = rsc->children; child_iter != NULL;
476 child_iter = child_iter->next) {
477
478 pcmk_resource_t *child = (pcmk_resource_t *) child_iter->data;
479
480 if (rsc_probed_on(child, node)) {
481 return true;
482 }
483 }
484 return false;
485 }
486
487 if (rsc->known_on != NULL) {
488 GHashTableIter iter;
489 pcmk_node_t *known_node = NULL;
490
491 g_hash_table_iter_init(&iter, rsc->known_on);
492 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
493 if (pcmk__same_node(node, known_node)) {
494 return true;
495 }
496 }
497 }
498 return false;
499 }
500
501
502
503
504
505
506
507
508
509
510
511 static pcmk_resource_t *
512 find_probed_instance_on(const pcmk_resource_t *clone, const pcmk_node_t *node)
513 {
514 for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
515 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
516
517 if (rsc_probed_on(instance, node)) {
518 return instance;
519 }
520 }
521 return NULL;
522 }
523
524
525
526
527
528
529
530
531 static bool
532 probe_anonymous_clone(pcmk_resource_t *clone, pcmk_node_t *node)
533 {
534
535 pcmk_resource_t *child = find_probed_instance_on(clone, node);
536
537
538 for (GList *iter = clone->children; (iter != NULL) && (child == NULL);
539 iter = iter->next) {
540 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
541 const pcmk_node_t *instance_node = NULL;
542
543 instance_node = instance->fns->location(instance, NULL, 0);
544 if (pcmk__same_node(instance_node, node)) {
545 child = instance;
546 }
547 }
548
549
550 if (child == NULL) {
551 child = clone->children->data;
552 }
553
554
555 return child->cmds->create_probe(child, node);
556 }
557
558
559
560
561
562
563
564
565
566
567 bool
568 pcmk__clone_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
569 {
570 CRM_ASSERT((node != NULL) && pcmk__is_clone(rsc));
571
572 if (rsc->exclusive_discover) {
573
574
575
576
577
578
579
580
581
582 pcmk_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes,
583 node->details->id);
584
585 if ((allowed == NULL)
586 || (allowed->rsc_discover_mode != pcmk_probe_exclusive)) {
587
588
589
590
591 pcmk__rsc_trace(rsc,
592 "Skipping probe for %s on %s because resource has "
593 "exclusive discovery but is not allowed on node",
594 rsc->id, pcmk__node_name(node));
595 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
596 return false;
597 }
598 }
599
600 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
601 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
602 return pcmk__probe_resource_list(rsc->children, node);
603 } else {
604 return probe_anonymous_clone(rsc, node);
605 }
606 }
607
608
609
610
611
612
613
614
615
616
617 void
618 pcmk__clone_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
619 {
620 char *name = NULL;
621
622 CRM_ASSERT(pcmk__is_clone(rsc) && (xml != NULL));
623
624 name = crm_meta_name(PCMK_META_GLOBALLY_UNIQUE);
625 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
626 free(name);
627
628 name = crm_meta_name(PCMK_META_NOTIFY);
629 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk_rsc_notify));
630 free(name);
631
632 name = crm_meta_name(PCMK_META_CLONE_MAX);
633 crm_xml_add_int(xml, name, pe__clone_max(rsc));
634 free(name);
635
636 name = crm_meta_name(PCMK_META_CLONE_NODE_MAX);
637 crm_xml_add_int(xml, name, pe__clone_node_max(rsc));
638 free(name);
639
640 if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
641 int promoted_max = pe__clone_promoted_max(rsc);
642 int promoted_node_max = pe__clone_promoted_node_max(rsc);
643
644 name = crm_meta_name(PCMK_META_PROMOTED_MAX);
645 crm_xml_add_int(xml, name, promoted_max);
646 free(name);
647
648 name = crm_meta_name(PCMK_META_PROMOTED_NODE_MAX);
649 crm_xml_add_int(xml, name, promoted_node_max);
650 free(name);
651
652
653
654
655 name = crm_meta_name(PCMK__META_PROMOTED_MAX_LEGACY);
656 crm_xml_add_int(xml, name, promoted_max);
657 free(name);
658
659 name = crm_meta_name(PCMK__META_PROMOTED_NODE_MAX_LEGACY);
660 crm_xml_add_int(xml, name, promoted_node_max);
661 free(name);
662 }
663 }
664
665
666 void
667 pcmk__clone_add_utilization(const pcmk_resource_t *rsc,
668 const pcmk_resource_t *orig_rsc, GList *all_rscs,
669 GHashTable *utilization)
670 {
671 bool existing = false;
672 pcmk_resource_t *child = NULL;
673
674 CRM_ASSERT(pcmk__is_clone(rsc) && (orig_rsc != NULL)
675 && (utilization != NULL));
676
677 if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
678 return;
679 }
680
681
682 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
683 child = (pcmk_resource_t *) iter->data;
684 if (g_list_find(all_rscs, child)) {
685 existing = true;
686 } else {
687
688 for (GList *member_iter = child->children; member_iter != NULL;
689 member_iter = member_iter->next) {
690
691 pcmk_resource_t *member = (pcmk_resource_t *) member_iter->data;
692
693 if (g_list_find(all_rscs, member) != NULL) {
694
695 child->cmds->add_utilization(child, orig_rsc, all_rscs,
696 utilization);
697 existing = true;
698 break;
699 }
700 }
701 }
702 }
703
704 if (!existing && (rsc->children != NULL)) {
705
706 child = (pcmk_resource_t *) rsc->children->data;
707
708 child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
709 }
710 }
711
712
713 void
714 pcmk__clone_shutdown_lock(pcmk_resource_t *rsc)
715 {
716 CRM_ASSERT(pcmk__is_clone(rsc));
717 return;
718 }