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