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