This source file includes following definitions.
- cmp_colocation_priority
- cmp_dependent_priority
- cmp_primary_priority
- pcmk__add_this_with
- pcmk__add_this_with_list
- pcmk__add_with_this
- pcmk__add_with_this_list
- anti_colocation_order
- pcmk__new_colocation
- unpack_influence
- unpack_colocation_set
- colocate_rsc_sets
- unpack_simple_colocation
- unpack_colocation_tags
- pcmk__unpack_colocation
- mark_action_blocked
- pcmk__block_colocation_dependents
- get_resource_for_role
- pcmk__colocation_affects
- pcmk__apply_coloc_to_scores
- pcmk__apply_coloc_to_priority
- best_node_score_matching_attr
- allowed_on_one
- add_node_scores_matching_attr
- pcmk__add_colocated_node_scores
- pcmk__add_dependent_scores
- pcmk__colocation_intersect_nodes
- pcmk__with_this_colocations
- pcmk__this_with_colocations
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <glib.h>
14
15 #include <crm/crm.h>
16 #include <crm/common/scheduler_internal.h>
17 #include <crm/pengine/status.h>
18 #include <pacemaker-internal.h>
19
20 #include "crm/common/util.h"
21 #include "crm/common/xml_internal.h"
22 #include "crm/msg_xml.h"
23 #include "libpacemaker_private.h"
24
25
26 #define INFINITY_HACK (INFINITY * -100)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 static gint
52 cmp_colocation_priority(const pcmk__colocation_t *colocation1,
53 const pcmk__colocation_t *colocation2, bool dependent)
54 {
55 const pcmk_resource_t *rsc1 = NULL;
56 const pcmk_resource_t *rsc2 = NULL;
57
58 if (colocation1 == NULL) {
59 return 1;
60 }
61 if (colocation2 == NULL) {
62 return -1;
63 }
64
65 if (dependent) {
66 rsc1 = colocation1->dependent;
67 rsc2 = colocation2->dependent;
68 CRM_ASSERT(colocation1->primary != NULL);
69 } else {
70 rsc1 = colocation1->primary;
71 rsc2 = colocation2->primary;
72 CRM_ASSERT(colocation1->dependent != NULL);
73 }
74 CRM_ASSERT((rsc1 != NULL) && (rsc2 != NULL));
75
76 if (rsc1->priority > rsc2->priority) {
77 return -1;
78 }
79 if (rsc1->priority < rsc2->priority) {
80 return 1;
81 }
82
83
84 if (rsc1->variant > rsc2->variant) {
85 return -1;
86 }
87 if (rsc1->variant < rsc2->variant) {
88 return 1;
89 }
90
91
92
93
94
95 if (rsc1->variant == pcmk_rsc_variant_clone) {
96 if (pcmk_is_set(rsc1->flags, pcmk_rsc_promotable)
97 && !pcmk_is_set(rsc2->flags, pcmk_rsc_promotable)) {
98 return -1;
99 }
100 if (!pcmk_is_set(rsc1->flags, pcmk_rsc_promotable)
101 && pcmk_is_set(rsc2->flags, pcmk_rsc_promotable)) {
102 return 1;
103 }
104 }
105
106 return strcmp(rsc1->id, rsc2->id);
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 static gint
130 cmp_dependent_priority(gconstpointer a, gconstpointer b)
131 {
132 return cmp_colocation_priority(a, b, true);
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 static gint
156 cmp_primary_priority(gconstpointer a, gconstpointer b)
157 {
158 return cmp_colocation_priority(a, b, false);
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172 void
173 pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation,
174 const pcmk_resource_t *rsc)
175 {
176 CRM_ASSERT((list != NULL) && (colocation != NULL) && (rsc != NULL));
177
178 pe_rsc_trace(rsc,
179 "Adding colocation %s (%s with %s using %s @%s) to "
180 "'this with' list for %s",
181 colocation->id, colocation->dependent->id,
182 colocation->primary->id, colocation->node_attribute,
183 pcmk_readable_score(colocation->score), rsc->id);
184 *list = g_list_insert_sorted(*list, (gpointer) colocation,
185 cmp_primary_priority);
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199 void
200 pcmk__add_this_with_list(GList **list, GList *addition,
201 const pcmk_resource_t *rsc)
202 {
203 CRM_ASSERT((list != NULL) && (rsc != NULL));
204
205 pcmk__if_tracing(
206 {},
207 {
208 if (*list == NULL) {
209
210 *list = g_list_copy(addition);
211 return;
212 }
213 }
214 );
215
216 for (const GList *iter = addition; iter != NULL; iter = iter->next) {
217 pcmk__add_this_with(list, addition->data, rsc);
218 }
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232 void
233 pcmk__add_with_this(GList **list, const pcmk__colocation_t *colocation,
234 const pcmk_resource_t *rsc)
235 {
236 CRM_ASSERT((list != NULL) && (colocation != NULL) && (rsc != NULL));
237
238 pe_rsc_trace(rsc,
239 "Adding colocation %s (%s with %s using %s @%s) to "
240 "'with this' list for %s",
241 colocation->id, colocation->dependent->id,
242 colocation->primary->id, colocation->node_attribute,
243 pcmk_readable_score(colocation->score), rsc->id);
244 *list = g_list_insert_sorted(*list, (gpointer) colocation,
245 cmp_dependent_priority);
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259 void
260 pcmk__add_with_this_list(GList **list, GList *addition,
261 const pcmk_resource_t *rsc)
262 {
263 CRM_ASSERT((list != NULL) && (rsc != NULL));
264
265 pcmk__if_tracing(
266 {},
267 {
268 if (*list == NULL) {
269
270 *list = g_list_copy(addition);
271 return;
272 }
273 }
274 );
275
276 for (const GList *iter = addition; iter != NULL; iter = iter->next) {
277 pcmk__add_with_this(list, addition->data, rsc);
278 }
279 }
280
281
282
283
284
285
286
287
288
289
290 static void
291 anti_colocation_order(pcmk_resource_t *first_rsc, int first_role,
292 pcmk_resource_t *then_rsc, int then_role)
293 {
294 const char *first_tasks[] = { NULL, NULL };
295 const char *then_tasks[] = { NULL, NULL };
296
297
298 if (first_role == pcmk_role_promoted) {
299 first_tasks[0] = PCMK_ACTION_DEMOTE;
300
301 } else {
302 first_tasks[0] = PCMK_ACTION_STOP;
303
304 if (first_role == pcmk_role_unpromoted) {
305 first_tasks[1] = PCMK_ACTION_PROMOTE;
306 }
307 }
308
309
310 if (then_role == pcmk_role_promoted) {
311 then_tasks[0] = PCMK_ACTION_PROMOTE;
312
313 } else {
314 then_tasks[0] = PCMK_ACTION_START;
315
316 if (then_role == pcmk_role_unpromoted) {
317 then_tasks[1] = PCMK_ACTION_DEMOTE;
318 }
319 }
320
321 for (int first_lpc = 0;
322 (first_lpc <= 1) && (first_tasks[first_lpc] != NULL); first_lpc++) {
323
324 for (int then_lpc = 0;
325 (then_lpc <= 1) && (then_tasks[then_lpc] != NULL); then_lpc++) {
326
327 pcmk__order_resource_actions(first_rsc, first_tasks[first_lpc],
328 then_rsc, then_tasks[then_lpc],
329 pcmk__ar_if_required_on_same_node);
330 }
331 }
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 void
348 pcmk__new_colocation(const char *id, const char *node_attr, int score,
349 pcmk_resource_t *dependent, pcmk_resource_t *primary,
350 const char *dependent_role, const char *primary_role,
351 uint32_t flags)
352 {
353 pcmk__colocation_t *new_con = NULL;
354
355 CRM_CHECK(id != NULL, return);
356
357 if ((dependent == NULL) || (primary == NULL)) {
358 pcmk__config_err("Ignoring colocation '%s' because resource "
359 "does not exist", id);
360 return;
361 }
362
363 if (score == 0) {
364 pe_rsc_trace(dependent,
365 "Ignoring colocation '%s' (%s with %s) because score is 0",
366 id, dependent->id, primary->id);
367 return;
368 }
369
370 new_con = calloc(1, sizeof(pcmk__colocation_t));
371 CRM_ASSERT(new_con != NULL);
372
373 if (pcmk__str_eq(dependent_role, PCMK__ROLE_STARTED,
374 pcmk__str_null_matches|pcmk__str_casei)) {
375 dependent_role = PCMK__ROLE_UNKNOWN;
376 }
377
378 if (pcmk__str_eq(primary_role, PCMK__ROLE_STARTED,
379 pcmk__str_null_matches|pcmk__str_casei)) {
380 primary_role = PCMK__ROLE_UNKNOWN;
381 }
382
383 new_con->id = id;
384 new_con->dependent = dependent;
385 new_con->primary = primary;
386 new_con->score = score;
387 new_con->dependent_role = text2role(dependent_role);
388 new_con->primary_role = text2role(primary_role);
389 new_con->node_attribute = pcmk__s(node_attr, CRM_ATTR_UNAME);
390 new_con->flags = flags;
391
392 pcmk__add_this_with(&(dependent->rsc_cons), new_con, dependent);
393 pcmk__add_with_this(&(primary->rsc_cons_lhs), new_con, primary);
394
395 dependent->cluster->colocation_constraints = g_list_prepend(
396 dependent->cluster->colocation_constraints, new_con);
397
398 if (score <= -INFINITY) {
399 anti_colocation_order(dependent, new_con->dependent_role, primary,
400 new_con->primary_role);
401 anti_colocation_order(primary, new_con->primary_role, dependent,
402 new_con->dependent_role);
403 }
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418 static uint32_t
419 unpack_influence(const char *coloc_id, const pcmk_resource_t *rsc,
420 const char *influence_s)
421 {
422 if (influence_s != NULL) {
423 int influence_i = 0;
424
425 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
426 pcmk__config_err("Constraint '%s' has invalid value for "
427 XML_COLOC_ATTR_INFLUENCE " (using default)",
428 coloc_id);
429 } else {
430 return (influence_i == 0)? pcmk__coloc_none : pcmk__coloc_influence;
431 }
432 }
433 if (pcmk_is_set(rsc->flags, pcmk_rsc_critical)) {
434 return pcmk__coloc_influence;
435 }
436 return pcmk__coloc_none;
437 }
438
439 static void
440 unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
441 const char *influence_s, pcmk_scheduler_t *scheduler)
442 {
443 xmlNode *xml_rsc = NULL;
444 pcmk_resource_t *other = NULL;
445 pcmk_resource_t *resource = NULL;
446 const char *set_id = ID(set);
447 const char *role = crm_element_value(set, "role");
448 bool with_previous = false;
449 int local_score = score;
450 bool sequential = false;
451 uint32_t flags = pcmk__coloc_none;
452 const char *xml_rsc_id = NULL;
453 const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE);
454
455 if (score_s) {
456 local_score = char2score(score_s);
457 }
458 if (local_score == 0) {
459 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
460 coloc_id, set_id);
461 return;
462 }
463
464
465
466
467 if (pcmk__str_eq(crm_element_value(set, "ordering"), "group",
468 pcmk__str_null_matches|pcmk__str_casei)) {
469 with_previous = true;
470 } else {
471 pe_warn_once(pcmk__wo_set_ordering,
472 "Support for 'ordering' other than 'group' in "
473 XML_CONS_TAG_RSC_SET " (such as %s) is deprecated and "
474 "will be removed in a future release", set_id);
475 }
476
477 if ((pcmk__xe_get_bool_attr(set, "sequential", &sequential) == pcmk_rc_ok)
478 && !sequential) {
479 return;
480 }
481
482 if (local_score > 0) {
483 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
484 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
485
486 xml_rsc_id = ID(xml_rsc);
487 resource = pcmk__find_constraint_resource(scheduler->resources,
488 xml_rsc_id);
489 if (resource == NULL) {
490
491 pcmk__config_err("Ignoring %s and later resources in set %s: "
492 "No such resource", xml_rsc_id, set_id);
493 return;
494 }
495 if (other != NULL) {
496 flags = pcmk__coloc_explicit
497 | unpack_influence(coloc_id, resource, influence_s);
498 if (with_previous) {
499 pe_rsc_trace(resource, "Colocating %s with %s in set %s",
500 resource->id, other->id, set_id);
501 pcmk__new_colocation(set_id, NULL, local_score, resource,
502 other, role, role, flags);
503 } else {
504 pe_rsc_trace(resource, "Colocating %s with %s in set %s",
505 other->id, resource->id, set_id);
506 pcmk__new_colocation(set_id, NULL, local_score, other,
507 resource, role, role, flags);
508 }
509 }
510 other = resource;
511 }
512
513 } else {
514
515
516
517
518
519 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
520 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
521
522 xmlNode *xml_rsc_with = NULL;
523
524 xml_rsc_id = ID(xml_rsc);
525 resource = pcmk__find_constraint_resource(scheduler->resources,
526 xml_rsc_id);
527 if (resource == NULL) {
528
529 pcmk__config_err("Ignoring %s and later resources in set %s: "
530 "No such resource", xml_rsc_id, set_id);
531 return;
532 }
533 flags = pcmk__coloc_explicit
534 | unpack_influence(coloc_id, resource, influence_s);
535 for (xml_rsc_with = first_named_child(set, XML_TAG_RESOURCE_REF);
536 xml_rsc_with != NULL;
537 xml_rsc_with = crm_next_same_xml(xml_rsc_with)) {
538
539 xml_rsc_id = ID(xml_rsc_with);
540 if (pcmk__str_eq(resource->id, xml_rsc_id, pcmk__str_none)) {
541 break;
542 }
543 other = pcmk__find_constraint_resource(scheduler->resources,
544 xml_rsc_id);
545 CRM_ASSERT(other != NULL);
546 pcmk__new_colocation(set_id, NULL, local_score,
547 resource, other, role, role, flags);
548 }
549 }
550 }
551 }
552
553
554
555
556
557
558
559
560
561
562
563
564 static void
565 colocate_rsc_sets(const char *id, const xmlNode *set1, const xmlNode *set2,
566 int score, const char *influence_s,
567 pcmk_scheduler_t *scheduler)
568 {
569 xmlNode *xml_rsc = NULL;
570 pcmk_resource_t *rsc_1 = NULL;
571 pcmk_resource_t *rsc_2 = NULL;
572
573 const char *xml_rsc_id = NULL;
574 const char *role_1 = crm_element_value(set1, "role");
575 const char *role_2 = crm_element_value(set2, "role");
576
577 int rc = pcmk_rc_ok;
578 bool sequential = false;
579 uint32_t flags = pcmk__coloc_none;
580
581 if (score == 0) {
582 crm_trace("Ignoring colocation '%s' between sets %s and %s "
583 "because score is 0", id, ID(set1), ID(set2));
584 return;
585 }
586
587 rc = pcmk__xe_get_bool_attr(set1, "sequential", &sequential);
588 if ((rc != pcmk_rc_ok) || sequential) {
589
590 xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
591 if (xml_rsc != NULL) {
592 xml_rsc_id = ID(xml_rsc);
593 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
594 xml_rsc_id);
595 if (rsc_1 == NULL) {
596
597 pcmk__config_err("Ignoring colocation of set %s with set %s "
598 "because first resource %s not found",
599 ID(set1), ID(set2), xml_rsc_id);
600 return;
601 }
602 }
603 }
604
605 rc = pcmk__xe_get_bool_attr(set2, "sequential", &sequential);
606 if ((rc != pcmk_rc_ok) || sequential) {
607
608 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
609 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
610
611 xml_rsc_id = ID(xml_rsc);
612 }
613 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
614 xml_rsc_id);
615 if (rsc_2 == NULL) {
616
617 pcmk__config_err("Ignoring colocation of set %s with set %s "
618 "because last resource %s not found",
619 ID(set1), ID(set2), xml_rsc_id);
620 return;
621 }
622 }
623
624 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
625 flags = pcmk__coloc_explicit | unpack_influence(id, rsc_1, influence_s);
626 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
627 flags);
628
629 } else if (rsc_1 != NULL) {
630 flags = pcmk__coloc_explicit | unpack_influence(id, rsc_1, influence_s);
631 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
632 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
633
634 xml_rsc_id = ID(xml_rsc);
635 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
636 xml_rsc_id);
637 if (rsc_2 == NULL) {
638
639 pcmk__config_err("Ignoring set %s colocation with resource %s "
640 "in set %s: No such resource",
641 ID(set1), xml_rsc_id, ID(set2));
642 continue;
643 }
644 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
645 role_2, flags);
646 }
647
648 } else if (rsc_2 != NULL) {
649 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
650 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
651
652 xml_rsc_id = ID(xml_rsc);
653 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
654 xml_rsc_id);
655 if (rsc_1 == NULL) {
656
657 pcmk__config_err("Ignoring colocation of set %s resource %s "
658 "with set %s: No such resource",
659 ID(set1), xml_rsc_id, ID(set2));
660 continue;
661 }
662 flags = pcmk__coloc_explicit
663 | unpack_influence(id, rsc_1, influence_s);
664 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
665 role_2, flags);
666 }
667
668 } else {
669 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
670 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
671
672 xmlNode *xml_rsc_2 = NULL;
673
674 xml_rsc_id = ID(xml_rsc);
675 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
676 xml_rsc_id);
677 if (rsc_1 == NULL) {
678
679 pcmk__config_err("Ignoring colocation of set %s resource %s "
680 "with set %s: No such resource",
681 ID(set1), xml_rsc_id, ID(set2));
682 continue;
683 }
684
685 flags = pcmk__coloc_explicit
686 | unpack_influence(id, rsc_1, influence_s);
687 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
688 xml_rsc_2 != NULL;
689 xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
690
691 xml_rsc_id = ID(xml_rsc_2);
692 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
693 xml_rsc_id);
694 if (rsc_2 == NULL) {
695
696 pcmk__config_err("Ignoring colocation of set %s resource "
697 "%s with set %s resource %s: No such "
698 "resource", ID(set1), ID(xml_rsc),
699 ID(set2), xml_rsc_id);
700 continue;
701 }
702 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
703 role_1, role_2, flags);
704 }
705 }
706 }
707 }
708
709 static void
710 unpack_simple_colocation(xmlNode *xml_obj, const char *id,
711 const char *influence_s, pcmk_scheduler_t *scheduler)
712 {
713 int score_i = 0;
714 uint32_t flags = pcmk__coloc_none;
715
716 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
717 const char *dependent_id = crm_element_value(xml_obj,
718 XML_COLOC_ATTR_SOURCE);
719 const char *primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
720 const char *dependent_role = crm_element_value(xml_obj,
721 XML_COLOC_ATTR_SOURCE_ROLE);
722 const char *primary_role = crm_element_value(xml_obj,
723 XML_COLOC_ATTR_TARGET_ROLE);
724 const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR);
725
726 const char *primary_instance = NULL;
727 const char *dependent_instance = NULL;
728 pcmk_resource_t *primary = NULL;
729 pcmk_resource_t *dependent = NULL;
730
731 primary = pcmk__find_constraint_resource(scheduler->resources, primary_id);
732 dependent = pcmk__find_constraint_resource(scheduler->resources,
733 dependent_id);
734
735
736 primary_instance = crm_element_value(xml_obj,
737 XML_COLOC_ATTR_TARGET_INSTANCE);
738 dependent_instance = crm_element_value(xml_obj,
739 XML_COLOC_ATTR_SOURCE_INSTANCE);
740 if (dependent_instance != NULL) {
741 pe_warn_once(pcmk__wo_coloc_inst,
742 "Support for " XML_COLOC_ATTR_SOURCE_INSTANCE " is "
743 "deprecated and will be removed in a future release.");
744 }
745 if (primary_instance != NULL) {
746 pe_warn_once(pcmk__wo_coloc_inst,
747 "Support for " XML_COLOC_ATTR_TARGET_INSTANCE " is "
748 "deprecated and will be removed in a future release.");
749 }
750
751 if (dependent == NULL) {
752 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
753 "does not exist", id, dependent_id);
754 return;
755
756 } else if (primary == NULL) {
757 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
758 "does not exist", id, primary_id);
759 return;
760
761 } else if ((dependent_instance != NULL) && !pe_rsc_is_clone(dependent)) {
762 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
763 "is not a clone but instance '%s' was requested",
764 id, dependent_id, dependent_instance);
765 return;
766
767 } else if ((primary_instance != NULL) && !pe_rsc_is_clone(primary)) {
768 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
769 "is not a clone but instance '%s' was requested",
770 id, primary_id, primary_instance);
771 return;
772 }
773
774 if (dependent_instance != NULL) {
775 dependent = find_clone_instance(dependent, dependent_instance);
776 if (dependent == NULL) {
777 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
778 "does not have an instance '%s'",
779 id, dependent_id, dependent_instance);
780 return;
781 }
782 }
783
784 if (primary_instance != NULL) {
785 primary = find_clone_instance(primary, primary_instance);
786 if (primary == NULL) {
787 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
788 "does not have an instance '%s'",
789 "'%s'", id, primary_id, primary_instance);
790 return;
791 }
792 }
793
794 if (pcmk__xe_attr_is_true(xml_obj, XML_CONS_ATTR_SYMMETRICAL)) {
795 pcmk__config_warn("The colocation constraint '"
796 XML_CONS_ATTR_SYMMETRICAL
797 "' attribute has been removed");
798 }
799
800 if (score) {
801 score_i = char2score(score);
802 }
803
804 flags = pcmk__coloc_explicit | unpack_influence(id, dependent, influence_s);
805 pcmk__new_colocation(id, attr, score_i, dependent, primary,
806 dependent_role, primary_role, flags);
807 }
808
809
810 static int
811 unpack_colocation_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
812 pcmk_scheduler_t *scheduler)
813 {
814 const char *id = NULL;
815 const char *dependent_id = NULL;
816 const char *primary_id = NULL;
817 const char *dependent_role = NULL;
818 const char *primary_role = NULL;
819
820 pcmk_resource_t *dependent = NULL;
821 pcmk_resource_t *primary = NULL;
822
823 pcmk_tag_t *dependent_tag = NULL;
824 pcmk_tag_t *primary_tag = NULL;
825
826 xmlNode *dependent_set = NULL;
827 xmlNode *primary_set = NULL;
828 bool any_sets = false;
829
830 *expanded_xml = NULL;
831
832 CRM_CHECK(xml_obj != NULL, return EINVAL);
833
834 id = ID(xml_obj);
835 if (id == NULL) {
836 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
837 xml_obj->name);
838 return pcmk_rc_unpack_error;
839 }
840
841
842 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
843 if (*expanded_xml != NULL) {
844 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
845 return pcmk_rc_ok;
846 }
847
848 dependent_id = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
849 primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
850 if ((dependent_id == NULL) || (primary_id == NULL)) {
851 return pcmk_rc_ok;
852 }
853
854 if (!pcmk__valid_resource_or_tag(scheduler, dependent_id, &dependent,
855 &dependent_tag)) {
856 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
857 "valid resource or tag", id, dependent_id);
858 return pcmk_rc_unpack_error;
859 }
860
861 if (!pcmk__valid_resource_or_tag(scheduler, primary_id, &primary,
862 &primary_tag)) {
863 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
864 "valid resource or tag", id, primary_id);
865 return pcmk_rc_unpack_error;
866 }
867
868 if ((dependent != NULL) && (primary != NULL)) {
869
870 return pcmk_rc_ok;
871 }
872
873 if ((dependent_tag != NULL) && (primary_tag != NULL)) {
874
875 pcmk__config_err("Ignoring constraint '%s' because two templates or "
876 "tags cannot be colocated", id);
877 return pcmk_rc_unpack_error;
878 }
879
880 dependent_role = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
881 primary_role = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
882
883 *expanded_xml = copy_xml(xml_obj);
884
885
886 if (!pcmk__tag_to_set(*expanded_xml, &dependent_set, XML_COLOC_ATTR_SOURCE,
887 true, scheduler)) {
888 free_xml(*expanded_xml);
889 *expanded_xml = NULL;
890 return pcmk_rc_unpack_error;
891 }
892
893 if (dependent_set != NULL) {
894 if (dependent_role != NULL) {
895
896 crm_xml_add(dependent_set, "role", dependent_role);
897 xml_remove_prop(*expanded_xml, XML_COLOC_ATTR_SOURCE_ROLE);
898 }
899 any_sets = true;
900 }
901
902
903 if (!pcmk__tag_to_set(*expanded_xml, &primary_set, XML_COLOC_ATTR_TARGET,
904 true, scheduler)) {
905 free_xml(*expanded_xml);
906 *expanded_xml = NULL;
907 return pcmk_rc_unpack_error;
908 }
909
910 if (primary_set != NULL) {
911 if (primary_role != NULL) {
912
913 crm_xml_add(primary_set, "role", primary_role);
914 xml_remove_prop(*expanded_xml, XML_COLOC_ATTR_TARGET_ROLE);
915 }
916 any_sets = true;
917 }
918
919 if (any_sets) {
920 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
921 } else {
922 free_xml(*expanded_xml);
923 *expanded_xml = NULL;
924 }
925
926 return pcmk_rc_ok;
927 }
928
929
930
931
932
933
934
935
936 void
937 pcmk__unpack_colocation(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
938 {
939 int score_i = 0;
940 xmlNode *set = NULL;
941 xmlNode *last = NULL;
942
943 xmlNode *orig_xml = NULL;
944 xmlNode *expanded_xml = NULL;
945
946 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
947 const char *score = NULL;
948 const char *influence_s = NULL;
949
950 if (pcmk__str_empty(id)) {
951 pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_DEPEND
952 " without " CRM_ATTR_ID);
953 return;
954 }
955
956 if (unpack_colocation_tags(xml_obj, &expanded_xml,
957 scheduler) != pcmk_rc_ok) {
958 return;
959 }
960 if (expanded_xml != NULL) {
961 orig_xml = xml_obj;
962 xml_obj = expanded_xml;
963 }
964
965 score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
966 if (score != NULL) {
967 score_i = char2score(score);
968 }
969 influence_s = crm_element_value(xml_obj, XML_COLOC_ATTR_INFLUENCE);
970
971 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
972 set = crm_next_same_xml(set)) {
973
974 set = expand_idref(set, scheduler->input);
975 if (set == NULL) {
976 if (expanded_xml != NULL) {
977 free_xml(expanded_xml);
978 }
979 return;
980 }
981
982 if (pcmk__str_empty(ID(set))) {
983 pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET
984 " without " CRM_ATTR_ID);
985 continue;
986 }
987 unpack_colocation_set(set, score_i, id, influence_s, scheduler);
988
989 if (last != NULL) {
990 colocate_rsc_sets(id, last, set, score_i, influence_s, scheduler);
991 }
992 last = set;
993 }
994
995 if (expanded_xml) {
996 free_xml(expanded_xml);
997 xml_obj = orig_xml;
998 }
999
1000 if (last == NULL) {
1001 unpack_simple_colocation(xml_obj, id, influence_s, scheduler);
1002 }
1003 }
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013 static void
1014 mark_action_blocked(pcmk_resource_t *rsc, const char *task,
1015 const pcmk_resource_t *reason)
1016 {
1017 GList *iter = NULL;
1018 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
1019
1020 for (iter = rsc->actions; iter != NULL; iter = iter->next) {
1021 pcmk_action_t *action = iter->data;
1022
1023 if (pcmk_is_set(action->flags, pcmk_action_runnable)
1024 && pcmk__str_eq(action->task, task, pcmk__str_none)) {
1025
1026 pe__clear_action_flags(action, pcmk_action_runnable);
1027 pe_action_set_reason(action, reason_text, false);
1028 pcmk__block_colocation_dependents(action);
1029 pcmk__update_action_for_orderings(action, rsc->cluster);
1030 }
1031 }
1032
1033
1034 for (iter = rsc->children; iter != NULL; iter = iter->next) {
1035 mark_action_blocked((pcmk_resource_t *) (iter->data), task, reason);
1036 }
1037 free(reason_text);
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050 void
1051 pcmk__block_colocation_dependents(pcmk_action_t *action)
1052 {
1053 GList *iter = NULL;
1054 GList *colocations = NULL;
1055 pcmk_resource_t *rsc = NULL;
1056 bool is_start = false;
1057
1058 if (pcmk_is_set(action->flags, pcmk_action_runnable)) {
1059 return;
1060 }
1061
1062 is_start = pcmk__str_eq(action->task, PCMK_ACTION_START, pcmk__str_none);
1063 if (!is_start
1064 && !pcmk__str_eq(action->task, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
1065 return;
1066 }
1067
1068 CRM_ASSERT(action->rsc != NULL);
1069
1070
1071
1072
1073
1074 rsc = uber_parent(action->rsc);
1075 if (rsc->parent != NULL) {
1076 rsc = rsc->parent;
1077 }
1078
1079
1080 for (iter = rsc->children; iter != NULL; iter = iter->next) {
1081 pcmk_resource_t *child = iter->data;
1082 pcmk_action_t *child_action = find_first_action(child->actions, NULL,
1083 action->task, NULL);
1084
1085 if ((child_action == NULL)
1086 || pcmk_is_set(child_action->flags, pcmk_action_runnable)) {
1087 crm_trace("Not blocking %s colocation dependents because "
1088 "at least %s has runnable %s",
1089 rsc->id, child->id, action->task);
1090 return;
1091 }
1092 }
1093
1094 crm_trace("Blocking %s colocation dependents due to unrunnable %s %s",
1095 rsc->id, action->rsc->id, action->task);
1096
1097
1098 colocations = pcmk__with_this_colocations(rsc);
1099 for (iter = colocations; iter != NULL; iter = iter->next) {
1100 pcmk__colocation_t *colocation = iter->data;
1101
1102 if (colocation->score < INFINITY) {
1103 continue;
1104 }
1105
1106
1107
1108
1109
1110
1111
1112 if (!is_start && (colocation->primary_role != pcmk_role_promoted)) {
1113 continue;
1114 }
1115
1116
1117 if (colocation->dependent_role == pcmk_role_promoted) {
1118 mark_action_blocked(colocation->dependent, PCMK_ACTION_PROMOTE,
1119 action->rsc);
1120 } else {
1121 mark_action_blocked(colocation->dependent, PCMK_ACTION_START,
1122 action->rsc);
1123 }
1124 }
1125 g_list_free(colocations);
1126 }
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146 static const pcmk_resource_t *
1147 get_resource_for_role(const pcmk_resource_t *rsc)
1148 {
1149 if (pcmk_is_set(rsc->flags, pcmk_rsc_replica_container)) {
1150 const pcmk_resource_t *child = pe__get_rsc_in_container(rsc);
1151
1152 if (child != NULL) {
1153 return child;
1154 }
1155 }
1156 return rsc;
1157 }
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177 enum pcmk__coloc_affects
1178 pcmk__colocation_affects(const pcmk_resource_t *dependent,
1179 const pcmk_resource_t *primary,
1180 const pcmk__colocation_t *colocation, bool preview)
1181 {
1182 const pcmk_resource_t *dependent_role_rsc = NULL;
1183 const pcmk_resource_t *primary_role_rsc = NULL;
1184
1185 CRM_ASSERT((dependent != NULL) && (primary != NULL)
1186 && (colocation != NULL));
1187
1188 if (!preview && pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
1189
1190 return pcmk__coloc_affects_nothing;
1191 }
1192
1193 dependent_role_rsc = get_resource_for_role(dependent);
1194 primary_role_rsc = get_resource_for_role(primary);
1195
1196 if ((colocation->dependent_role >= pcmk_role_unpromoted)
1197 && (dependent_role_rsc->parent != NULL)
1198 && pcmk_is_set(dependent_role_rsc->parent->flags, pcmk_rsc_promotable)
1199 && !pcmk_is_set(dependent_role_rsc->flags, pcmk_rsc_unassigned)) {
1200
1201
1202
1203
1204
1205 return pcmk__coloc_affects_role;
1206 }
1207
1208 if (!preview && !pcmk_is_set(dependent->flags, pcmk_rsc_unassigned)) {
1209
1210
1211
1212
1213
1214 const pcmk_node_t *primary_node = primary->allocated_to;
1215
1216 if (dependent->allocated_to == NULL) {
1217 crm_trace("Skipping colocation '%s': %s will not run anywhere",
1218 colocation->id, dependent->id);
1219
1220 } else if (colocation->score >= INFINITY) {
1221
1222
1223 if (!pe__same_node(primary_node, dependent->allocated_to)) {
1224 crm_err("%s must be colocated with %s but is not (%s vs. %s)",
1225 dependent->id, primary->id,
1226 pe__node_name(dependent->allocated_to),
1227 pe__node_name(primary_node));
1228 }
1229
1230 } else if (colocation->score <= -CRM_SCORE_INFINITY) {
1231
1232
1233 if (pe__same_node(dependent->allocated_to, primary_node)) {
1234 crm_err("%s and %s must be anti-colocated but are assigned "
1235 "to the same node (%s)",
1236 dependent->id, primary->id,
1237 pe__node_name(primary_node));
1238 }
1239 }
1240 return pcmk__coloc_affects_nothing;
1241 }
1242
1243 if ((colocation->dependent_role != pcmk_role_unknown)
1244 && (colocation->dependent_role != dependent_role_rsc->next_role)) {
1245 crm_trace("Skipping %scolocation '%s': dependent limited to %s role "
1246
1247 "but %s next role is %s",
1248 ((colocation->score < 0)? "anti-" : ""),
1249 colocation->id, role2text(colocation->dependent_role),
1250 dependent_role_rsc->id,
1251 role2text(dependent_role_rsc->next_role));
1252 return pcmk__coloc_affects_nothing;
1253 }
1254
1255 if ((colocation->primary_role != pcmk_role_unknown)
1256 && (colocation->primary_role != primary_role_rsc->next_role)) {
1257 crm_trace("Skipping %scolocation '%s': primary limited to %s role "
1258 "but %s next role is %s",
1259 ((colocation->score < 0)? "anti-" : ""),
1260 colocation->id, role2text(colocation->primary_role),
1261 primary_role_rsc->id, role2text(primary_role_rsc->next_role));
1262 return pcmk__coloc_affects_nothing;
1263 }
1264
1265 return pcmk__coloc_affects_location;
1266 }
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279 void
1280 pcmk__apply_coloc_to_scores(pcmk_resource_t *dependent,
1281 const pcmk_resource_t *primary,
1282 const pcmk__colocation_t *colocation)
1283 {
1284 const char *attr = colocation->node_attribute;
1285 const char *value = NULL;
1286 GHashTable *work = NULL;
1287 GHashTableIter iter;
1288 pcmk_node_t *node = NULL;
1289
1290 if (primary->allocated_to != NULL) {
1291 value = pcmk__colocation_node_attr(primary->allocated_to, attr,
1292 primary);
1293
1294 } else if (colocation->score < 0) {
1295
1296 return;
1297 }
1298
1299 work = pcmk__copy_node_table(dependent->allowed_nodes);
1300
1301 g_hash_table_iter_init(&iter, work);
1302 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1303 if (primary->allocated_to == NULL) {
1304 node->weight = pcmk__add_scores(-colocation->score, node->weight);
1305 pe_rsc_trace(dependent,
1306 "Applied %s to %s score on %s (now %s after "
1307 "subtracting %s because primary %s inactive)",
1308 colocation->id, dependent->id, pe__node_name(node),
1309 pcmk_readable_score(node->weight),
1310 pcmk_readable_score(colocation->score), primary->id);
1311 continue;
1312 }
1313
1314 if (pcmk__str_eq(pcmk__colocation_node_attr(node, attr, dependent),
1315 value, pcmk__str_casei)) {
1316
1317
1318
1319
1320
1321
1322
1323 if (colocation->score < CRM_SCORE_INFINITY) {
1324 node->weight = pcmk__add_scores(colocation->score,
1325 node->weight);
1326 pe_rsc_trace(dependent,
1327 "Applied %s to %s score on %s (now %s after "
1328 "adding %s)",
1329 colocation->id, dependent->id, pe__node_name(node),
1330 pcmk_readable_score(node->weight),
1331 pcmk_readable_score(colocation->score));
1332 }
1333 continue;
1334 }
1335
1336 if (colocation->score >= CRM_SCORE_INFINITY) {
1337
1338
1339
1340
1341
1342 node->weight = -CRM_SCORE_INFINITY;
1343 pe_rsc_trace(dependent,
1344 "Banned %s from %s because colocation %s attribute %s "
1345 "does not match",
1346 dependent->id, pe__node_name(node), colocation->id,
1347 attr);
1348 }
1349 }
1350
1351 if ((colocation->score <= -INFINITY) || (colocation->score >= INFINITY)
1352 || pcmk__any_node_available(work)) {
1353
1354 g_hash_table_destroy(dependent->allowed_nodes);
1355 dependent->allowed_nodes = work;
1356 work = NULL;
1357
1358 } else {
1359 pe_rsc_info(dependent,
1360 "%s: Rolling back scores from %s (no available nodes)",
1361 dependent->id, primary->id);
1362 }
1363
1364 if (work != NULL) {
1365 g_hash_table_destroy(work);
1366 }
1367 }
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380 void
1381 pcmk__apply_coloc_to_priority(pcmk_resource_t *dependent,
1382 const pcmk_resource_t *primary,
1383 const pcmk__colocation_t *colocation)
1384 {
1385 const char *dependent_value = NULL;
1386 const char *primary_value = NULL;
1387 const char *attr = colocation->node_attribute;
1388 int score_multiplier = 1;
1389
1390 const pcmk_resource_t *primary_role_rsc = NULL;
1391
1392 CRM_ASSERT((dependent != NULL) && (primary != NULL) &&
1393 (colocation != NULL));
1394
1395 if ((primary->allocated_to == NULL) || (dependent->allocated_to == NULL)) {
1396 return;
1397 }
1398
1399 dependent_value = pcmk__colocation_node_attr(dependent->allocated_to, attr,
1400 dependent);
1401 primary_value = pcmk__colocation_node_attr(primary->allocated_to, attr,
1402 primary);
1403
1404 primary_role_rsc = get_resource_for_role(primary);
1405
1406 if (!pcmk__str_eq(dependent_value, primary_value, pcmk__str_casei)) {
1407 if ((colocation->score == INFINITY)
1408 && (colocation->dependent_role == pcmk_role_promoted)) {
1409 dependent->priority = -INFINITY;
1410 }
1411 return;
1412 }
1413
1414 if ((colocation->primary_role != pcmk_role_unknown)
1415 && (colocation->primary_role != primary_role_rsc->next_role)) {
1416 return;
1417 }
1418
1419 if (colocation->dependent_role == pcmk_role_unpromoted) {
1420 score_multiplier = -1;
1421 }
1422
1423 dependent->priority = pcmk__add_scores(score_multiplier * colocation->score,
1424 dependent->priority);
1425 pe_rsc_trace(dependent,
1426 "Applied %s to %s promotion priority (now %s after %s %s)",
1427 colocation->id, dependent->id,
1428 pcmk_readable_score(dependent->priority),
1429 ((score_multiplier == 1)? "adding" : "subtracting"),
1430 pcmk_readable_score(colocation->score));
1431 }
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441 static int
1442 best_node_score_matching_attr(const pcmk_resource_t *rsc, const char *attr,
1443 const char *value)
1444 {
1445 GHashTableIter iter;
1446 pcmk_node_t *node = NULL;
1447 int best_score = -INFINITY;
1448 const char *best_node = NULL;
1449
1450
1451 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1452 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1453
1454 if ((node->weight > best_score)
1455 && pcmk__node_available(node, false, false)
1456 && pcmk__str_eq(value, pcmk__colocation_node_attr(node, attr, rsc),
1457 pcmk__str_casei)) {
1458
1459 best_score = node->weight;
1460 best_node = node->details->uname;
1461 }
1462 }
1463
1464 if (!pcmk__str_eq(attr, CRM_ATTR_UNAME, pcmk__str_none)) {
1465 if (best_node == NULL) {
1466 crm_info("No allowed node for %s matches node attribute %s=%s",
1467 rsc->id, attr, value);
1468 } else {
1469 crm_info("Allowed node %s for %s had best score (%d) "
1470 "of those matching node attribute %s=%s",
1471 best_node, rsc->id, best_score, attr, value);
1472 }
1473 }
1474 return best_score;
1475 }
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 static bool
1486 allowed_on_one(const pcmk_resource_t *rsc)
1487 {
1488 GHashTableIter iter;
1489 pcmk_node_t *allowed_node = NULL;
1490 int allowed_nodes = 0;
1491
1492 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1493 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &allowed_node)) {
1494 if ((allowed_node->weight >= 0) && (++allowed_nodes > 1)) {
1495 pe_rsc_trace(rsc, "%s is allowed on multiple nodes", rsc->id);
1496 return false;
1497 }
1498 }
1499 pe_rsc_trace(rsc, "%s is allowed %s", rsc->id,
1500 ((allowed_nodes == 1)? "on a single node" : "nowhere"));
1501 return (allowed_nodes == 1);
1502 }
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522 static void
1523 add_node_scores_matching_attr(GHashTable *nodes,
1524 const pcmk_resource_t *source_rsc,
1525 const pcmk_resource_t *target_rsc,
1526 const pcmk__colocation_t *colocation,
1527 float factor, bool only_positive)
1528 {
1529 GHashTableIter iter;
1530 pcmk_node_t *node = NULL;
1531 const char *attr = colocation->node_attribute;
1532
1533
1534 g_hash_table_iter_init(&iter, nodes);
1535 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1536 float delta_f = 0;
1537 int delta = 0;
1538 int score = 0;
1539 int new_score = 0;
1540 const char *value = pcmk__colocation_node_attr(node, attr, target_rsc);
1541
1542 score = best_node_score_matching_attr(source_rsc, attr, value);
1543
1544 if ((factor < 0) && (score < 0)) {
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578 if ((colocation->primary->stickiness >= -score)
1579 || !pcmk__colocation_has_influence(colocation, NULL)
1580 || !allowed_on_one(colocation->dependent)) {
1581 crm_trace("%s: Filtering %d + %f * %d "
1582 "(double negative disallowed)",
1583 pe__node_name(node), node->weight, factor, score);
1584 continue;
1585 }
1586 }
1587
1588 if (node->weight == INFINITY_HACK) {
1589 crm_trace("%s: Filtering %d + %f * %d (node was marked unusable)",
1590 pe__node_name(node), node->weight, factor, score);
1591 continue;
1592 }
1593
1594 delta_f = factor * score;
1595
1596
1597 delta = (int) ((delta_f < 0)? (delta_f - 0.5) : (delta_f + 0.5));
1598
1599
1600
1601
1602
1603 if ((delta == 0) && (score != 0)) {
1604 if (factor > 0.0) {
1605 delta = 1;
1606 } else if (factor < 0.0) {
1607 delta = -1;
1608 }
1609 }
1610
1611 new_score = pcmk__add_scores(delta, node->weight);
1612
1613 if (only_positive && (new_score < 0) && (node->weight > 0)) {
1614 crm_trace("%s: Filtering %d + %f * %d = %d "
1615 "(negative disallowed, marking node unusable)",
1616 pe__node_name(node), node->weight, factor, score,
1617 new_score);
1618 node->weight = INFINITY_HACK;
1619 continue;
1620 }
1621
1622 if (only_positive && (new_score < 0) && (node->weight == 0)) {
1623 crm_trace("%s: Filtering %d + %f * %d = %d (negative disallowed)",
1624 pe__node_name(node), node->weight, factor, score,
1625 new_score);
1626 continue;
1627 }
1628
1629 crm_trace("%s: %d + %f * %d = %d", pe__node_name(node),
1630 node->weight, factor, score, new_score);
1631 node->weight = new_score;
1632 }
1633 }
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665 void
1666 pcmk__add_colocated_node_scores(pcmk_resource_t *source_rsc,
1667 const pcmk_resource_t *target_rsc,
1668 const char *log_id,
1669 GHashTable **nodes,
1670 const pcmk__colocation_t *colocation,
1671 float factor, uint32_t flags)
1672 {
1673 GHashTable *work = NULL;
1674
1675 CRM_ASSERT((source_rsc != NULL) && (nodes != NULL)
1676 && ((colocation != NULL)
1677 || ((target_rsc == NULL) && (*nodes == NULL))));
1678
1679 if (log_id == NULL) {
1680 log_id = source_rsc->id;
1681 }
1682
1683
1684 if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
1685 pe_rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
1686 log_id, source_rsc->id);
1687 return;
1688 }
1689 pe__set_resource_flags(source_rsc, pcmk_rsc_updating_nodes);
1690
1691 if (*nodes == NULL) {
1692 work = pcmk__copy_node_table(source_rsc->allowed_nodes);
1693 target_rsc = source_rsc;
1694 } else {
1695 const bool pos = pcmk_is_set(flags, pcmk__coloc_select_nonnegative);
1696
1697 pe_rsc_trace(source_rsc, "%s: Merging %s scores from %s (at %.6f)",
1698 log_id, (pos? "positive" : "all"), source_rsc->id, factor);
1699 work = pcmk__copy_node_table(*nodes);
1700 add_node_scores_matching_attr(work, source_rsc, target_rsc, colocation,
1701 factor, pos);
1702 }
1703
1704 if (work == NULL) {
1705 pe__clear_resource_flags(source_rsc, pcmk_rsc_updating_nodes);
1706 return;
1707 }
1708
1709 if (pcmk__any_node_available(work)) {
1710 GList *colocations = NULL;
1711
1712 if (pcmk_is_set(flags, pcmk__coloc_select_this_with)) {
1713 colocations = pcmk__this_with_colocations(source_rsc);
1714 pe_rsc_trace(source_rsc,
1715 "Checking additional %d optional '%s with' "
1716 "constraints",
1717 g_list_length(colocations), source_rsc->id);
1718 } else {
1719 colocations = pcmk__with_this_colocations(source_rsc);
1720 pe_rsc_trace(source_rsc,
1721 "Checking additional %d optional 'with %s' "
1722 "constraints",
1723 g_list_length(colocations), source_rsc->id);
1724 }
1725 flags |= pcmk__coloc_select_active;
1726
1727 for (GList *iter = colocations; iter != NULL; iter = iter->next) {
1728 pcmk__colocation_t *constraint = iter->data;
1729
1730 pcmk_resource_t *other = NULL;
1731 float other_factor = factor * constraint->score / (float) INFINITY;
1732
1733 if (pcmk_is_set(flags, pcmk__coloc_select_this_with)) {
1734 other = constraint->primary;
1735 } else if (!pcmk__colocation_has_influence(constraint, NULL)) {
1736 continue;
1737 } else {
1738 other = constraint->dependent;
1739 }
1740
1741 pe_rsc_trace(source_rsc,
1742 "Optionally merging score of '%s' constraint "
1743 "(%s with %s)",
1744 constraint->id, constraint->dependent->id,
1745 constraint->primary->id);
1746 other->cmds->add_colocated_node_scores(other, target_rsc, log_id,
1747 &work, constraint,
1748 other_factor, flags);
1749 pe__show_node_scores(true, NULL, log_id, work, source_rsc->cluster);
1750 }
1751 g_list_free(colocations);
1752
1753 } else if (pcmk_is_set(flags, pcmk__coloc_select_active)) {
1754 pe_rsc_info(source_rsc, "%s: Rolling back optional scores from %s",
1755 log_id, source_rsc->id);
1756 g_hash_table_destroy(work);
1757 pe__clear_resource_flags(source_rsc, pcmk_rsc_updating_nodes);
1758 return;
1759 }
1760
1761
1762 if (pcmk_is_set(flags, pcmk__coloc_select_nonnegative)) {
1763 pcmk_node_t *node = NULL;
1764 GHashTableIter iter;
1765
1766 g_hash_table_iter_init(&iter, work);
1767 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1768 if (node->weight == INFINITY_HACK) {
1769 node->weight = 1;
1770 }
1771 }
1772 }
1773
1774 if (*nodes != NULL) {
1775 g_hash_table_destroy(*nodes);
1776 }
1777 *nodes = work;
1778
1779 pe__clear_resource_flags(source_rsc, pcmk_rsc_updating_nodes);
1780 }
1781
1782
1783
1784
1785
1786
1787
1788
1789 void
1790 pcmk__add_dependent_scores(gpointer data, gpointer user_data)
1791 {
1792 pcmk__colocation_t *colocation = data;
1793 pcmk_resource_t *target_rsc = user_data;
1794
1795 pcmk_resource_t *source_rsc = colocation->dependent;
1796 const float factor = colocation->score / (float) INFINITY;
1797 uint32_t flags = pcmk__coloc_select_active;
1798
1799 if (!pcmk__colocation_has_influence(colocation, NULL)) {
1800 return;
1801 }
1802 if (target_rsc->variant == pcmk_rsc_variant_clone) {
1803 flags |= pcmk__coloc_select_nonnegative;
1804 }
1805 pe_rsc_trace(target_rsc,
1806 "%s: Incorporating attenuated %s assignment scores due "
1807 "to colocation %s",
1808 target_rsc->id, source_rsc->id, colocation->id);
1809 source_rsc->cmds->add_colocated_node_scores(source_rsc, target_rsc,
1810 source_rsc->id,
1811 &target_rsc->allowed_nodes,
1812 colocation, factor, flags);
1813 }
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832 void
1833 pcmk__colocation_intersect_nodes(pcmk_resource_t *dependent,
1834 const pcmk_resource_t *primary,
1835 const pcmk__colocation_t *colocation,
1836 const GList *primary_nodes, bool merge_scores)
1837 {
1838 GHashTableIter iter;
1839 pcmk_node_t *dependent_node = NULL;
1840
1841 CRM_ASSERT((dependent != NULL) && (primary != NULL)
1842 && (colocation != NULL));
1843
1844 g_hash_table_iter_init(&iter, dependent->allowed_nodes);
1845 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &dependent_node)) {
1846 const pcmk_node_t *primary_node = NULL;
1847
1848 primary_node = pe_find_node_id(primary_nodes,
1849 dependent_node->details->id);
1850 if (primary_node == NULL) {
1851 dependent_node->weight = -INFINITY;
1852 pe_rsc_trace(dependent,
1853 "Banning %s from %s (no primary instance) for %s",
1854 dependent->id, pe__node_name(dependent_node),
1855 colocation->id);
1856
1857 } else if (merge_scores) {
1858 dependent_node->weight = pcmk__add_scores(dependent_node->weight,
1859 primary_node->weight);
1860 pe_rsc_trace(dependent,
1861 "Added %s's score %s to %s's score for %s (now %s) "
1862 "for colocation %s",
1863 primary->id, pcmk_readable_score(primary_node->weight),
1864 dependent->id, pe__node_name(dependent_node),
1865 pcmk_readable_score(dependent_node->weight),
1866 colocation->id);
1867 }
1868 }
1869 }
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881 GList *
1882 pcmk__with_this_colocations(const pcmk_resource_t *rsc)
1883 {
1884 GList *list = NULL;
1885
1886 rsc->cmds->with_this_colocations(rsc, rsc, &list);
1887 return list;
1888 }
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900 GList *
1901 pcmk__this_with_colocations(const pcmk_resource_t *rsc)
1902 {
1903 GList *list = NULL;
1904
1905 rsc->cmds->this_with_colocations(rsc, rsc, &list);
1906 return list;
1907 }