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
- pcmk__colocation_has_influence
- 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/common/xml.h"
23 #include "libpacemaker_private.h"
24
25
26 #define INFINITY_HACK (PCMK_SCORE_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 pcmk__assert(colocation1->primary != NULL);
69 } else {
70 rsc1 = colocation1->primary;
71 rsc2 = colocation2->primary;
72 pcmk__assert(colocation1->dependent != NULL);
73 }
74 pcmk__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 (pcmk__is_clone(rsc1)) {
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 pcmk__assert((list != NULL) && (colocation != NULL) && (rsc != NULL));
177
178 pcmk__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 pcmk__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 pcmk__assert((list != NULL) && (colocation != NULL) && (rsc != NULL));
237
238 pcmk__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 pcmk__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 pcmk__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 = pcmk__assert_alloc(1, sizeof(pcmk__colocation_t));
371
372 if (pcmk__str_eq(dependent_role, PCMK_ROLE_STARTED,
373 pcmk__str_null_matches|pcmk__str_casei)) {
374 dependent_role = PCMK__ROLE_UNKNOWN;
375 }
376
377 if (pcmk__str_eq(primary_role, PCMK_ROLE_STARTED,
378 pcmk__str_null_matches|pcmk__str_casei)) {
379 primary_role = PCMK__ROLE_UNKNOWN;
380 }
381
382 new_con->id = id;
383 new_con->dependent = dependent;
384 new_con->primary = primary;
385 new_con->score = score;
386 new_con->dependent_role = pcmk_parse_role(dependent_role);
387 new_con->primary_role = pcmk_parse_role(primary_role);
388 new_con->node_attribute = pcmk__s(node_attr, CRM_ATTR_UNAME);
389 new_con->flags = flags;
390
391 pcmk__add_this_with(&(dependent->rsc_cons), new_con, dependent);
392 pcmk__add_with_this(&(primary->rsc_cons_lhs), new_con, primary);
393
394 dependent->cluster->colocation_constraints = g_list_prepend(
395 dependent->cluster->colocation_constraints, new_con);
396
397 if (score <= -PCMK_SCORE_INFINITY) {
398 anti_colocation_order(dependent, new_con->dependent_role, primary,
399 new_con->primary_role);
400 anti_colocation_order(primary, new_con->primary_role, dependent,
401 new_con->dependent_role);
402 }
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417 static uint32_t
418 unpack_influence(const char *coloc_id, const pcmk_resource_t *rsc,
419 const char *influence_s)
420 {
421 if (influence_s != NULL) {
422 int influence_i = 0;
423
424 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
425 pcmk__config_err("Constraint '%s' has invalid value for "
426 PCMK_XA_INFLUENCE " (using default)",
427 coloc_id);
428 } else {
429 return (influence_i == 0)? pcmk__coloc_none : pcmk__coloc_influence;
430 }
431 }
432 if (pcmk_is_set(rsc->flags, pcmk_rsc_critical)) {
433 return pcmk__coloc_influence;
434 }
435 return pcmk__coloc_none;
436 }
437
438 static void
439 unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
440 const char *influence_s, pcmk_scheduler_t *scheduler)
441 {
442 xmlNode *xml_rsc = NULL;
443 pcmk_resource_t *other = NULL;
444 pcmk_resource_t *resource = NULL;
445 const char *set_id = pcmk__xe_id(set);
446 const char *role = crm_element_value(set, PCMK_XA_ROLE);
447 bool with_previous = false;
448 int local_score = score;
449 bool sequential = false;
450 uint32_t flags = pcmk__coloc_none;
451 const char *xml_rsc_id = NULL;
452 const char *score_s = crm_element_value(set, PCMK_XA_SCORE);
453
454 if (score_s) {
455 local_score = char2score(score_s);
456 }
457 if (local_score == 0) {
458 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
459 coloc_id, set_id);
460 return;
461 }
462
463
464
465
466
467 if (pcmk__str_eq(crm_element_value(set, PCMK__XA_ORDERING),
468 PCMK__VALUE_GROUP,
469 pcmk__str_null_matches|pcmk__str_casei)) {
470 with_previous = true;
471 } else {
472 pcmk__warn_once(pcmk__wo_set_ordering,
473 "Support for '" PCMK__XA_ORDERING "' other than"
474 " '" PCMK__VALUE_GROUP "' in " PCMK_XE_RESOURCE_SET
475 " (such as %s) is deprecated and will be removed in a"
476 " future release",
477 set_id);
478 }
479
480 if ((pcmk__xe_get_bool_attr(set, PCMK_XA_SEQUENTIAL,
481 &sequential) == pcmk_rc_ok)
482 && !sequential) {
483 return;
484 }
485
486 if (local_score > 0) {
487 for (xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL,
488 NULL);
489 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
490
491 xml_rsc_id = pcmk__xe_id(xml_rsc);
492 resource = pcmk__find_constraint_resource(scheduler->resources,
493 xml_rsc_id);
494 if (resource == NULL) {
495
496 pcmk__config_err("Ignoring %s and later resources in set %s: "
497 "No such resource", xml_rsc_id, set_id);
498 return;
499 }
500 if (other != NULL) {
501 flags = pcmk__coloc_explicit
502 | unpack_influence(coloc_id, resource, influence_s);
503 if (with_previous) {
504 pcmk__rsc_trace(resource, "Colocating %s with %s in set %s",
505 resource->id, other->id, set_id);
506 pcmk__new_colocation(set_id, NULL, local_score, resource,
507 other, role, role, flags);
508 } else {
509 pcmk__rsc_trace(resource, "Colocating %s with %s in set %s",
510 other->id, resource->id, set_id);
511 pcmk__new_colocation(set_id, NULL, local_score, other,
512 resource, role, role, flags);
513 }
514 }
515 other = resource;
516 }
517
518 } else {
519
520
521
522
523
524 for (xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL,
525 NULL);
526 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
527
528 xmlNode *xml_rsc_with = NULL;
529
530 xml_rsc_id = pcmk__xe_id(xml_rsc);
531 resource = pcmk__find_constraint_resource(scheduler->resources,
532 xml_rsc_id);
533 if (resource == NULL) {
534
535 pcmk__config_err("Ignoring %s and later resources in set %s: "
536 "No such resource", xml_rsc_id, set_id);
537 return;
538 }
539 flags = pcmk__coloc_explicit
540 | unpack_influence(coloc_id, resource, influence_s);
541 for (xml_rsc_with = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF,
542 NULL, NULL);
543 xml_rsc_with != NULL;
544 xml_rsc_with = pcmk__xe_next_same(xml_rsc_with)) {
545
546 xml_rsc_id = pcmk__xe_id(xml_rsc_with);
547 if (pcmk__str_eq(resource->id, xml_rsc_id, pcmk__str_none)) {
548 break;
549 }
550 other = pcmk__find_constraint_resource(scheduler->resources,
551 xml_rsc_id);
552 pcmk__assert(other != NULL);
553 pcmk__new_colocation(set_id, NULL, local_score,
554 resource, other, role, role, flags);
555 }
556 }
557 }
558 }
559
560
561
562
563
564
565
566
567
568
569
570
571
572 static void
573 colocate_rsc_sets(const char *id, const xmlNode *set1, const xmlNode *set2,
574 int score, const char *influence_s,
575 pcmk_scheduler_t *scheduler)
576 {
577 xmlNode *xml_rsc = NULL;
578 pcmk_resource_t *rsc_1 = NULL;
579 pcmk_resource_t *rsc_2 = NULL;
580
581 const char *xml_rsc_id = NULL;
582 const char *role_1 = crm_element_value(set1, PCMK_XA_ROLE);
583 const char *role_2 = crm_element_value(set2, PCMK_XA_ROLE);
584
585 int rc = pcmk_rc_ok;
586 bool sequential = false;
587 uint32_t flags = pcmk__coloc_none;
588
589 if (score == 0) {
590 crm_trace("Ignoring colocation '%s' between sets %s and %s "
591 "because score is 0",
592 id, pcmk__xe_id(set1), pcmk__xe_id(set2));
593 return;
594 }
595
596 rc = pcmk__xe_get_bool_attr(set1, PCMK_XA_SEQUENTIAL, &sequential);
597 if ((rc != pcmk_rc_ok) || sequential) {
598
599 xml_rsc = pcmk__xe_first_child(set1, PCMK_XE_RESOURCE_REF, NULL, NULL);
600 if (xml_rsc != NULL) {
601 xml_rsc_id = pcmk__xe_id(xml_rsc);
602 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
603 xml_rsc_id);
604 if (rsc_1 == NULL) {
605
606 pcmk__config_err("Ignoring colocation of set %s with set %s "
607 "because first resource %s not found",
608 pcmk__xe_id(set1), pcmk__xe_id(set2),
609 xml_rsc_id);
610 return;
611 }
612 }
613 }
614
615 rc = pcmk__xe_get_bool_attr(set2, PCMK_XA_SEQUENTIAL, &sequential);
616 if ((rc != pcmk_rc_ok) || sequential) {
617
618 for (xml_rsc = pcmk__xe_first_child(set2, PCMK_XE_RESOURCE_REF, NULL,
619 NULL);
620 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
621
622 xml_rsc_id = pcmk__xe_id(xml_rsc);
623 }
624 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
625 xml_rsc_id);
626 if (rsc_2 == NULL) {
627
628 pcmk__config_err("Ignoring colocation of set %s with set %s "
629 "because last resource %s not found",
630 pcmk__xe_id(set1), pcmk__xe_id(set2), xml_rsc_id);
631 return;
632 }
633 }
634
635 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
636 flags = pcmk__coloc_explicit | unpack_influence(id, rsc_1, influence_s);
637 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
638 flags);
639
640 } else if (rsc_1 != NULL) {
641 flags = pcmk__coloc_explicit | unpack_influence(id, rsc_1, influence_s);
642 for (xml_rsc = pcmk__xe_first_child(set2, PCMK_XE_RESOURCE_REF, NULL,
643 NULL);
644 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
645
646 xml_rsc_id = pcmk__xe_id(xml_rsc);
647 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
648 xml_rsc_id);
649 if (rsc_2 == NULL) {
650
651 pcmk__config_err("Ignoring set %s colocation with resource %s "
652 "in set %s: No such resource",
653 pcmk__xe_id(set1), xml_rsc_id,
654 pcmk__xe_id(set2));
655 continue;
656 }
657 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
658 role_2, flags);
659 }
660
661 } else if (rsc_2 != NULL) {
662 for (xml_rsc = pcmk__xe_first_child(set1, PCMK_XE_RESOURCE_REF, NULL,
663 NULL);
664 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
665
666 xml_rsc_id = pcmk__xe_id(xml_rsc);
667 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
668 xml_rsc_id);
669 if (rsc_1 == NULL) {
670
671 pcmk__config_err("Ignoring colocation of set %s resource %s "
672 "with set %s: No such resource",
673 pcmk__xe_id(set1), xml_rsc_id,
674 pcmk__xe_id(set2));
675 continue;
676 }
677 flags = pcmk__coloc_explicit
678 | unpack_influence(id, rsc_1, influence_s);
679 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
680 role_2, flags);
681 }
682
683 } else {
684 for (xml_rsc = pcmk__xe_first_child(set1, PCMK_XE_RESOURCE_REF, NULL,
685 NULL);
686 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
687
688 xmlNode *xml_rsc_2 = NULL;
689
690 xml_rsc_id = pcmk__xe_id(xml_rsc);
691 rsc_1 = pcmk__find_constraint_resource(scheduler->resources,
692 xml_rsc_id);
693 if (rsc_1 == NULL) {
694
695 pcmk__config_err("Ignoring colocation of set %s resource %s "
696 "with set %s: No such resource",
697 pcmk__xe_id(set1), xml_rsc_id,
698 pcmk__xe_id(set2));
699 continue;
700 }
701
702 flags = pcmk__coloc_explicit
703 | unpack_influence(id, rsc_1, influence_s);
704 for (xml_rsc_2 = pcmk__xe_first_child(set2, PCMK_XE_RESOURCE_REF,
705 NULL, NULL);
706 xml_rsc_2 != NULL; xml_rsc_2 = pcmk__xe_next_same(xml_rsc_2)) {
707
708 xml_rsc_id = pcmk__xe_id(xml_rsc_2);
709 rsc_2 = pcmk__find_constraint_resource(scheduler->resources,
710 xml_rsc_id);
711 if (rsc_2 == NULL) {
712
713 pcmk__config_err("Ignoring colocation of set %s resource "
714 "%s with set %s resource %s: No such "
715 "resource",
716 pcmk__xe_id(set1), pcmk__xe_id(xml_rsc),
717 pcmk__xe_id(set2), xml_rsc_id);
718 continue;
719 }
720 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
721 role_1, role_2, flags);
722 }
723 }
724 }
725 }
726
727 static void
728 unpack_simple_colocation(xmlNode *xml_obj, const char *id,
729 const char *influence_s, pcmk_scheduler_t *scheduler)
730 {
731 int score_i = 0;
732 uint32_t flags = pcmk__coloc_none;
733
734 const char *score = crm_element_value(xml_obj, PCMK_XA_SCORE);
735 const char *dependent_id = crm_element_value(xml_obj, PCMK_XA_RSC);
736 const char *primary_id = crm_element_value(xml_obj, PCMK_XA_WITH_RSC);
737 const char *dependent_role = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
738 const char *primary_role = crm_element_value(xml_obj,
739 PCMK_XA_WITH_RSC_ROLE);
740 const char *attr = crm_element_value(xml_obj, PCMK_XA_NODE_ATTRIBUTE);
741
742 const char *primary_instance = NULL;
743 const char *dependent_instance = NULL;
744 pcmk_resource_t *primary = NULL;
745 pcmk_resource_t *dependent = NULL;
746
747 primary = pcmk__find_constraint_resource(scheduler->resources, primary_id);
748 dependent = pcmk__find_constraint_resource(scheduler->resources,
749 dependent_id);
750
751
752 primary_instance = crm_element_value(xml_obj, PCMK__XA_WITH_RSC_INSTANCE);
753 dependent_instance = crm_element_value(xml_obj, PCMK__XA_RSC_INSTANCE);
754 if (dependent_instance != NULL) {
755 pcmk__warn_once(pcmk__wo_coloc_inst,
756 "Support for " PCMK__XA_RSC_INSTANCE " is deprecated "
757 "and will be removed in a future release");
758 }
759 if (primary_instance != NULL) {
760 pcmk__warn_once(pcmk__wo_coloc_inst,
761 "Support for " PCMK__XA_WITH_RSC_INSTANCE " is "
762 "deprecated and will be removed in a future release");
763 }
764
765 if (dependent == NULL) {
766 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
767 "does not exist", id, dependent_id);
768 return;
769
770 } else if (primary == NULL) {
771 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
772 "does not exist", id, primary_id);
773 return;
774
775 } else if ((dependent_instance != NULL) && !pcmk__is_clone(dependent)) {
776 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
777 "is not a clone but instance '%s' was requested",
778 id, dependent_id, dependent_instance);
779 return;
780
781 } else if ((primary_instance != NULL) && !pcmk__is_clone(primary)) {
782 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
783 "is not a clone but instance '%s' was requested",
784 id, primary_id, primary_instance);
785 return;
786 }
787
788 if (dependent_instance != NULL) {
789 dependent = find_clone_instance(dependent, dependent_instance);
790 if (dependent == NULL) {
791 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
792 "does not have an instance '%s'",
793 id, dependent_id, dependent_instance);
794 return;
795 }
796 }
797
798 if (primary_instance != NULL) {
799 primary = find_clone_instance(primary, primary_instance);
800 if (primary == NULL) {
801 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
802 "does not have an instance '%s'",
803 id, primary_id, primary_instance);
804 return;
805 }
806 }
807
808 if (pcmk__xe_attr_is_true(xml_obj, PCMK_XA_SYMMETRICAL)) {
809 pcmk__config_warn("The colocation constraint "
810 "'" PCMK_XA_SYMMETRICAL "' attribute has been "
811 "removed");
812 }
813
814 if (score) {
815 score_i = char2score(score);
816 }
817
818 flags = pcmk__coloc_explicit | unpack_influence(id, dependent, influence_s);
819 pcmk__new_colocation(id, attr, score_i, dependent, primary,
820 dependent_role, primary_role, flags);
821 }
822
823
824 static int
825 unpack_colocation_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
826 pcmk_scheduler_t *scheduler)
827 {
828 const char *id = NULL;
829 const char *dependent_id = NULL;
830 const char *primary_id = NULL;
831 const char *dependent_role = NULL;
832 const char *primary_role = NULL;
833
834 pcmk_resource_t *dependent = NULL;
835 pcmk_resource_t *primary = NULL;
836
837 pcmk_tag_t *dependent_tag = NULL;
838 pcmk_tag_t *primary_tag = NULL;
839
840 xmlNode *dependent_set = NULL;
841 xmlNode *primary_set = NULL;
842 bool any_sets = false;
843
844 *expanded_xml = NULL;
845
846 CRM_CHECK(xml_obj != NULL, return EINVAL);
847
848 id = pcmk__xe_id(xml_obj);
849 if (id == NULL) {
850 pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
851 xml_obj->name);
852 return pcmk_rc_unpack_error;
853 }
854
855
856 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
857 if (*expanded_xml != NULL) {
858 crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_COLOCATION);
859 return pcmk_rc_ok;
860 }
861
862 dependent_id = crm_element_value(xml_obj, PCMK_XA_RSC);
863 primary_id = crm_element_value(xml_obj, PCMK_XA_WITH_RSC);
864 if ((dependent_id == NULL) || (primary_id == NULL)) {
865 return pcmk_rc_ok;
866 }
867
868 if (!pcmk__valid_resource_or_tag(scheduler, dependent_id, &dependent,
869 &dependent_tag)) {
870 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
871 "valid resource or tag", id, dependent_id);
872 return pcmk_rc_unpack_error;
873 }
874
875 if (!pcmk__valid_resource_or_tag(scheduler, primary_id, &primary,
876 &primary_tag)) {
877 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
878 "valid resource or tag", id, primary_id);
879 return pcmk_rc_unpack_error;
880 }
881
882 if ((dependent != NULL) && (primary != NULL)) {
883
884 return pcmk_rc_ok;
885 }
886
887 if ((dependent_tag != NULL) && (primary_tag != NULL)) {
888
889 pcmk__config_err("Ignoring constraint '%s' because two templates or "
890 "tags cannot be colocated", id);
891 return pcmk_rc_unpack_error;
892 }
893
894 dependent_role = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
895 primary_role = crm_element_value(xml_obj, PCMK_XA_WITH_RSC_ROLE);
896
897 *expanded_xml = pcmk__xml_copy(NULL, xml_obj);
898
899
900
901
902 if (!pcmk__tag_to_set(*expanded_xml, &dependent_set, PCMK_XA_RSC, true,
903 scheduler)) {
904 free_xml(*expanded_xml);
905 *expanded_xml = NULL;
906 return pcmk_rc_unpack_error;
907 }
908
909 if (dependent_set != NULL) {
910 if (dependent_role != NULL) {
911
912
913
914 crm_xml_add(dependent_set, PCMK_XA_ROLE, dependent_role);
915 pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_RSC_ROLE);
916 }
917 any_sets = true;
918 }
919
920
921
922
923 if (!pcmk__tag_to_set(*expanded_xml, &primary_set, PCMK_XA_WITH_RSC, true,
924 scheduler)) {
925 free_xml(*expanded_xml);
926 *expanded_xml = NULL;
927 return pcmk_rc_unpack_error;
928 }
929
930 if (primary_set != NULL) {
931 if (primary_role != NULL) {
932
933
934
935 crm_xml_add(primary_set, PCMK_XA_ROLE, primary_role);
936 pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_WITH_RSC_ROLE);
937 }
938 any_sets = true;
939 }
940
941 if (any_sets) {
942 crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_COLOCATION);
943 } else {
944 free_xml(*expanded_xml);
945 *expanded_xml = NULL;
946 }
947
948 return pcmk_rc_ok;
949 }
950
951
952
953
954
955
956
957
958 void
959 pcmk__unpack_colocation(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
960 {
961 int score_i = 0;
962 xmlNode *set = NULL;
963 xmlNode *last = NULL;
964
965 xmlNode *orig_xml = NULL;
966 xmlNode *expanded_xml = NULL;
967
968 const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
969 const char *score = NULL;
970 const char *influence_s = NULL;
971
972 if (pcmk__str_empty(id)) {
973 pcmk__config_err("Ignoring " PCMK_XE_RSC_COLOCATION
974 " without " CRM_ATTR_ID);
975 return;
976 }
977
978 if (unpack_colocation_tags(xml_obj, &expanded_xml,
979 scheduler) != pcmk_rc_ok) {
980 return;
981 }
982 if (expanded_xml != NULL) {
983 orig_xml = xml_obj;
984 xml_obj = expanded_xml;
985 }
986
987 score = crm_element_value(xml_obj, PCMK_XA_SCORE);
988 if (score != NULL) {
989 score_i = char2score(score);
990 }
991 influence_s = crm_element_value(xml_obj, PCMK_XA_INFLUENCE);
992
993 for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL);
994 set != NULL; set = pcmk__xe_next_same(set)) {
995
996 set = expand_idref(set, scheduler->input);
997 if (set == NULL) {
998 if (expanded_xml != NULL) {
999 free_xml(expanded_xml);
1000 }
1001 return;
1002 }
1003
1004 if (pcmk__str_empty(pcmk__xe_id(set))) {
1005 pcmk__config_err("Ignoring " PCMK_XE_RESOURCE_SET
1006 " without " CRM_ATTR_ID);
1007 continue;
1008 }
1009 unpack_colocation_set(set, score_i, id, influence_s, scheduler);
1010
1011 if (last != NULL) {
1012 colocate_rsc_sets(id, last, set, score_i, influence_s, scheduler);
1013 }
1014 last = set;
1015 }
1016
1017 if (expanded_xml) {
1018 free_xml(expanded_xml);
1019 xml_obj = orig_xml;
1020 }
1021
1022 if (last == NULL) {
1023 unpack_simple_colocation(xml_obj, id, influence_s, scheduler);
1024 }
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039 bool
1040 pcmk__colocation_has_influence(const pcmk__colocation_t *colocation,
1041 const pcmk_resource_t *rsc)
1042 {
1043 if (rsc == NULL) {
1044 rsc = colocation->primary;
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 if (pcmk_is_set(colocation->dependent->flags,
1060 pcmk_rsc_remote_nesting_allowed)
1061 && !pcmk_is_set(rsc->flags, pcmk_rsc_failed)
1062 && pcmk__list_of_1(rsc->running_on)) {
1063 return false;
1064 }
1065
1066
1067
1068
1069 return pcmk_is_set(colocation->flags, pcmk__coloc_influence)
1070 || (rsc->running_on == NULL);
1071 }
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081 static void
1082 mark_action_blocked(pcmk_resource_t *rsc, const char *task,
1083 const pcmk_resource_t *reason)
1084 {
1085 GList *iter = NULL;
1086 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
1087
1088 for (iter = rsc->actions; iter != NULL; iter = iter->next) {
1089 pcmk_action_t *action = iter->data;
1090
1091 if (pcmk_is_set(action->flags, pcmk_action_runnable)
1092 && pcmk__str_eq(action->task, task, pcmk__str_none)) {
1093
1094 pcmk__clear_action_flags(action, pcmk_action_runnable);
1095 pe_action_set_reason(action, reason_text, false);
1096 pcmk__block_colocation_dependents(action);
1097 pcmk__update_action_for_orderings(action, rsc->cluster);
1098 }
1099 }
1100
1101
1102 for (iter = rsc->children; iter != NULL; iter = iter->next) {
1103 mark_action_blocked((pcmk_resource_t *) (iter->data), task, reason);
1104 }
1105 free(reason_text);
1106 }
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 void
1119 pcmk__block_colocation_dependents(pcmk_action_t *action)
1120 {
1121 GList *iter = NULL;
1122 GList *colocations = NULL;
1123 pcmk_resource_t *rsc = NULL;
1124 bool is_start = false;
1125
1126 if (pcmk_is_set(action->flags, pcmk_action_runnable)) {
1127 return;
1128 }
1129
1130 is_start = pcmk__str_eq(action->task, PCMK_ACTION_START, pcmk__str_none);
1131 if (!is_start
1132 && !pcmk__str_eq(action->task, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
1133 return;
1134 }
1135
1136 pcmk__assert(action->rsc != NULL);
1137
1138
1139
1140
1141
1142 rsc = uber_parent(action->rsc);
1143 if (rsc->parent != NULL) {
1144 rsc = rsc->parent;
1145 }
1146
1147
1148 for (iter = rsc->children; iter != NULL; iter = iter->next) {
1149 pcmk_resource_t *child = iter->data;
1150 pcmk_action_t *child_action = find_first_action(child->actions, NULL,
1151 action->task, NULL);
1152
1153 if ((child_action == NULL)
1154 || pcmk_is_set(child_action->flags, pcmk_action_runnable)) {
1155 crm_trace("Not blocking %s colocation dependents because "
1156 "at least %s has runnable %s",
1157 rsc->id, child->id, action->task);
1158 return;
1159 }
1160 }
1161
1162 crm_trace("Blocking %s colocation dependents due to unrunnable %s %s",
1163 rsc->id, action->rsc->id, action->task);
1164
1165
1166 colocations = pcmk__with_this_colocations(rsc);
1167 for (iter = colocations; iter != NULL; iter = iter->next) {
1168 pcmk__colocation_t *colocation = iter->data;
1169
1170 if (colocation->score < PCMK_SCORE_INFINITY) {
1171 continue;
1172 }
1173
1174
1175
1176
1177
1178
1179
1180 if (!is_start && (colocation->primary_role != pcmk_role_promoted)) {
1181 continue;
1182 }
1183
1184
1185 if (colocation->dependent_role == pcmk_role_promoted) {
1186 mark_action_blocked(colocation->dependent, PCMK_ACTION_PROMOTE,
1187 action->rsc);
1188 } else {
1189 mark_action_blocked(colocation->dependent, PCMK_ACTION_START,
1190 action->rsc);
1191 }
1192 }
1193 g_list_free(colocations);
1194 }
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214 static const pcmk_resource_t *
1215 get_resource_for_role(const pcmk_resource_t *rsc)
1216 {
1217 if (pcmk_is_set(rsc->flags, pcmk_rsc_replica_container)) {
1218 const pcmk_resource_t *child = pe__get_rsc_in_container(rsc);
1219
1220 if (child != NULL) {
1221 return child;
1222 }
1223 }
1224 return rsc;
1225 }
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 enum pcmk__coloc_affects
1246 pcmk__colocation_affects(const pcmk_resource_t *dependent,
1247 const pcmk_resource_t *primary,
1248 const pcmk__colocation_t *colocation, bool preview)
1249 {
1250 const pcmk_resource_t *dependent_role_rsc = NULL;
1251 const pcmk_resource_t *primary_role_rsc = NULL;
1252
1253 pcmk__assert((dependent != NULL) && (primary != NULL)
1254 && (colocation != NULL));
1255
1256 if (!preview && pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
1257
1258 return pcmk__coloc_affects_nothing;
1259 }
1260
1261 dependent_role_rsc = get_resource_for_role(dependent);
1262 primary_role_rsc = get_resource_for_role(primary);
1263
1264 if ((colocation->dependent_role >= pcmk_role_unpromoted)
1265 && (dependent_role_rsc->parent != NULL)
1266 && pcmk_is_set(dependent_role_rsc->parent->flags, pcmk_rsc_promotable)
1267 && !pcmk_is_set(dependent_role_rsc->flags, pcmk_rsc_unassigned)) {
1268
1269
1270
1271
1272
1273 return pcmk__coloc_affects_role;
1274 }
1275
1276 if (!preview && !pcmk_is_set(dependent->flags, pcmk_rsc_unassigned)) {
1277
1278
1279
1280
1281
1282 const pcmk_node_t *primary_node = primary->allocated_to;
1283
1284 if (dependent->allocated_to == NULL) {
1285 crm_trace("Skipping colocation '%s': %s will not run anywhere",
1286 colocation->id, dependent->id);
1287
1288 } else if (colocation->score >= PCMK_SCORE_INFINITY) {
1289
1290
1291 if (!pcmk__same_node(primary_node, dependent->allocated_to)) {
1292 pcmk__sched_err("%s must be colocated with %s but is not "
1293 "(%s vs. %s)",
1294 dependent->id, primary->id,
1295 pcmk__node_name(dependent->allocated_to),
1296 pcmk__node_name(primary_node));
1297 }
1298
1299 } else if (colocation->score <= -PCMK_SCORE_INFINITY) {
1300
1301
1302 if (pcmk__same_node(dependent->allocated_to, primary_node)) {
1303 pcmk__sched_err("%s and %s must be anti-colocated but are "
1304 "assigned to the same node (%s)",
1305 dependent->id, primary->id,
1306 pcmk__node_name(primary_node));
1307 }
1308 }
1309 return pcmk__coloc_affects_nothing;
1310 }
1311
1312 if ((colocation->dependent_role != pcmk_role_unknown)
1313 && (colocation->dependent_role != dependent_role_rsc->next_role)) {
1314 crm_trace("Skipping %scolocation '%s': dependent limited to %s role "
1315
1316 "but %s next role is %s",
1317 ((colocation->score < 0)? "anti-" : ""),
1318 colocation->id, pcmk_role_text(colocation->dependent_role),
1319 dependent_role_rsc->id,
1320 pcmk_role_text(dependent_role_rsc->next_role));
1321 return pcmk__coloc_affects_nothing;
1322 }
1323
1324 if ((colocation->primary_role != pcmk_role_unknown)
1325 && (colocation->primary_role != primary_role_rsc->next_role)) {
1326 crm_trace("Skipping %scolocation '%s': primary limited to %s role "
1327 "but %s next role is %s",
1328 ((colocation->score < 0)? "anti-" : ""),
1329 colocation->id, pcmk_role_text(colocation->primary_role),
1330 primary_role_rsc->id,
1331 pcmk_role_text(primary_role_rsc->next_role));
1332 return pcmk__coloc_affects_nothing;
1333 }
1334
1335 return pcmk__coloc_affects_location;
1336 }
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349 void
1350 pcmk__apply_coloc_to_scores(pcmk_resource_t *dependent,
1351 const pcmk_resource_t *primary,
1352 const pcmk__colocation_t *colocation)
1353 {
1354 const char *attr = colocation->node_attribute;
1355 const char *value = NULL;
1356 GHashTable *work = NULL;
1357 GHashTableIter iter;
1358 pcmk_node_t *node = NULL;
1359
1360 if (primary->allocated_to != NULL) {
1361 value = pcmk__colocation_node_attr(primary->allocated_to, attr,
1362 primary);
1363
1364 } else if (colocation->score < 0) {
1365
1366 return;
1367 }
1368
1369 work = pcmk__copy_node_table(dependent->allowed_nodes);
1370
1371 g_hash_table_iter_init(&iter, work);
1372 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1373 if (primary->allocated_to == NULL) {
1374 node->weight = pcmk__add_scores(-colocation->score, node->weight);
1375 pcmk__rsc_trace(dependent,
1376 "Applied %s to %s score on %s (now %s after "
1377 "subtracting %s because primary %s inactive)",
1378 colocation->id, dependent->id,
1379 pcmk__node_name(node),
1380 pcmk_readable_score(node->weight),
1381 pcmk_readable_score(colocation->score), primary->id);
1382 continue;
1383 }
1384
1385 if (pcmk__str_eq(pcmk__colocation_node_attr(node, attr, dependent),
1386 value, pcmk__str_casei)) {
1387
1388
1389
1390
1391
1392
1393
1394 if (colocation->score < PCMK_SCORE_INFINITY) {
1395 node->weight = pcmk__add_scores(colocation->score,
1396 node->weight);
1397 pcmk__rsc_trace(dependent,
1398 "Applied %s to %s score on %s (now %s after "
1399 "adding %s)",
1400 colocation->id, dependent->id,
1401 pcmk__node_name(node),
1402 pcmk_readable_score(node->weight),
1403 pcmk_readable_score(colocation->score));
1404 }
1405 continue;
1406 }
1407
1408 if (colocation->score >= PCMK_SCORE_INFINITY) {
1409
1410
1411
1412
1413
1414 node->weight = -PCMK_SCORE_INFINITY;
1415 pcmk__rsc_trace(dependent,
1416 "Banned %s from %s because colocation %s attribute %s "
1417 "does not match",
1418 dependent->id, pcmk__node_name(node),
1419 colocation->id, attr);
1420 }
1421 }
1422
1423 if ((colocation->score <= -PCMK_SCORE_INFINITY)
1424 || (colocation->score >= PCMK_SCORE_INFINITY)
1425 || pcmk__any_node_available(work)) {
1426
1427 g_hash_table_destroy(dependent->allowed_nodes);
1428 dependent->allowed_nodes = work;
1429 work = NULL;
1430
1431 } else {
1432 pcmk__rsc_info(dependent,
1433 "%s: Rolling back scores from %s (no available nodes)",
1434 dependent->id, primary->id);
1435 }
1436
1437 if (work != NULL) {
1438 g_hash_table_destroy(work);
1439 }
1440 }
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455 int
1456 pcmk__apply_coloc_to_priority(pcmk_resource_t *dependent,
1457 const pcmk_resource_t *primary,
1458 const pcmk__colocation_t *colocation)
1459 {
1460 const char *dependent_value = NULL;
1461 const char *primary_value = NULL;
1462 const char *attr = colocation->node_attribute;
1463 int score_multiplier = 1;
1464 int priority_delta = 0;
1465
1466 pcmk__assert((dependent != NULL) && (primary != NULL)
1467 && (colocation != NULL));
1468
1469 if (dependent->allocated_to == NULL) {
1470 return 0;
1471 }
1472
1473 if ((primary->allocated_to != NULL)
1474 && (colocation->primary_role != pcmk_role_unknown)) {
1475
1476
1477
1478
1479
1480
1481
1482
1483 const pcmk_resource_t *role_rsc = get_resource_for_role(primary);
1484
1485 if (colocation->primary_role != role_rsc->next_role) {
1486 return 0;
1487 }
1488 }
1489
1490 dependent_value = pcmk__colocation_node_attr(dependent->allocated_to, attr,
1491 dependent);
1492 primary_value = pcmk__colocation_node_attr(primary->allocated_to, attr,
1493 primary);
1494
1495 if (!pcmk__str_eq(dependent_value, primary_value, pcmk__str_casei)) {
1496 if ((colocation->score == PCMK_SCORE_INFINITY)
1497 && (colocation->dependent_role == pcmk_role_promoted)) {
1498
1499
1500
1501
1502
1503 score_multiplier = -1;
1504
1505 } else {
1506
1507 return 0;
1508 }
1509
1510 } else if (colocation->dependent_role == pcmk_role_unpromoted) {
1511
1512
1513
1514 score_multiplier = -1;
1515 }
1516
1517 priority_delta = score_multiplier * colocation->score;
1518 dependent->priority = pcmk__add_scores(priority_delta, dependent->priority);
1519 pcmk__rsc_trace(dependent,
1520 "Applied %s to %s promotion priority (now %s after %s %d)",
1521 colocation->id, dependent->id,
1522 pcmk_readable_score(dependent->priority),
1523 ((score_multiplier == 1)? "adding" : "subtracting"),
1524 colocation->score);
1525
1526 return priority_delta;
1527 }
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538 static int
1539 best_node_score_matching_attr(const pcmk__colocation_t *colocation,
1540 pcmk_resource_t *rsc, const char *attr,
1541 const char *value)
1542 {
1543 GHashTable *allowed_nodes_orig = NULL;
1544 GHashTableIter iter;
1545 pcmk_node_t *node = NULL;
1546 int best_score = -PCMK_SCORE_INFINITY;
1547 const char *best_node = NULL;
1548
1549 if ((colocation != NULL) && (rsc == colocation->dependent)
1550 && pcmk_is_set(colocation->flags, pcmk__coloc_explicit)
1551 && pcmk__is_group(rsc->parent)
1552 && (rsc != rsc->parent->children->data)) {
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564 allowed_nodes_orig = rsc->allowed_nodes;
1565 rsc->allowed_nodes = pcmk__copy_node_table(allowed_nodes_orig);
1566 for (GList *loc_iter = rsc->cluster->placement_constraints;
1567 loc_iter != NULL; loc_iter = loc_iter->next) {
1568
1569 pcmk__location_t *location = loc_iter->data;
1570
1571 if (location->rsc == rsc->parent) {
1572 rsc->cmds->apply_location(rsc, location);
1573 }
1574 }
1575 }
1576
1577
1578 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1579 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1580
1581 if ((node->weight > best_score)
1582 && pcmk__node_available(node, false, false)
1583 && pcmk__str_eq(value, pcmk__colocation_node_attr(node, attr, rsc),
1584 pcmk__str_casei)) {
1585
1586 best_score = node->weight;
1587 best_node = node->details->uname;
1588 }
1589 }
1590
1591 if (!pcmk__str_eq(attr, CRM_ATTR_UNAME, pcmk__str_none)) {
1592 if (best_node == NULL) {
1593 crm_info("No allowed node for %s matches node attribute %s=%s",
1594 rsc->id, attr, value);
1595 } else {
1596 crm_info("Allowed node %s for %s had best score (%d) "
1597 "of those matching node attribute %s=%s",
1598 best_node, rsc->id, best_score, attr, value);
1599 }
1600 }
1601
1602 if (allowed_nodes_orig != NULL) {
1603 g_hash_table_destroy(rsc->allowed_nodes);
1604 rsc->allowed_nodes = allowed_nodes_orig;
1605 }
1606 return best_score;
1607 }
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617 static bool
1618 allowed_on_one(const pcmk_resource_t *rsc)
1619 {
1620 GHashTableIter iter;
1621 pcmk_node_t *allowed_node = NULL;
1622 int allowed_nodes = 0;
1623
1624 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1625 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &allowed_node)) {
1626 if ((allowed_node->weight >= 0) && (++allowed_nodes > 1)) {
1627 pcmk__rsc_trace(rsc, "%s is allowed on multiple nodes", rsc->id);
1628 return false;
1629 }
1630 }
1631 pcmk__rsc_trace(rsc, "%s is allowed %s", rsc->id,
1632 ((allowed_nodes == 1)? "on a single node" : "nowhere"));
1633 return (allowed_nodes == 1);
1634 }
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654 static void
1655 add_node_scores_matching_attr(GHashTable *nodes,
1656 pcmk_resource_t *source_rsc,
1657 const pcmk_resource_t *target_rsc,
1658 const pcmk__colocation_t *colocation,
1659 float factor, bool only_positive)
1660 {
1661 GHashTableIter iter;
1662 pcmk_node_t *node = NULL;
1663 const char *attr = colocation->node_attribute;
1664
1665
1666 g_hash_table_iter_init(&iter, nodes);
1667 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1668 float delta_f = 0;
1669 int delta = 0;
1670 int score = 0;
1671 int new_score = 0;
1672 const char *value = pcmk__colocation_node_attr(node, attr, target_rsc);
1673
1674 score = best_node_score_matching_attr(colocation, source_rsc, attr, value);
1675
1676 if ((factor < 0) && (score < 0)) {
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710 if ((colocation->primary->stickiness >= -score)
1711 || !pcmk__colocation_has_influence(colocation, NULL)
1712 || !allowed_on_one(colocation->dependent)) {
1713 crm_trace("%s: Filtering %d + %f * %d "
1714 "(double negative disallowed)",
1715 pcmk__node_name(node), node->weight, factor, score);
1716 continue;
1717 }
1718 }
1719
1720 if (node->weight == INFINITY_HACK) {
1721 crm_trace("%s: Filtering %d + %f * %d (node was marked unusable)",
1722 pcmk__node_name(node), node->weight, factor, score);
1723 continue;
1724 }
1725
1726 delta_f = factor * score;
1727
1728
1729 delta = (int) ((delta_f < 0)? (delta_f - 0.5) : (delta_f + 0.5));
1730
1731
1732
1733
1734
1735 if ((delta == 0) && (score != 0)) {
1736 if (factor > 0.0) {
1737 delta = 1;
1738 } else if (factor < 0.0) {
1739 delta = -1;
1740 }
1741 }
1742
1743 new_score = pcmk__add_scores(delta, node->weight);
1744
1745 if (only_positive && (new_score < 0) && (node->weight > 0)) {
1746 crm_trace("%s: Filtering %d + %f * %d = %d "
1747 "(negative disallowed, marking node unusable)",
1748 pcmk__node_name(node), node->weight, factor, score,
1749 new_score);
1750 node->weight = INFINITY_HACK;
1751 continue;
1752 }
1753
1754 if (only_positive && (new_score < 0) && (node->weight == 0)) {
1755 crm_trace("%s: Filtering %d + %f * %d = %d (negative disallowed)",
1756 pcmk__node_name(node), node->weight, factor, score,
1757 new_score);
1758 continue;
1759 }
1760
1761 crm_trace("%s: %d + %f * %d = %d", pcmk__node_name(node),
1762 node->weight, factor, score, new_score);
1763 node->weight = new_score;
1764 }
1765 }
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797 void
1798 pcmk__add_colocated_node_scores(pcmk_resource_t *source_rsc,
1799 const pcmk_resource_t *target_rsc,
1800 const char *log_id,
1801 GHashTable **nodes,
1802 const pcmk__colocation_t *colocation,
1803 float factor, uint32_t flags)
1804 {
1805 GHashTable *work = NULL;
1806
1807 pcmk__assert((source_rsc != NULL) && (nodes != NULL)
1808 && ((colocation != NULL)
1809 || ((target_rsc == NULL) && (*nodes == NULL))));
1810
1811 if (log_id == NULL) {
1812 log_id = source_rsc->id;
1813 }
1814
1815
1816 if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
1817 pcmk__rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
1818 log_id, source_rsc->id);
1819 return;
1820 }
1821 pcmk__set_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
1822
1823 if (*nodes == NULL) {
1824 work = pcmk__copy_node_table(source_rsc->allowed_nodes);
1825 target_rsc = source_rsc;
1826 } else {
1827 const bool pos = pcmk_is_set(flags, pcmk__coloc_select_nonnegative);
1828
1829 pcmk__rsc_trace(source_rsc, "%s: Merging %s scores from %s (at %.6f)",
1830 log_id, (pos? "positive" : "all"), source_rsc->id, factor);
1831 work = pcmk__copy_node_table(*nodes);
1832 add_node_scores_matching_attr(work, source_rsc, target_rsc, colocation,
1833 factor, pos);
1834 }
1835
1836 if (work == NULL) {
1837 pcmk__clear_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
1838 return;
1839 }
1840
1841 if (pcmk__any_node_available(work)) {
1842 GList *colocations = NULL;
1843
1844 if (pcmk_is_set(flags, pcmk__coloc_select_this_with)) {
1845 colocations = pcmk__this_with_colocations(source_rsc);
1846 pcmk__rsc_trace(source_rsc,
1847 "Checking additional %d optional '%s with' "
1848 "constraints",
1849 g_list_length(colocations), source_rsc->id);
1850 } else {
1851 colocations = pcmk__with_this_colocations(source_rsc);
1852 pcmk__rsc_trace(source_rsc,
1853 "Checking additional %d optional 'with %s' "
1854 "constraints",
1855 g_list_length(colocations), source_rsc->id);
1856 }
1857 flags |= pcmk__coloc_select_active;
1858
1859 for (GList *iter = colocations; iter != NULL; iter = iter->next) {
1860 pcmk__colocation_t *constraint = iter->data;
1861
1862 pcmk_resource_t *other = NULL;
1863 float other_factor = factor * constraint->score
1864 / (float) PCMK_SCORE_INFINITY;
1865
1866 if (pcmk_is_set(flags, pcmk__coloc_select_this_with)) {
1867 other = constraint->primary;
1868 } else if (!pcmk__colocation_has_influence(constraint, NULL)) {
1869 continue;
1870 } else {
1871 other = constraint->dependent;
1872 }
1873
1874 pcmk__rsc_trace(source_rsc,
1875 "Optionally merging score of '%s' constraint "
1876 "(%s with %s)",
1877 constraint->id, constraint->dependent->id,
1878 constraint->primary->id);
1879 other->cmds->add_colocated_node_scores(other, target_rsc, log_id,
1880 &work, constraint,
1881 other_factor, flags);
1882 pe__show_node_scores(true, NULL, log_id, work, source_rsc->cluster);
1883 }
1884 g_list_free(colocations);
1885
1886 } else if (pcmk_is_set(flags, pcmk__coloc_select_active)) {
1887 pcmk__rsc_info(source_rsc, "%s: Rolling back optional scores from %s",
1888 log_id, source_rsc->id);
1889 g_hash_table_destroy(work);
1890 pcmk__clear_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
1891 return;
1892 }
1893
1894
1895 if (pcmk_is_set(flags, pcmk__coloc_select_nonnegative)) {
1896 pcmk_node_t *node = NULL;
1897 GHashTableIter iter;
1898
1899 g_hash_table_iter_init(&iter, work);
1900 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1901 if (node->weight == INFINITY_HACK) {
1902 node->weight = 1;
1903 }
1904 }
1905 }
1906
1907 if (*nodes != NULL) {
1908 g_hash_table_destroy(*nodes);
1909 }
1910 *nodes = work;
1911
1912 pcmk__clear_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
1913 }
1914
1915
1916
1917
1918
1919
1920
1921
1922 void
1923 pcmk__add_dependent_scores(gpointer data, gpointer user_data)
1924 {
1925 pcmk__colocation_t *colocation = data;
1926 pcmk_resource_t *target_rsc = user_data;
1927
1928 pcmk_resource_t *source_rsc = colocation->dependent;
1929 const float factor = colocation->score / (float) PCMK_SCORE_INFINITY;
1930 uint32_t flags = pcmk__coloc_select_active;
1931
1932 if (!pcmk__colocation_has_influence(colocation, NULL)) {
1933 return;
1934 }
1935 if (pcmk__is_clone(target_rsc)) {
1936 flags |= pcmk__coloc_select_nonnegative;
1937 }
1938 pcmk__rsc_trace(target_rsc,
1939 "%s: Incorporating attenuated %s assignment scores due "
1940 "to colocation %s",
1941 target_rsc->id, source_rsc->id, colocation->id);
1942 source_rsc->cmds->add_colocated_node_scores(source_rsc, target_rsc,
1943 source_rsc->id,
1944 &target_rsc->allowed_nodes,
1945 colocation, factor, flags);
1946 }
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965 void
1966 pcmk__colocation_intersect_nodes(pcmk_resource_t *dependent,
1967 const pcmk_resource_t *primary,
1968 const pcmk__colocation_t *colocation,
1969 const GList *primary_nodes, bool merge_scores)
1970 {
1971 GHashTableIter iter;
1972 pcmk_node_t *dependent_node = NULL;
1973
1974 pcmk__assert((dependent != NULL) && (primary != NULL)
1975 && (colocation != NULL));
1976
1977 g_hash_table_iter_init(&iter, dependent->allowed_nodes);
1978 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &dependent_node)) {
1979 const pcmk_node_t *primary_node = NULL;
1980
1981 primary_node = pe_find_node_id(primary_nodes,
1982 dependent_node->details->id);
1983 if (primary_node == NULL) {
1984 dependent_node->weight = -PCMK_SCORE_INFINITY;
1985 pcmk__rsc_trace(dependent,
1986 "Banning %s from %s (no primary instance) for %s",
1987 dependent->id, pcmk__node_name(dependent_node),
1988 colocation->id);
1989
1990 } else if (merge_scores) {
1991 dependent_node->weight = pcmk__add_scores(dependent_node->weight,
1992 primary_node->weight);
1993 pcmk__rsc_trace(dependent,
1994 "Added %s's score %s to %s's score for %s (now %s) "
1995 "for colocation %s",
1996 primary->id, pcmk_readable_score(primary_node->weight),
1997 dependent->id, pcmk__node_name(dependent_node),
1998 pcmk_readable_score(dependent_node->weight),
1999 colocation->id);
2000 }
2001 }
2002 }
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014 GList *
2015 pcmk__with_this_colocations(const pcmk_resource_t *rsc)
2016 {
2017 GList *list = NULL;
2018
2019 rsc->cmds->with_this_colocations(rsc, rsc, &list);
2020 return list;
2021 }
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033 GList *
2034 pcmk__this_with_colocations(const pcmk_resource_t *rsc)
2035 {
2036 GList *list = NULL;
2037
2038 rsc->cmds->this_with_colocations(rsc, rsc, &list);
2039 return list;
2040 }