This source file includes following definitions.
- cmp_dependent_priority
- cmp_primary_priority
- anti_colocation_order
- pcmk__new_colocation
- unpack_influence
- unpack_colocation_set
- colocate_rsc_sets
- unpack_simple_colocation
- unpack_colocation_tags
- pcmk__unpack_colocation
- mark_start_blocked
- pcmk__block_colocated_starts
- pcmk__colocation_affects
- pcmk__apply_coloc_to_weights
- pcmk__apply_coloc_to_priority
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/pengine/status.h>
17 #include <pacemaker-internal.h>
18
19 #include "crm/common/util.h"
20 #include "crm/common/xml_internal.h"
21 #include "crm/msg_xml.h"
22 #include "libpacemaker_private.h"
23
24 #define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
25 __rsc = pcmk__find_constraint_resource(data_set->resources, __name); \
26 if (__rsc == NULL) { \
27 pcmk__config_err("%s: No resource found for %s", __set, __name); \
28 return; \
29 } \
30 } while(0)
31
32 static gint
33 cmp_dependent_priority(gconstpointer a, gconstpointer b)
34 {
35 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
36 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
37
38 if (a == NULL) {
39 return 1;
40 }
41 if (b == NULL) {
42 return -1;
43 }
44
45 CRM_ASSERT(rsc_constraint1->dependent != NULL);
46 CRM_ASSERT(rsc_constraint1->primary != NULL);
47
48 if (rsc_constraint1->dependent->priority > rsc_constraint2->dependent->priority) {
49 return -1;
50 }
51
52 if (rsc_constraint1->dependent->priority < rsc_constraint2->dependent->priority) {
53 return 1;
54 }
55
56
57 if (rsc_constraint1->dependent->variant > rsc_constraint2->dependent->variant) {
58 return -1;
59 }
60 if (rsc_constraint1->dependent->variant < rsc_constraint2->dependent->variant) {
61 return 1;
62 }
63
64
65
66
67
68 if (rsc_constraint1->dependent->variant == pe_clone) {
69 if (pcmk_is_set(rsc_constraint1->dependent->flags, pe_rsc_promotable)
70 && !pcmk_is_set(rsc_constraint2->dependent->flags, pe_rsc_promotable)) {
71 return -1;
72 } else if (!pcmk_is_set(rsc_constraint1->dependent->flags, pe_rsc_promotable)
73 && pcmk_is_set(rsc_constraint2->dependent->flags, pe_rsc_promotable)) {
74 return 1;
75 }
76 }
77
78 return strcmp(rsc_constraint1->dependent->id,
79 rsc_constraint2->dependent->id);
80 }
81
82 static gint
83 cmp_primary_priority(gconstpointer a, gconstpointer b)
84 {
85 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
86 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
87
88 if (a == NULL) {
89 return 1;
90 }
91 if (b == NULL) {
92 return -1;
93 }
94
95 CRM_ASSERT(rsc_constraint1->dependent != NULL);
96 CRM_ASSERT(rsc_constraint1->primary != NULL);
97
98 if (rsc_constraint1->primary->priority > rsc_constraint2->primary->priority) {
99 return -1;
100 }
101
102 if (rsc_constraint1->primary->priority < rsc_constraint2->primary->priority) {
103 return 1;
104 }
105
106
107 if (rsc_constraint1->primary->variant > rsc_constraint2->primary->variant) {
108 return -1;
109 } else if (rsc_constraint1->primary->variant < rsc_constraint2->primary->variant) {
110 return 1;
111 }
112
113
114
115
116
117 if (rsc_constraint1->primary->variant == pe_clone) {
118 if (pcmk_is_set(rsc_constraint1->primary->flags, pe_rsc_promotable)
119 && !pcmk_is_set(rsc_constraint2->primary->flags, pe_rsc_promotable)) {
120 return -1;
121 } else if (!pcmk_is_set(rsc_constraint1->primary->flags, pe_rsc_promotable)
122 && pcmk_is_set(rsc_constraint2->primary->flags, pe_rsc_promotable)) {
123 return 1;
124 }
125 }
126
127 return strcmp(rsc_constraint1->primary->id, rsc_constraint2->primary->id);
128 }
129
130
131
132
133
134 static void
135 anti_colocation_order(pe_resource_t *first_rsc, int first_role,
136 pe_resource_t *then_rsc, int then_role,
137 pe_working_set_t *data_set)
138 {
139 const char *first_tasks[] = { NULL, NULL };
140 const char *then_tasks[] = { NULL, NULL };
141
142
143 if (first_role == RSC_ROLE_PROMOTED) {
144 first_tasks[0] = CRMD_ACTION_DEMOTE;
145
146 } else {
147 first_tasks[0] = CRMD_ACTION_STOP;
148
149 if (first_role == RSC_ROLE_UNPROMOTED) {
150 first_tasks[1] = CRMD_ACTION_PROMOTE;
151 }
152 }
153
154
155 if (then_role == RSC_ROLE_PROMOTED) {
156 then_tasks[0] = CRMD_ACTION_PROMOTE;
157
158 } else {
159 then_tasks[0] = CRMD_ACTION_START;
160
161 if (then_role == RSC_ROLE_UNPROMOTED) {
162 then_tasks[1] = CRMD_ACTION_DEMOTE;
163 }
164 }
165
166 for (int first_lpc = 0;
167 (first_lpc <= 1) && (first_tasks[first_lpc] != NULL); first_lpc++) {
168
169 for (int then_lpc = 0;
170 (then_lpc <= 1) && (then_tasks[then_lpc] != NULL); then_lpc++) {
171
172 pcmk__order_resource_actions(first_rsc, first_tasks[first_lpc],
173 then_rsc, then_tasks[then_lpc],
174 pe_order_anti_colocation, data_set);
175 }
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 void
194 pcmk__new_colocation(const char *id, const char *node_attr, int score,
195 pe_resource_t *dependent, pe_resource_t *primary,
196 const char *dependent_role, const char *primary_role,
197 bool influence, pe_working_set_t *data_set)
198 {
199 pcmk__colocation_t *new_con = NULL;
200
201 if (score == 0) {
202 crm_trace("Ignoring colocation '%s' because score is 0", id);
203 return;
204 }
205 if ((dependent == NULL) || (primary == NULL)) {
206 pcmk__config_err("Ignoring colocation '%s' because resource "
207 "does not exist", id);
208 return;
209 }
210
211 new_con = calloc(1, sizeof(pcmk__colocation_t));
212 if (new_con == NULL) {
213 return;
214 }
215
216 if (pcmk__str_eq(dependent_role, RSC_ROLE_STARTED_S,
217 pcmk__str_null_matches|pcmk__str_casei)) {
218 dependent_role = RSC_ROLE_UNKNOWN_S;
219 }
220
221 if (pcmk__str_eq(primary_role, RSC_ROLE_STARTED_S,
222 pcmk__str_null_matches|pcmk__str_casei)) {
223 primary_role = RSC_ROLE_UNKNOWN_S;
224 }
225
226 new_con->id = id;
227 new_con->dependent = dependent;
228 new_con->primary = primary;
229 new_con->score = score;
230 new_con->dependent_role = text2role(dependent_role);
231 new_con->primary_role = text2role(primary_role);
232 new_con->node_attribute = node_attr;
233 new_con->influence = influence;
234
235 if (node_attr == NULL) {
236 node_attr = CRM_ATTR_UNAME;
237 }
238
239 pe_rsc_trace(dependent, "%s ==> %s (%s %d)",
240 dependent->id, primary->id, node_attr, score);
241
242 dependent->rsc_cons = g_list_insert_sorted(dependent->rsc_cons, new_con,
243 cmp_primary_priority);
244
245 primary->rsc_cons_lhs = g_list_insert_sorted(primary->rsc_cons_lhs, new_con,
246 cmp_dependent_priority);
247
248 data_set->colocation_constraints = g_list_append(data_set->colocation_constraints,
249 new_con);
250
251 if (score <= -INFINITY) {
252 anti_colocation_order(dependent, new_con->dependent_role, primary,
253 new_con->primary_role, data_set);
254 anti_colocation_order(primary, new_con->primary_role, dependent,
255 new_con->dependent_role, data_set);
256 }
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270 static bool
271 unpack_influence(const char *coloc_id, const pe_resource_t *rsc,
272 const char *influence_s)
273 {
274 if (influence_s != NULL) {
275 int influence_i = 0;
276
277 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
278 pcmk__config_err("Constraint '%s' has invalid value for "
279 XML_COLOC_ATTR_INFLUENCE " (using default)",
280 coloc_id);
281 } else {
282 return (influence_i != 0);
283 }
284 }
285 return pcmk_is_set(rsc->flags, pe_rsc_critical);
286 }
287
288 static void
289 unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
290 const char *influence_s, pe_working_set_t *data_set)
291 {
292 xmlNode *xml_rsc = NULL;
293 pe_resource_t *with = NULL;
294 pe_resource_t *resource = NULL;
295 const char *set_id = ID(set);
296 const char *role = crm_element_value(set, "role");
297 const char *ordering = crm_element_value(set, "ordering");
298 int local_score = score;
299 bool sequential = false;
300
301 const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE);
302
303 if (score_s) {
304 local_score = char2score(score_s);
305 }
306 if (local_score == 0) {
307 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
308 coloc_id, set_id);
309 return;
310 }
311
312 if (ordering == NULL) {
313 ordering = "group";
314 }
315
316 if (pcmk__xe_get_bool_attr(set, "sequential", &sequential) == pcmk_rc_ok && !sequential) {
317 return;
318
319 } else if ((local_score > 0)
320 && pcmk__str_eq(ordering, "group", pcmk__str_casei)) {
321 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
322 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
323
324 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
325 if (with != NULL) {
326 pe_rsc_trace(resource, "Colocating %s with %s", resource->id, with->id);
327 pcmk__new_colocation(set_id, NULL, local_score, resource,
328 with, role, role,
329 unpack_influence(coloc_id, resource,
330 influence_s), data_set);
331 }
332 with = resource;
333 }
334
335 } else if (local_score > 0) {
336 pe_resource_t *last = NULL;
337
338 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
339 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
340
341 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
342 if (last != NULL) {
343 pe_rsc_trace(resource, "Colocating %s with %s",
344 last->id, resource->id);
345 pcmk__new_colocation(set_id, NULL, local_score, last,
346 resource, role, role,
347 unpack_influence(coloc_id, last,
348 influence_s), data_set);
349 }
350
351 last = resource;
352 }
353
354 } else {
355
356
357
358
359
360 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
361 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
362
363 xmlNode *xml_rsc_with = NULL;
364 bool influence = true;
365
366 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
367 influence = unpack_influence(coloc_id, resource, influence_s);
368
369 for (xml_rsc_with = first_named_child(set, XML_TAG_RESOURCE_REF);
370 xml_rsc_with != NULL;
371 xml_rsc_with = crm_next_same_xml(xml_rsc_with)) {
372
373 if (pcmk__str_eq(resource->id, ID(xml_rsc_with),
374 pcmk__str_casei)) {
375 break;
376 }
377 EXPAND_CONSTRAINT_IDREF(set_id, with, ID(xml_rsc_with));
378 pe_rsc_trace(resource, "Anti-Colocating %s with %s", resource->id,
379 with->id);
380 pcmk__new_colocation(set_id, NULL, local_score,
381 resource, with, role, role,
382 influence, data_set);
383 }
384 }
385 }
386 }
387
388 static void
389 colocate_rsc_sets(const char *id, xmlNode *set1, xmlNode *set2, int score,
390 const char *influence_s, pe_working_set_t *data_set)
391 {
392 xmlNode *xml_rsc = NULL;
393 pe_resource_t *rsc_1 = NULL;
394 pe_resource_t *rsc_2 = NULL;
395
396 const char *role_1 = crm_element_value(set1, "role");
397 const char *role_2 = crm_element_value(set2, "role");
398
399 int rc = pcmk_rc_ok;
400 bool sequential = false;
401
402 if (score == 0) {
403 crm_trace("Ignoring colocation '%s' between sets because score is 0",
404 id);
405 return;
406 }
407
408 rc = pcmk__xe_get_bool_attr(set1, "sequential", &sequential);
409 if (rc != pcmk_rc_ok || sequential) {
410
411 xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
412 if (xml_rsc != NULL) {
413 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
414 }
415 }
416
417 rc = pcmk__xe_get_bool_attr(set2, "sequential", &sequential);
418 if (rc != pcmk_rc_ok || sequential) {
419
420 const char *rid = NULL;
421
422 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
423 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
424
425 rid = ID(xml_rsc);
426 }
427 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
428 }
429
430 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
431 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
432 unpack_influence(id, rsc_1, influence_s),
433 data_set);
434
435 } else if (rsc_1 != NULL) {
436 bool influence = unpack_influence(id, rsc_1, influence_s);
437
438 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
439 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
440
441 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
442 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
443 role_2, influence, data_set);
444 }
445
446 } else if (rsc_2 != NULL) {
447 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
448 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
449
450 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
451 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
452 role_2,
453 unpack_influence(id, rsc_1, influence_s),
454 data_set);
455 }
456
457 } else {
458 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
459 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
460
461 xmlNode *xml_rsc_2 = NULL;
462 bool influence = true;
463
464 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
465 influence = unpack_influence(id, rsc_1, influence_s);
466
467 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
468 xml_rsc_2 != NULL;
469 xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
470
471 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
472 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
473 role_1, role_2, influence,
474 data_set);
475 }
476 }
477 }
478 }
479
480 static void
481 unpack_simple_colocation(xmlNode *xml_obj, const char *id,
482 const char *influence_s, pe_working_set_t *data_set)
483 {
484 int score_i = 0;
485
486 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
487 const char *dependent_id = crm_element_value(xml_obj,
488 XML_COLOC_ATTR_SOURCE);
489 const char *primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
490 const char *dependent_role = crm_element_value(xml_obj,
491 XML_COLOC_ATTR_SOURCE_ROLE);
492 const char *primary_role = crm_element_value(xml_obj,
493 XML_COLOC_ATTR_TARGET_ROLE);
494 const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR);
495
496
497 const char *dependent_instance = crm_element_value(xml_obj,
498 XML_COLOC_ATTR_SOURCE_INSTANCE);
499 const char *primary_instance = crm_element_value(xml_obj,
500 XML_COLOC_ATTR_TARGET_INSTANCE);
501
502 pe_resource_t *dependent = pcmk__find_constraint_resource(data_set->resources,
503 dependent_id);
504 pe_resource_t *primary = pcmk__find_constraint_resource(data_set->resources,
505 primary_id);
506
507 if (dependent == NULL) {
508 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
509 "does not exist", id, dependent_id);
510 return;
511
512 } else if (primary == NULL) {
513 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
514 "does not exist", id, primary_id);
515 return;
516
517 } else if ((dependent_instance != NULL) && !pe_rsc_is_clone(dependent)) {
518 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
519 "is not a clone but instance '%s' was requested",
520 id, dependent_id, dependent_instance);
521 return;
522
523 } else if ((primary_instance != NULL) && !pe_rsc_is_clone(primary)) {
524 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
525 "is not a clone but instance '%s' was requested",
526 id, primary_id, primary_instance);
527 return;
528 }
529
530 if (dependent_instance != NULL) {
531 dependent = find_clone_instance(dependent, dependent_instance, data_set);
532 if (dependent == NULL) {
533 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
534 "does not have an instance '%s'",
535 id, dependent_id, dependent_instance);
536 return;
537 }
538 }
539
540 if (primary_instance != NULL) {
541 primary = find_clone_instance(primary, primary_instance, data_set);
542 if (primary == NULL) {
543 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
544 "does not have an instance '%s'",
545 "'%s'", id, primary_id, primary_instance);
546 return;
547 }
548 }
549
550 if (pcmk__xe_attr_is_true(xml_obj, XML_CONS_ATTR_SYMMETRICAL)) {
551 pcmk__config_warn("The colocation constraint '"
552 XML_CONS_ATTR_SYMMETRICAL
553 "' attribute has been removed");
554 }
555
556 if (score) {
557 score_i = char2score(score);
558 }
559
560 pcmk__new_colocation(id, attr, score_i, dependent, primary,
561 dependent_role, primary_role,
562 unpack_influence(id, dependent, influence_s), data_set);
563 }
564
565
566 static int
567 unpack_colocation_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
568 pe_working_set_t *data_set)
569 {
570 const char *id = NULL;
571 const char *dependent_id = NULL;
572 const char *primary_id = NULL;
573 const char *dependent_role = NULL;
574 const char *primary_role = NULL;
575
576 pe_resource_t *dependent = NULL;
577 pe_resource_t *primary = NULL;
578
579 pe_tag_t *dependent_tag = NULL;
580 pe_tag_t *primary_tag = NULL;
581
582 xmlNode *dependent_set = NULL;
583 xmlNode *primary_set = NULL;
584 bool any_sets = false;
585
586 *expanded_xml = NULL;
587
588 CRM_CHECK(xml_obj != NULL, return pcmk_rc_schema_validation);
589
590 id = ID(xml_obj);
591 if (id == NULL) {
592 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
593 crm_element_name(xml_obj));
594 return pcmk_rc_schema_validation;
595 }
596
597
598 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
599 if (*expanded_xml != NULL) {
600 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
601 return pcmk_rc_ok;
602 }
603
604 dependent_id = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
605 primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
606 if ((dependent_id == NULL) || (primary_id == NULL)) {
607 return pcmk_rc_ok;
608 }
609
610 if (!pcmk__valid_resource_or_tag(data_set, dependent_id, &dependent,
611 &dependent_tag)) {
612 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
613 "valid resource or tag", id, dependent_id);
614 return pcmk_rc_schema_validation;
615 }
616
617 if (!pcmk__valid_resource_or_tag(data_set, primary_id, &primary,
618 &primary_tag)) {
619 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
620 "valid resource or tag", id, primary_id);
621 return pcmk_rc_schema_validation;
622 }
623
624 if ((dependent != NULL) && (primary != NULL)) {
625
626 return pcmk_rc_ok;
627 }
628
629 if ((dependent_tag != NULL) && (primary_tag != NULL)) {
630
631 pcmk__config_err("Ignoring constraint '%s' because two templates or "
632 "tags cannot be colocated", id);
633 return pcmk_rc_schema_validation;
634 }
635
636 dependent_role = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
637 primary_role = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
638
639 *expanded_xml = copy_xml(xml_obj);
640
641
642 if (!pcmk__tag_to_set(*expanded_xml, &dependent_set, XML_COLOC_ATTR_SOURCE,
643 true, data_set)) {
644 free_xml(*expanded_xml);
645 *expanded_xml = NULL;
646 return pcmk_rc_schema_validation;
647 }
648
649 if (dependent_set != NULL) {
650 if (dependent_role != NULL) {
651
652 crm_xml_add(dependent_set, "role", dependent_role);
653 xml_remove_prop(*expanded_xml, XML_COLOC_ATTR_SOURCE_ROLE);
654 }
655 any_sets = true;
656 }
657
658
659 if (!pcmk__tag_to_set(*expanded_xml, &primary_set, XML_COLOC_ATTR_TARGET,
660 true, data_set)) {
661 free_xml(*expanded_xml);
662 *expanded_xml = NULL;
663 return pcmk_rc_schema_validation;
664 }
665
666 if (primary_set != NULL) {
667 if (primary_role != NULL) {
668
669 crm_xml_add(primary_set, "role", primary_role);
670 xml_remove_prop(*expanded_xml, XML_COLOC_ATTR_TARGET_ROLE);
671 }
672 any_sets = true;
673 }
674
675 if (any_sets) {
676 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
677 } else {
678 free_xml(*expanded_xml);
679 *expanded_xml = NULL;
680 }
681
682 return pcmk_rc_ok;
683 }
684
685
686
687
688
689
690
691
692 void
693 pcmk__unpack_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
694 {
695 int score_i = 0;
696 xmlNode *set = NULL;
697 xmlNode *last = NULL;
698
699 xmlNode *orig_xml = NULL;
700 xmlNode *expanded_xml = NULL;
701
702 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
703 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
704 const char *influence_s = crm_element_value(xml_obj,
705 XML_COLOC_ATTR_INFLUENCE);
706
707 if (score) {
708 score_i = char2score(score);
709 }
710
711 if (unpack_colocation_tags(xml_obj, &expanded_xml,
712 data_set) != pcmk_rc_ok) {
713 return;
714 }
715 if (expanded_xml) {
716 orig_xml = xml_obj;
717 xml_obj = expanded_xml;
718 }
719
720 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
721 set = crm_next_same_xml(set)) {
722
723 set = expand_idref(set, data_set->input);
724 if (set == NULL) {
725 if (expanded_xml != NULL) {
726 free_xml(expanded_xml);
727 }
728 return;
729 }
730
731 unpack_colocation_set(set, score_i, id, influence_s, data_set);
732
733 if (last != NULL) {
734 colocate_rsc_sets(id, last, set, score_i, influence_s, data_set);
735 }
736 last = set;
737 }
738
739 if (expanded_xml) {
740 free_xml(expanded_xml);
741 xml_obj = orig_xml;
742 }
743
744 if (last == NULL) {
745 unpack_simple_colocation(xml_obj, id, influence_s, data_set);
746 }
747 }
748
749 static void
750 mark_start_blocked(pe_resource_t *rsc, pe_resource_t *reason,
751 pe_working_set_t *data_set)
752 {
753 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
754
755 for (GList *gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
756 pe_action_t *action = (pe_action_t *) gIter->data;
757
758 if (pcmk_is_set(action->flags, pe_action_runnable)
759 && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
760
761 pe__clear_action_flags(action, pe_action_runnable);
762 pe_action_set_reason(action, reason_text, false);
763 pcmk__block_colocated_starts(action, data_set);
764 pcmk__update_action_for_orderings(action, data_set);
765 }
766 }
767 free(reason_text);
768 }
769
770
771
772
773
774
775
776
777 void
778 pcmk__block_colocated_starts(pe_action_t *action, pe_working_set_t *data_set)
779 {
780 GList *gIter = NULL;
781 pe_resource_t *rsc = NULL;
782
783 if (!pcmk_is_set(action->flags, pe_action_runnable)
784 && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
785
786 rsc = uber_parent(action->rsc);
787 if (rsc->parent) {
788
789
790
791
792
793 rsc = rsc->parent;
794 }
795 }
796
797 if ((rsc == NULL) || (rsc->rsc_cons_lhs == NULL)) {
798 return;
799 }
800
801
802 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
803 pe_resource_t *child = (pe_resource_t *)gIter->data;
804 pe_action_t *start = find_first_action(child->actions, NULL, RSC_START, NULL);
805
806 if ((start == NULL) || pcmk_is_set(start->flags, pe_action_runnable)) {
807 return;
808 }
809 }
810
811 for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
812 pcmk__colocation_t *colocate_with = (pcmk__colocation_t *) gIter->data;
813
814 if (colocate_with->score == INFINITY) {
815 mark_start_blocked(colocate_with->dependent, action->rsc, data_set);
816 }
817 }
818 }
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838 enum pcmk__coloc_affects
839 pcmk__colocation_affects(pe_resource_t *dependent, pe_resource_t *primary,
840 pcmk__colocation_t *constraint, bool preview)
841 {
842 if (!preview && pcmk_is_set(primary->flags, pe_rsc_provisional)) {
843
844 return pcmk__coloc_affects_nothing;
845 }
846
847 if ((constraint->dependent_role >= RSC_ROLE_UNPROMOTED)
848 && (dependent->parent != NULL)
849 && pcmk_is_set(dependent->parent->flags, pe_rsc_promotable)
850 && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
851
852
853
854
855
856 return pcmk__coloc_affects_role;
857 }
858
859 if (!preview && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
860
861
862
863
864
865 const pe_node_t *primary_node = primary->allocated_to;
866
867 if (dependent->allocated_to == NULL) {
868 crm_trace("Skipping colocation '%s': %s will not run anywhere",
869 constraint->id, dependent->id);
870
871 } else if (constraint->score >= INFINITY) {
872
873
874 if ((primary_node == NULL) ||
875 (primary_node->details != dependent->allocated_to->details)) {
876 crm_err("%s must be colocated with %s but is not (%s vs. %s)",
877 dependent->id, primary->id,
878 dependent->allocated_to->details->uname,
879 (primary_node == NULL)? "unallocated" : primary_node->details->uname);
880 }
881
882 } else if (constraint->score <= -CRM_SCORE_INFINITY) {
883
884
885 if ((primary_node != NULL) &&
886 (dependent->allocated_to->details == primary_node->details)) {
887 crm_err("%s and %s must be anti-colocated but are allocated "
888 "to the same node (%s)",
889 dependent->id, primary->id, primary_node->details->uname);
890 }
891 }
892 return pcmk__coloc_affects_nothing;
893 }
894
895 if ((constraint->score > 0)
896 && (constraint->dependent_role != RSC_ROLE_UNKNOWN)
897 && (constraint->dependent_role != dependent->next_role)) {
898
899 crm_trace("Skipping colocation '%s': dependent limited to %s role "
900 "but %s next role is %s",
901 constraint->id, role2text(constraint->dependent_role),
902 dependent->id, role2text(dependent->next_role));
903 return pcmk__coloc_affects_nothing;
904 }
905
906 if ((constraint->score > 0)
907 && (constraint->primary_role != RSC_ROLE_UNKNOWN)
908 && (constraint->primary_role != primary->next_role)) {
909
910 crm_trace("Skipping colocation '%s': primary limited to %s role "
911 "but %s next role is %s",
912 constraint->id, role2text(constraint->primary_role),
913 primary->id, role2text(primary->next_role));
914 return pcmk__coloc_affects_nothing;
915 }
916
917 if ((constraint->score < 0)
918 && (constraint->dependent_role != RSC_ROLE_UNKNOWN)
919 && (constraint->dependent_role == dependent->next_role)) {
920 crm_trace("Skipping anti-colocation '%s': dependent role %s matches",
921 constraint->id, role2text(constraint->dependent_role));
922 return pcmk__coloc_affects_nothing;
923 }
924
925 if ((constraint->score < 0)
926 && (constraint->primary_role != RSC_ROLE_UNKNOWN)
927 && (constraint->primary_role == primary->next_role)) {
928 crm_trace("Skipping anti-colocation '%s': primary role %s matches",
929 constraint->id, role2text(constraint->primary_role));
930 return pcmk__coloc_affects_nothing;
931 }
932
933 return pcmk__coloc_affects_location;
934 }
935
936
937
938
939
940
941
942
943
944
945
946
947 void
948 pcmk__apply_coloc_to_weights(pe_resource_t *dependent, pe_resource_t *primary,
949 pcmk__colocation_t *constraint)
950 {
951 const char *attribute = CRM_ATTR_ID;
952 const char *value = NULL;
953 GHashTable *work = NULL;
954 GHashTableIter iter;
955 pe_node_t *node = NULL;
956
957 if (constraint->node_attribute != NULL) {
958 attribute = constraint->node_attribute;
959 }
960
961 if (primary->allocated_to != NULL) {
962 value = pe_node_attribute_raw(primary->allocated_to, attribute);
963
964 } else if (constraint->score < 0) {
965
966 return;
967 }
968
969 work = pcmk__copy_node_table(dependent->allowed_nodes);
970
971 g_hash_table_iter_init(&iter, work);
972 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
973 if (primary->allocated_to == NULL) {
974 pe_rsc_trace(dependent, "%s: %s@%s -= %d (%s inactive)",
975 constraint->id, dependent->id, node->details->uname,
976 constraint->score, primary->id);
977 node->weight = pcmk__add_scores(-constraint->score, node->weight);
978
979 } else if (pcmk__str_eq(pe_node_attribute_raw(node, attribute), value,
980 pcmk__str_casei)) {
981 if (constraint->score < CRM_SCORE_INFINITY) {
982 pe_rsc_trace(dependent, "%s: %s@%s += %d",
983 constraint->id, dependent->id,
984 node->details->uname, constraint->score);
985 node->weight = pcmk__add_scores(constraint->score,
986 node->weight);
987 }
988
989 } else if (constraint->score >= CRM_SCORE_INFINITY) {
990 pe_rsc_trace(dependent, "%s: %s@%s -= %d (%s mismatch)",
991 constraint->id, dependent->id, node->details->uname,
992 constraint->score, attribute);
993 node->weight = pcmk__add_scores(-constraint->score, node->weight);
994 }
995 }
996
997 if ((constraint->score <= -INFINITY) || (constraint->score >= INFINITY)
998 || pcmk__any_node_available(work)) {
999
1000 g_hash_table_destroy(dependent->allowed_nodes);
1001 dependent->allowed_nodes = work;
1002 work = NULL;
1003
1004 } else {
1005 pe_rsc_info(dependent,
1006 "%s: Rolling back scores from %s (no available nodes)",
1007 dependent->id, primary->id);
1008 }
1009
1010 if (work != NULL) {
1011 g_hash_table_destroy(work);
1012 }
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 void
1027 pcmk__apply_coloc_to_priority(pe_resource_t *dependent, pe_resource_t *primary,
1028 pcmk__colocation_t *constraint)
1029 {
1030 const char *dependent_value = NULL;
1031 const char *primary_value = NULL;
1032 const char *attribute = CRM_ATTR_ID;
1033 int score_multiplier = 1;
1034
1035 if ((primary->allocated_to == NULL) || (dependent->allocated_to == NULL)) {
1036 return;
1037 }
1038
1039 if (constraint->node_attribute != NULL) {
1040 attribute = constraint->node_attribute;
1041 }
1042
1043 dependent_value = pe_node_attribute_raw(dependent->allocated_to, attribute);
1044 primary_value = pe_node_attribute_raw(primary->allocated_to, attribute);
1045
1046 if (!pcmk__str_eq(dependent_value, primary_value, pcmk__str_casei)) {
1047 if ((constraint->score == INFINITY)
1048 && (constraint->dependent_role == RSC_ROLE_PROMOTED)) {
1049 dependent->priority = -INFINITY;
1050 }
1051 return;
1052 }
1053
1054 if ((constraint->primary_role != RSC_ROLE_UNKNOWN)
1055 && (constraint->primary_role != primary->next_role)) {
1056 return;
1057 }
1058
1059 if (constraint->dependent_role == RSC_ROLE_UNPROMOTED) {
1060 score_multiplier = -1;
1061 }
1062
1063 dependent->priority = pcmk__add_scores(score_multiplier * constraint->score,
1064 dependent->priority);
1065 }