This source file includes following definitions.
- evaluate_lifetime
- unpack_constraints
- invert_action
- get_ordering_type
- pe_find_constraint_resource
- pe_find_constraint_tag
- valid_resource_or_tag
- order_is_symmetrical
- unpack_simple_rsc_order
- expand_tags_in_sets
- tag_to_set
- unpack_simple_location
- unpack_rsc_location
- unpack_location_tags
- unpack_location_set
- unpack_location
- get_node_score
- generate_location_rule
- sort_cons_priority_lh
- sort_cons_priority_rh
- anti_colocation_order
- pcmk__new_colocation
- new_rsc_order
- task_from_action_or_key
- handle_migration_ordering
- custom_action_order
- get_asymmetrical_flags
- get_flags
- unpack_order_set
- order_rsc_sets
- unpack_order_tags
- unpack_rsc_order
- unpack_influence
- unpack_colocation_set
- colocate_rsc_sets
- unpack_simple_colocation
- unpack_colocation_tags
- unpack_rsc_colocation
- rsc_ticket_new
- unpack_rsc_ticket_set
- unpack_simple_rsc_ticket
- unpack_rsc_ticket_tags
- unpack_rsc_ticket
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <stdbool.h>
15 #include <regex.h>
16 #include <glib.h>
17
18 #include <crm/crm.h>
19 #include <crm/cib.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/xml.h>
22 #include <crm/common/xml_internal.h>
23 #include <crm/common/iso8601.h>
24 #include <crm/pengine/status.h>
25 #include <crm/pengine/internal.h>
26 #include <crm/pengine/rules.h>
27 #include <pacemaker-internal.h>
28
29 enum pe_order_kind {
30 pe_order_kind_optional,
31 pe_order_kind_mandatory,
32 pe_order_kind_serialize,
33 };
34
35 #define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
36 __rsc = pe_find_constraint_resource(data_set->resources, __name); \
37 if(__rsc == NULL) { \
38 pcmk__config_err("%s: No resource found for %s", __set, __name); \
39 return FALSE; \
40 } \
41 } while(0)
42
43 enum pe_ordering get_flags(const char *id, enum pe_order_kind kind,
44 const char *action_first, const char *action_then, gboolean invert);
45 enum pe_ordering get_asymmetrical_flags(enum pe_order_kind kind);
46 static pe__location_t *generate_location_rule(pe_resource_t *rsc,
47 xmlNode *rule_xml,
48 const char *discovery,
49 crm_time_t *next_change,
50 pe_working_set_t *data_set,
51 pe_re_match_data_t *match_data);
52 static void unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set);
53 static void unpack_rsc_colocation(xmlNode *xml_obj, pe_working_set_t *data_set);
54
55 static bool
56 evaluate_lifetime(xmlNode *lifetime, pe_working_set_t *data_set)
57 {
58 bool result = FALSE;
59 crm_time_t *next_change = crm_time_new_undefined();
60
61 result = pe_evaluate_rules(lifetime, NULL, data_set->now, next_change);
62 if (crm_time_is_defined(next_change)) {
63 time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
64
65 pe__update_recheck_time(recheck, data_set);
66 }
67 crm_time_free(next_change);
68 return result;
69 }
70
71 gboolean
72 unpack_constraints(xmlNode * xml_constraints, pe_working_set_t * data_set)
73 {
74 xmlNode *xml_obj = NULL;
75 xmlNode *lifetime = NULL;
76
77 for (xml_obj = pcmk__xe_first_child(xml_constraints); xml_obj != NULL;
78 xml_obj = pcmk__xe_next(xml_obj)) {
79 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
80 const char *tag = crm_element_name(xml_obj);
81
82 if (id == NULL) {
83 pcmk__config_err("Ignoring <%s> constraint without "
84 XML_ATTR_ID, tag);
85 continue;
86 }
87
88 crm_trace("Processing constraint %s %s", tag, id);
89
90 lifetime = first_named_child(xml_obj, "lifetime");
91 if (lifetime) {
92 pcmk__config_warn("Support for 'lifetime' attribute (in %s) is "
93 "deprecated (the rules it contains should "
94 "instead be direct descendents of the "
95 "constraint object)", id);
96 }
97
98 if (lifetime && !evaluate_lifetime(lifetime, data_set)) {
99 crm_info("Constraint %s %s is not active", tag, id);
100
101 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_ORDER, tag, pcmk__str_casei)) {
102 unpack_rsc_order(xml_obj, data_set);
103
104 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_DEPEND, tag, pcmk__str_casei)) {
105 unpack_rsc_colocation(xml_obj, data_set);
106
107 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_LOCATION, tag, pcmk__str_casei)) {
108 unpack_location(xml_obj, data_set);
109
110 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_TICKET, tag, pcmk__str_casei)) {
111 unpack_rsc_ticket(xml_obj, data_set);
112
113 } else {
114 pe_err("Unsupported constraint type: %s", tag);
115 }
116 }
117
118 return TRUE;
119 }
120
121 static const char *
122 invert_action(const char *action)
123 {
124 if (pcmk__str_eq(action, RSC_START, pcmk__str_casei)) {
125 return RSC_STOP;
126
127 } else if (pcmk__str_eq(action, RSC_STOP, pcmk__str_casei)) {
128 return RSC_START;
129
130 } else if (pcmk__str_eq(action, RSC_PROMOTE, pcmk__str_casei)) {
131 return RSC_DEMOTE;
132
133 } else if (pcmk__str_eq(action, RSC_DEMOTE, pcmk__str_casei)) {
134 return RSC_PROMOTE;
135
136 } else if (pcmk__str_eq(action, RSC_PROMOTED, pcmk__str_casei)) {
137 return RSC_DEMOTED;
138
139 } else if (pcmk__str_eq(action, RSC_DEMOTED, pcmk__str_casei)) {
140 return RSC_PROMOTED;
141
142 } else if (pcmk__str_eq(action, RSC_STARTED, pcmk__str_casei)) {
143 return RSC_STOPPED;
144
145 } else if (pcmk__str_eq(action, RSC_STOPPED, pcmk__str_casei)) {
146 return RSC_STARTED;
147 }
148 crm_warn("Unknown action '%s' specified in order constraint", action);
149 return NULL;
150 }
151
152 static enum pe_order_kind
153 get_ordering_type(xmlNode * xml_obj)
154 {
155 enum pe_order_kind kind_e = pe_order_kind_mandatory;
156 const char *kind = crm_element_value(xml_obj, XML_ORDER_ATTR_KIND);
157
158 if (kind == NULL) {
159 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
160
161 kind_e = pe_order_kind_mandatory;
162
163 if (score) {
164
165 int score_i = char2score(score);
166
167 if (score_i == 0) {
168 kind_e = pe_order_kind_optional;
169 }
170 pe_warn_once(pe_wo_order_score,
171 "Support for 'score' in rsc_order is deprecated "
172 "and will be removed in a future release (use 'kind' instead)");
173 }
174
175 } else if (pcmk__str_eq(kind, "Mandatory", pcmk__str_casei)) {
176 kind_e = pe_order_kind_mandatory;
177
178 } else if (pcmk__str_eq(kind, "Optional", pcmk__str_casei)) {
179 kind_e = pe_order_kind_optional;
180
181 } else if (pcmk__str_eq(kind, "Serialize", pcmk__str_casei)) {
182 kind_e = pe_order_kind_serialize;
183
184 } else {
185 pcmk__config_err("Resetting '" XML_ORDER_ATTR_KIND "' for constraint "
186 "'%s' to Mandatory because '%s' is not valid",
187 crm_str(ID(xml_obj)), kind);
188 }
189 return kind_e;
190 }
191
192 static pe_resource_t *
193 pe_find_constraint_resource(GList *rsc_list, const char *id)
194 {
195 GList *rIter = NULL;
196
197 for (rIter = rsc_list; id && rIter; rIter = rIter->next) {
198 pe_resource_t *parent = rIter->data;
199 pe_resource_t *match = parent->fns->find_rsc(parent, id, NULL,
200 pe_find_renamed);
201
202 if (match != NULL) {
203 if(!pcmk__str_eq(match->id, id, pcmk__str_casei)) {
204
205 match = uber_parent(match);
206 crm_debug("Found %s for %s", match->id, id);
207 }
208 return match;
209 }
210 }
211 crm_trace("No match for %s", id);
212 return NULL;
213 }
214
215 static gboolean
216 pe_find_constraint_tag(pe_working_set_t * data_set, const char * id, pe_tag_t ** tag)
217 {
218 gboolean rc = FALSE;
219
220 *tag = NULL;
221 rc = g_hash_table_lookup_extended(data_set->template_rsc_sets, id,
222 NULL, (gpointer*) tag);
223
224 if (rc == FALSE) {
225 rc = g_hash_table_lookup_extended(data_set->tags, id,
226 NULL, (gpointer*) tag);
227
228 if (rc == FALSE) {
229 crm_warn("No template or tag named '%s'", id);
230 return FALSE;
231
232 } else if (*tag == NULL) {
233 crm_warn("No resource is tagged with '%s'", id);
234 return FALSE;
235 }
236
237 } else if (*tag == NULL) {
238 crm_warn("No resource is derived from template '%s'", id);
239 return FALSE;
240 }
241
242 return rc;
243 }
244
245 static gboolean
246 valid_resource_or_tag(pe_working_set_t * data_set, const char * id,
247 pe_resource_t ** rsc, pe_tag_t ** tag)
248 {
249 gboolean rc = FALSE;
250
251 if (rsc) {
252 *rsc = NULL;
253 *rsc = pe_find_constraint_resource(data_set->resources, id);
254 if (*rsc) {
255 return TRUE;
256 }
257 }
258
259 if (tag) {
260 *tag = NULL;
261 rc = pe_find_constraint_tag(data_set, id, tag);
262 }
263
264 return rc;
265 }
266
267 static gboolean
268 order_is_symmetrical(xmlNode * xml_obj,
269 enum pe_order_kind parent_kind, const char * parent_symmetrical_s)
270 {
271 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
272 const char *kind_s = crm_element_value(xml_obj, XML_ORDER_ATTR_KIND);
273 const char *score_s = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
274 const char *symmetrical_s = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL);
275 enum pe_order_kind kind = parent_kind;
276
277 if (kind_s || score_s) {
278 kind = get_ordering_type(xml_obj);
279 }
280
281 if (symmetrical_s == NULL) {
282 symmetrical_s = parent_symmetrical_s;
283 }
284
285 if (symmetrical_s) {
286 gboolean symmetrical = crm_is_true(symmetrical_s);
287
288 if (symmetrical && kind == pe_order_kind_serialize) {
289 pcmk__config_warn("Ignoring " XML_CONS_ATTR_SYMMETRICAL
290 " for '%s' because not valid with "
291 XML_ORDER_ATTR_KIND " of 'Serialize'", id);
292 return FALSE;
293 }
294
295 return symmetrical;
296
297 } else {
298 if (kind == pe_order_kind_serialize) {
299 return FALSE;
300
301 } else {
302 return TRUE;
303 }
304 }
305 }
306
307 static gboolean
308 unpack_simple_rsc_order(xmlNode * xml_obj, pe_working_set_t * data_set)
309 {
310 int order_id = 0;
311 pe_resource_t *rsc_then = NULL;
312 pe_resource_t *rsc_first = NULL;
313 gboolean invert_bool = TRUE;
314 int min_required_before = 0;
315 enum pe_order_kind kind = pe_order_kind_mandatory;
316 enum pe_ordering cons_weight = pe_order_optional;
317
318 const char *id_first = NULL;
319 const char *id_then = NULL;
320 const char *action_then = NULL;
321 const char *action_first = NULL;
322 const char *instance_then = NULL;
323 const char *instance_first = NULL;
324
325 const char *id = NULL;
326
327 CRM_CHECK(xml_obj != NULL, return FALSE);
328
329 id = crm_element_value(xml_obj, XML_ATTR_ID);
330 if (id == NULL) {
331 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
332 crm_element_name(xml_obj));
333 return FALSE;
334 }
335
336 invert_bool = order_is_symmetrical(xml_obj, kind, NULL);
337
338 id_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN);
339 id_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST);
340
341 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
342 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
343
344 instance_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_INSTANCE);
345 instance_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_INSTANCE);
346
347 if (action_first == NULL) {
348 action_first = RSC_START;
349 }
350 if (action_then == NULL) {
351 action_then = action_first;
352 }
353
354 if (id_first == NULL) {
355 pcmk__config_err("Ignoring constraint '%s' without "
356 XML_ORDER_ATTR_FIRST, id);
357 return FALSE;
358 }
359 if (id_then == NULL) {
360 pcmk__config_err("Ignoring constraint '%s' without "
361 XML_ORDER_ATTR_THEN, id);
362 return FALSE;
363 }
364
365 rsc_then = pe_find_constraint_resource(data_set->resources, id_then);
366 rsc_first = pe_find_constraint_resource(data_set->resources, id_first);
367
368 if (rsc_then == NULL) {
369 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
370 "does not exist", id, id_then);
371 return FALSE;
372
373 } else if (rsc_first == NULL) {
374 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
375 "does not exist", id, id_first);
376 return FALSE;
377
378 } else if (instance_then && pe_rsc_is_clone(rsc_then) == FALSE) {
379 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
380 "is not a clone but instance '%s' was requested",
381 id, id_then, instance_then);
382 return FALSE;
383
384 } else if (instance_first && pe_rsc_is_clone(rsc_first) == FALSE) {
385 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
386 "is not a clone but instance '%s' was requested",
387 id, id_first, instance_first);
388 return FALSE;
389 }
390
391 if (instance_then) {
392 rsc_then = find_clone_instance(rsc_then, instance_then, data_set);
393 if (rsc_then == NULL) {
394 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
395 "does not have an instance '%s'",
396 id, id_then, instance_then);
397 return FALSE;
398 }
399 }
400
401 if (instance_first) {
402 rsc_first = find_clone_instance(rsc_first, instance_first, data_set);
403 if (rsc_first == NULL) {
404 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
405 "does not have an instance '%s'",
406 "'%s'", id, id_first, instance_first);
407 return FALSE;
408 }
409 }
410
411 cons_weight = pe_order_optional;
412 kind = get_ordering_type(xml_obj);
413
414 if (kind == pe_order_kind_optional && rsc_then->restart_type == pe_restart_restart) {
415 crm_trace("Upgrade : recovery - implies right");
416 pe__set_order_flags(cons_weight, pe_order_implies_then);
417 }
418
419 if (invert_bool == FALSE) {
420 pe__set_order_flags(cons_weight, get_asymmetrical_flags(kind));
421 } else {
422 pe__set_order_flags(cons_weight,
423 get_flags(id, kind, action_first, action_then, FALSE));
424 }
425
426 if (pe_rsc_is_clone(rsc_first)) {
427
428
429
430 const char *min_clones_s = g_hash_table_lookup(rsc_first->meta,
431 XML_RSC_ATTR_INCARNATION_MIN);
432
433
434 const char *require_all_s = crm_element_value(xml_obj, "require-all");
435
436 if (min_clones_s) {
437 pcmk__scan_min_int(min_clones_s, &min_required_before, 0);
438
439 } else if (require_all_s) {
440 pe_warn_once(pe_wo_require_all,
441 "Support for require-all in ordering constraints "
442 "is deprecated and will be removed in a future release"
443 " (use clone-min clone meta-attribute instead)");
444 if (crm_is_true(require_all_s) == FALSE) {
445
446 min_required_before = 1;
447 }
448 }
449 }
450
451
452
453
454 if (min_required_before) {
455 GList *rIter = NULL;
456 char *task = crm_strdup_printf(CRM_OP_RELAXED_CLONE ":%s", id);
457 pe_action_t *unordered_action = get_pseudo_op(task, data_set);
458 free(task);
459
460
461
462
463 unordered_action->required_runnable_before = min_required_before;
464 pe__set_action_flags(unordered_action, pe_action_requires_any);
465
466 for (rIter = rsc_first->children; id && rIter; rIter = rIter->next) {
467 pe_resource_t *child = rIter->data;
468
469 custom_action_order(child, pcmk__op_key(child->id, action_first, 0),
470 NULL, NULL, NULL, unordered_action,
471 pe_order_one_or_more|pe_order_implies_then_printed,
472 data_set);
473 }
474
475
476
477 order_id = custom_action_order(NULL, NULL, unordered_action, rsc_then,
478 pcmk__op_key(rsc_then->id, action_then, 0),
479 NULL, cons_weight|pe_order_runnable_left,
480 data_set);
481 } else {
482 order_id = new_rsc_order(rsc_first, action_first, rsc_then, action_then, cons_weight, data_set);
483 }
484
485 pe_rsc_trace(rsc_first, "order-%d (%s): %s_%s before %s_%s flags=0x%.6x",
486 order_id, id, rsc_first->id, action_first, rsc_then->id, action_then, cons_weight);
487
488 if (invert_bool == FALSE) {
489 return TRUE;
490 }
491
492 action_then = invert_action(action_then);
493 action_first = invert_action(action_first);
494 if (action_then == NULL || action_first == NULL) {
495 pcmk__config_err("Cannot invert constraint '%s' "
496 "(please specify inverse manually)", id);
497 return TRUE;
498 }
499
500 cons_weight = pe_order_optional;
501 if (kind == pe_order_kind_optional && rsc_then->restart_type == pe_restart_restart) {
502 crm_trace("Upgrade : recovery - implies left");
503 pe__set_order_flags(cons_weight, pe_order_implies_first);
504 }
505
506 pe__set_order_flags(cons_weight,
507 get_flags(id, kind, action_first, action_then, TRUE));
508
509 order_id = new_rsc_order(rsc_then, action_then, rsc_first, action_first, cons_weight, data_set);
510
511 pe_rsc_trace(rsc_then, "order-%d (%s): %s_%s before %s_%s flags=0x%.6x",
512 order_id, id, rsc_then->id, action_then, rsc_first->id, action_first, cons_weight);
513
514 return TRUE;
515 }
516
517 static gboolean
518 expand_tags_in_sets(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * data_set)
519 {
520 xmlNode *new_xml = NULL;
521 xmlNode *set = NULL;
522 gboolean any_refs = FALSE;
523 const char *cons_id = NULL;
524
525 *expanded_xml = NULL;
526
527 CRM_CHECK(xml_obj != NULL, return FALSE);
528
529 new_xml = copy_xml(xml_obj);
530 cons_id = ID(new_xml);
531
532 for (set = pcmk__xe_first_child(new_xml); set != NULL;
533 set = pcmk__xe_next(set)) {
534
535 xmlNode *xml_rsc = NULL;
536 GList *tag_refs = NULL;
537 GList *gIter = NULL;
538
539 if (!pcmk__str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, pcmk__str_casei)) {
540 continue;
541 }
542
543 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
544 xml_rsc = pcmk__xe_next(xml_rsc)) {
545
546 pe_resource_t *rsc = NULL;
547 pe_tag_t *tag = NULL;
548 const char *id = ID(xml_rsc);
549
550 if (!pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_casei)) {
551 continue;
552 }
553
554 if (valid_resource_or_tag(data_set, id, &rsc, &tag) == FALSE) {
555 pcmk__config_err("Ignoring resource sets for constraint '%s' "
556 "because '%s' is not a valid resource or tag",
557 cons_id, id);
558 free_xml(new_xml);
559 return FALSE;
560
561 } else if (rsc) {
562 continue;
563
564 } else if (tag) {
565
566 xmlNode *last_ref = xml_rsc;
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
591 const char *obj_ref = (const char *) gIter->data;
592 xmlNode *new_rsc_ref = NULL;
593
594 new_rsc_ref = xmlNewDocRawNode(getDocPtr(set), NULL,
595 (pcmkXmlStr) XML_TAG_RESOURCE_REF, NULL);
596 crm_xml_add(new_rsc_ref, XML_ATTR_ID, obj_ref);
597 xmlAddNextSibling(last_ref, new_rsc_ref);
598
599 last_ref = new_rsc_ref;
600 }
601
602 any_refs = TRUE;
603
604
605
606
607
608
609 tag_refs = g_list_append(tag_refs, xml_rsc);
610 }
611 }
612
613
614
615
616
617
618
619
620
621
622
623 for (gIter = tag_refs; gIter != NULL; gIter = gIter->next) {
624 xmlNode *tag_ref = gIter->data;
625
626 free_xml(tag_ref);
627 }
628 g_list_free(tag_refs);
629 }
630
631 if (any_refs) {
632 *expanded_xml = new_xml;
633 } else {
634 free_xml(new_xml);
635 }
636
637 return TRUE;
638 }
639
640 static gboolean
641 tag_to_set(xmlNode * xml_obj, xmlNode ** rsc_set, const char * attr,
642 gboolean convert_rsc, pe_working_set_t * data_set)
643 {
644 const char *cons_id = NULL;
645 const char *id = NULL;
646
647 pe_resource_t *rsc = NULL;
648 pe_tag_t *tag = NULL;
649
650 *rsc_set = NULL;
651
652 CRM_CHECK((xml_obj != NULL) && (attr != NULL), return FALSE);
653
654 cons_id = ID(xml_obj);
655 if (cons_id == NULL) {
656 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
657 crm_element_name(xml_obj));
658 return FALSE;
659 }
660
661 id = crm_element_value(xml_obj, attr);
662 if (id == NULL) {
663 return TRUE;
664 }
665
666 if (valid_resource_or_tag(data_set, id, &rsc, &tag) == FALSE) {
667 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
668 "valid resource or tag", cons_id, id);
669 return FALSE;
670
671 } else if (tag) {
672 GList *gIter = NULL;
673
674
675
676
677 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
678 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
679
680 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
681 const char *obj_ref = (const char *) gIter->data;
682 xmlNode *rsc_ref = NULL;
683
684 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
685 crm_xml_add(rsc_ref, XML_ATTR_ID, obj_ref);
686 }
687
688
689 crm_xml_add(*rsc_set, "sequential", XML_BOOLEAN_FALSE);
690
691 } else if (rsc && convert_rsc) {
692
693
694 xmlNode *rsc_ref = NULL;
695
696 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
697 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
698
699 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
700 crm_xml_add(rsc_ref, XML_ATTR_ID, id);
701
702 } else {
703 return TRUE;
704 }
705
706
707 if (*rsc_set) {
708 xml_remove_prop(xml_obj, attr);
709 }
710
711 return TRUE;
712 }
713
714 static void unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc_lh,
715 const char *role, const char *score,
716 pe_working_set_t *data_set,
717 pe_re_match_data_t *match_data);
718
719 static void
720 unpack_simple_location(xmlNode *xml_obj, pe_working_set_t *data_set)
721 {
722 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
723 const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
724
725 if(value) {
726 pe_resource_t *rsc_lh = pe_find_constraint_resource(data_set->resources, value);
727
728 unpack_rsc_location(xml_obj, rsc_lh, NULL, NULL, data_set, NULL);
729 }
730
731 value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE_PATTERN);
732 if(value) {
733 regex_t *r_patt = calloc(1, sizeof(regex_t));
734 bool invert = FALSE;
735 GList *rIter = NULL;
736
737 if(value[0] == '!') {
738 value++;
739 invert = TRUE;
740 }
741
742 if (regcomp(r_patt, value, REG_EXTENDED)) {
743 pcmk__config_err("Ignoring constraint '%s' because "
744 XML_LOC_ATTR_SOURCE_PATTERN
745 " has invalid value '%s'", id, value);
746 regfree(r_patt);
747 free(r_patt);
748 return;
749 }
750
751 for (rIter = data_set->resources; rIter; rIter = rIter->next) {
752 pe_resource_t *r = rIter->data;
753 int nregs = 0;
754 regmatch_t *pmatch = NULL;
755 int status;
756
757 if(r_patt->re_nsub > 0) {
758 nregs = r_patt->re_nsub + 1;
759 } else {
760 nregs = 1;
761 }
762 pmatch = calloc(nregs, sizeof(regmatch_t));
763
764 status = regexec(r_patt, r->id, nregs, pmatch, 0);
765
766 if(invert == FALSE && status == 0) {
767 pe_re_match_data_t re_match_data = {
768 .string = r->id,
769 .nregs = nregs,
770 .pmatch = pmatch
771 };
772
773 crm_debug("'%s' matched '%s' for %s", r->id, value, id);
774 unpack_rsc_location(xml_obj, r, NULL, NULL, data_set, &re_match_data);
775
776 } else if (invert && (status != 0)) {
777 crm_debug("'%s' is an inverted match of '%s' for %s", r->id, value, id);
778 unpack_rsc_location(xml_obj, r, NULL, NULL, data_set, NULL);
779
780 } else {
781 crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
782 }
783
784 free(pmatch);
785 }
786
787 regfree(r_patt);
788 free(r_patt);
789 }
790 }
791
792 static void
793 unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc_lh, const char *role,
794 const char *score, pe_working_set_t *data_set,
795 pe_re_match_data_t *re_match_data)
796 {
797 pe__location_t *location = NULL;
798 const char *id_lh = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
799 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
800 const char *node = crm_element_value(xml_obj, XML_CIB_TAG_NODE);
801 const char *discovery = crm_element_value(xml_obj, XML_LOCATION_ATTR_DISCOVERY);
802
803 if (rsc_lh == NULL) {
804 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
805 "does not exist", id, id_lh);
806 return;
807 }
808
809 if (score == NULL) {
810 score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
811 }
812
813 if (node != NULL && score != NULL) {
814 int score_i = char2score(score);
815 pe_node_t *match = pe_find_node(data_set->nodes, node);
816
817 if (!match) {
818 return;
819 }
820 location = rsc2node_new(id, rsc_lh, score_i, discovery, match, data_set);
821
822 } else {
823 bool empty = TRUE;
824 crm_time_t *next_change = crm_time_new_undefined();
825
826
827
828
829
830 for (xmlNode *rule_xml = first_named_child(xml_obj, XML_TAG_RULE);
831 rule_xml != NULL; rule_xml = crm_next_same_xml(rule_xml)) {
832 empty = FALSE;
833 crm_trace("Unpacking %s/%s", id, ID(rule_xml));
834 generate_location_rule(rsc_lh, rule_xml, discovery, next_change,
835 data_set, re_match_data);
836 }
837
838 if (empty) {
839 pcmk__config_err("Ignoring constraint '%s' because it contains "
840 "no rules", id);
841 }
842
843
844
845
846 if (crm_time_is_defined(next_change)) {
847 time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
848
849 pe__update_recheck_time(t, data_set);
850 }
851 crm_time_free(next_change);
852 return;
853 }
854
855 if (role == NULL) {
856 role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
857 }
858
859 if (location && role) {
860 if (text2role(role) == RSC_ROLE_UNKNOWN) {
861 pe_err("Invalid constraint %s: Bad role %s", id, role);
862 return;
863
864 } else {
865 enum rsc_role_e r = text2role(role);
866 switch(r) {
867 case RSC_ROLE_UNKNOWN:
868 case RSC_ROLE_STARTED:
869 case RSC_ROLE_UNPROMOTED:
870
871 location->role_filter = RSC_ROLE_UNKNOWN;
872 break;
873 default:
874 location->role_filter = r;
875 break;
876 }
877 }
878 }
879 }
880
881 static gboolean
882 unpack_location_tags(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * data_set)
883 {
884 const char *id = NULL;
885 const char *id_lh = NULL;
886 const char *state_lh = NULL;
887
888 pe_resource_t *rsc_lh = NULL;
889
890 pe_tag_t *tag_lh = NULL;
891
892 xmlNode *new_xml = NULL;
893 xmlNode *rsc_set_lh = NULL;
894
895 *expanded_xml = NULL;
896
897 CRM_CHECK(xml_obj != NULL, return FALSE);
898
899 id = ID(xml_obj);
900 if (id == NULL) {
901 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
902 crm_element_name(xml_obj));
903 return FALSE;
904 }
905
906
907 expand_tags_in_sets(xml_obj, &new_xml, data_set);
908 if (new_xml) {
909
910 crm_log_xml_trace(new_xml, "Expanded rsc_location...");
911 *expanded_xml = new_xml;
912 return TRUE;
913 }
914
915 id_lh = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
916 if (id_lh == NULL) {
917 return TRUE;
918 }
919
920 if (valid_resource_or_tag(data_set, id_lh, &rsc_lh, &tag_lh) == FALSE) {
921 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
922 "valid resource or tag", id, id_lh);
923 return FALSE;
924
925 } else if (rsc_lh) {
926
927 return TRUE;
928 }
929
930 state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
931
932 new_xml = copy_xml(xml_obj);
933
934
935 if (tag_to_set(new_xml, &rsc_set_lh, XML_LOC_ATTR_SOURCE, FALSE, data_set) == FALSE) {
936 free_xml(new_xml);
937 return FALSE;
938 }
939
940 if (rsc_set_lh) {
941 if (state_lh) {
942
943
944 crm_xml_add(rsc_set_lh, "role", state_lh);
945 xml_remove_prop(new_xml, XML_RULE_ATTR_ROLE);
946 }
947 crm_log_xml_trace(new_xml, "Expanded rsc_location...");
948 *expanded_xml = new_xml;
949
950 } else {
951
952 free_xml(new_xml);
953 }
954
955 return TRUE;
956 }
957
958 static gboolean
959 unpack_location_set(xmlNode * location, xmlNode * set, pe_working_set_t * data_set)
960 {
961 xmlNode *xml_rsc = NULL;
962 pe_resource_t *resource = NULL;
963 const char *set_id;
964 const char *role;
965 const char *local_score;
966
967 CRM_CHECK(set != NULL, return FALSE);
968
969 set_id = ID(set);
970 if (set_id == NULL) {
971 pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
972 XML_ATTR_ID " in constraint '%s'",
973 crm_str(ID(location)));
974 return FALSE;
975 }
976
977 role = crm_element_value(set, "role");
978 local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
979
980 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
981 xml_rsc = pcmk__xe_next(xml_rsc)) {
982
983 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
984 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
985 unpack_rsc_location(location, resource, role, local_score, data_set, NULL);
986 }
987 }
988
989 return TRUE;
990 }
991
992 static void
993 unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set)
994 {
995 xmlNode *set = NULL;
996 gboolean any_sets = FALSE;
997
998 xmlNode *orig_xml = NULL;
999 xmlNode *expanded_xml = NULL;
1000
1001 if (unpack_location_tags(xml_obj, &expanded_xml, data_set) == FALSE) {
1002 return;
1003 }
1004
1005 if (expanded_xml) {
1006 orig_xml = xml_obj;
1007 xml_obj = expanded_xml;
1008 }
1009
1010 for (set = pcmk__xe_first_child(xml_obj); set != NULL;
1011 set = pcmk__xe_next(set)) {
1012
1013 if (pcmk__str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, pcmk__str_none)) {
1014 any_sets = TRUE;
1015 set = expand_idref(set, data_set->input);
1016 if (unpack_location_set(xml_obj, set, data_set) == FALSE) {
1017 if (expanded_xml) {
1018 free_xml(expanded_xml);
1019 }
1020 return;
1021 }
1022 }
1023 }
1024
1025 if (expanded_xml) {
1026 free_xml(expanded_xml);
1027 xml_obj = orig_xml;
1028 }
1029
1030 if (any_sets == FALSE) {
1031 unpack_simple_location(xml_obj, data_set);
1032 }
1033 }
1034
1035 static int
1036 get_node_score(const char *rule, const char *score, gboolean raw, pe_node_t * node, pe_resource_t *rsc)
1037 {
1038 int score_f = 0;
1039
1040 if (score == NULL) {
1041 pe_err("Rule %s: no score specified. Assuming 0.", rule);
1042
1043 } else if (raw) {
1044 score_f = char2score(score);
1045
1046 } else {
1047 const char *attr_score = pe_node_attribute_calculated(node, score, rsc);
1048
1049 if (attr_score == NULL) {
1050 crm_debug("Rule %s: node %s did not have a value for %s",
1051 rule, node->details->uname, score);
1052 score_f = -INFINITY;
1053
1054 } else {
1055 crm_debug("Rule %s: node %s had value %s for %s",
1056 rule, node->details->uname, attr_score, score);
1057 score_f = char2score(attr_score);
1058 }
1059 }
1060 return score_f;
1061 }
1062
1063 static pe__location_t *
1064 generate_location_rule(pe_resource_t *rsc, xmlNode *rule_xml,
1065 const char *discovery, crm_time_t *next_change,
1066 pe_working_set_t *data_set,
1067 pe_re_match_data_t *re_match_data)
1068 {
1069 const char *rule_id = NULL;
1070 const char *score = NULL;
1071 const char *boolean = NULL;
1072 const char *role = NULL;
1073
1074 GList *gIter = NULL;
1075 GList *match_L = NULL;
1076
1077 gboolean do_and = TRUE;
1078 gboolean accept = TRUE;
1079 gboolean raw_score = TRUE;
1080 gboolean score_allocated = FALSE;
1081
1082 pe__location_t *location_rule = NULL;
1083
1084 rule_xml = expand_idref(rule_xml, data_set->input);
1085 rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
1086 boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
1087 role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
1088
1089 crm_trace("Processing rule: %s", rule_id);
1090
1091 if (role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) {
1092 pe_err("Bad role specified for %s: %s", rule_id, role);
1093 return NULL;
1094 }
1095
1096 score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
1097 if (score == NULL) {
1098 score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE);
1099 if (score != NULL) {
1100 raw_score = FALSE;
1101 }
1102 }
1103 if (pcmk__str_eq(boolean, "or", pcmk__str_casei)) {
1104 do_and = FALSE;
1105 }
1106
1107 location_rule = rsc2node_new(rule_id, rsc, 0, discovery, NULL, data_set);
1108
1109 if (location_rule == NULL) {
1110 return NULL;
1111 }
1112
1113 if ((re_match_data != NULL) && (re_match_data->nregs > 0)
1114 && (re_match_data->pmatch[0].rm_so != -1) && !raw_score) {
1115
1116 char *result = pe_expand_re_matches(score, re_match_data);
1117
1118 if (result != NULL) {
1119 score = result;
1120 score_allocated = TRUE;
1121 }
1122 }
1123
1124 if (role != NULL) {
1125 crm_trace("Setting role filter: %s", role);
1126 location_rule->role_filter = text2role(role);
1127 if (location_rule->role_filter == RSC_ROLE_UNPROMOTED) {
1128
1129
1130
1131
1132 location_rule->role_filter = RSC_ROLE_UNKNOWN;
1133 }
1134 }
1135 if (do_and) {
1136 GList *gIter = NULL;
1137
1138 match_L = pcmk__copy_node_list(data_set->nodes, true);
1139 for (gIter = match_L; gIter != NULL; gIter = gIter->next) {
1140 pe_node_t *node = (pe_node_t *) gIter->data;
1141
1142 node->weight = get_node_score(rule_id, score, raw_score, node, rsc);
1143 }
1144 }
1145
1146 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1147 int score_f = 0;
1148 pe_node_t *node = (pe_node_t *) gIter->data;
1149 pe_match_data_t match_data = {
1150 .re = re_match_data,
1151 .params = pe_rsc_params(rsc, node, data_set),
1152 .meta = rsc->meta,
1153 };
1154
1155 accept = pe_test_rule(rule_xml, node->details->attrs, RSC_ROLE_UNKNOWN,
1156 data_set->now, next_change, &match_data);
1157
1158 crm_trace("Rule %s %s on %s", ID(rule_xml), accept ? "passed" : "failed",
1159 node->details->uname);
1160
1161 score_f = get_node_score(rule_id, score, raw_score, node, rsc);
1162
1163
1164
1165
1166 if (accept) {
1167 pe_node_t *local = pe_find_node_id(match_L, node->details->id);
1168
1169 if (local == NULL && do_and) {
1170 continue;
1171
1172 } else if (local == NULL) {
1173 local = pe__copy_node(node);
1174 match_L = g_list_append(match_L, local);
1175 }
1176
1177 if (do_and == FALSE) {
1178 local->weight = pe__add_scores(local->weight, score_f);
1179 }
1180 crm_trace("node %s now has weight %d", node->details->uname, local->weight);
1181
1182 } else if (do_and && !accept) {
1183
1184 pe_node_t *delete = pe_find_node_id(match_L, node->details->id);
1185
1186 if (delete != NULL) {
1187 match_L = g_list_remove(match_L, delete);
1188 crm_trace("node %s did not match", node->details->uname);
1189 }
1190 free(delete);
1191 }
1192 }
1193
1194 if (score_allocated == TRUE) {
1195 free((char *)score);
1196 }
1197
1198 location_rule->node_list_rh = match_L;
1199 if (location_rule->node_list_rh == NULL) {
1200 crm_trace("No matching nodes for rule %s", rule_id);
1201 return NULL;
1202 }
1203
1204 crm_trace("%s: %d nodes matched", rule_id, g_list_length(location_rule->node_list_rh));
1205 return location_rule;
1206 }
1207
1208 static gint
1209 sort_cons_priority_lh(gconstpointer a, gconstpointer b)
1210 {
1211 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
1212 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
1213
1214 if (a == NULL) {
1215 return 1;
1216 }
1217 if (b == NULL) {
1218 return -1;
1219 }
1220
1221 CRM_ASSERT(rsc_constraint1->rsc_lh != NULL);
1222 CRM_ASSERT(rsc_constraint1->rsc_rh != NULL);
1223
1224 if (rsc_constraint1->rsc_lh->priority > rsc_constraint2->rsc_lh->priority) {
1225 return -1;
1226 }
1227
1228 if (rsc_constraint1->rsc_lh->priority < rsc_constraint2->rsc_lh->priority) {
1229 return 1;
1230 }
1231
1232
1233 if (rsc_constraint1->rsc_lh->variant > rsc_constraint2->rsc_lh->variant) {
1234 return -1;
1235 } else if (rsc_constraint1->rsc_lh->variant < rsc_constraint2->rsc_lh->variant) {
1236 return 1;
1237 }
1238
1239
1240
1241
1242
1243 if (rsc_constraint1->rsc_lh->variant == pe_clone) {
1244 if (pcmk_is_set(rsc_constraint1->rsc_lh->flags, pe_rsc_promotable)
1245 && !pcmk_is_set(rsc_constraint2->rsc_lh->flags, pe_rsc_promotable)) {
1246 return -1;
1247 } else if (!pcmk_is_set(rsc_constraint1->rsc_lh->flags, pe_rsc_promotable)
1248 && pcmk_is_set(rsc_constraint2->rsc_lh->flags, pe_rsc_promotable)) {
1249 return 1;
1250 }
1251 }
1252
1253 return strcmp(rsc_constraint1->rsc_lh->id, rsc_constraint2->rsc_lh->id);
1254 }
1255
1256 static gint
1257 sort_cons_priority_rh(gconstpointer a, gconstpointer b)
1258 {
1259 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
1260 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
1261
1262 if (a == NULL) {
1263 return 1;
1264 }
1265 if (b == NULL) {
1266 return -1;
1267 }
1268
1269 CRM_ASSERT(rsc_constraint1->rsc_lh != NULL);
1270 CRM_ASSERT(rsc_constraint1->rsc_rh != NULL);
1271
1272 if (rsc_constraint1->rsc_rh->priority > rsc_constraint2->rsc_rh->priority) {
1273 return -1;
1274 }
1275
1276 if (rsc_constraint1->rsc_rh->priority < rsc_constraint2->rsc_rh->priority) {
1277 return 1;
1278 }
1279
1280
1281 if (rsc_constraint1->rsc_rh->variant > rsc_constraint2->rsc_rh->variant) {
1282 return -1;
1283 } else if (rsc_constraint1->rsc_rh->variant < rsc_constraint2->rsc_rh->variant) {
1284 return 1;
1285 }
1286
1287
1288
1289
1290
1291 if (rsc_constraint1->rsc_rh->variant == pe_clone) {
1292 if (pcmk_is_set(rsc_constraint1->rsc_rh->flags, pe_rsc_promotable)
1293 && !pcmk_is_set(rsc_constraint2->rsc_rh->flags, pe_rsc_promotable)) {
1294 return -1;
1295 } else if (!pcmk_is_set(rsc_constraint1->rsc_rh->flags, pe_rsc_promotable)
1296 && pcmk_is_set(rsc_constraint2->rsc_rh->flags, pe_rsc_promotable)) {
1297 return 1;
1298 }
1299 }
1300
1301 return strcmp(rsc_constraint1->rsc_rh->id, rsc_constraint2->rsc_rh->id);
1302 }
1303
1304 static void
1305 anti_colocation_order(pe_resource_t * first_rsc, int first_role,
1306 pe_resource_t * then_rsc, int then_role,
1307 pe_working_set_t * data_set)
1308 {
1309 const char *first_tasks[] = { NULL, NULL };
1310 const char *then_tasks[] = { NULL, NULL };
1311 int first_lpc = 0;
1312 int then_lpc = 0;
1313
1314
1315 if (first_role == RSC_ROLE_PROMOTED) {
1316 first_tasks[0] = CRMD_ACTION_DEMOTE;
1317
1318 } else {
1319 first_tasks[0] = CRMD_ACTION_STOP;
1320
1321 if (first_role == RSC_ROLE_UNPROMOTED) {
1322 first_tasks[1] = CRMD_ACTION_PROMOTE;
1323 }
1324 }
1325
1326
1327 if (then_role == RSC_ROLE_PROMOTED) {
1328 then_tasks[0] = CRMD_ACTION_PROMOTE;
1329
1330 } else {
1331 then_tasks[0] = CRMD_ACTION_START;
1332
1333 if (then_role == RSC_ROLE_UNPROMOTED) {
1334 then_tasks[1] = CRMD_ACTION_DEMOTE;
1335 }
1336 }
1337
1338 for (first_lpc = 0; first_lpc <= 1 && first_tasks[first_lpc] != NULL; first_lpc++) {
1339 for (then_lpc = 0; then_lpc <= 1 && then_tasks[then_lpc] != NULL; then_lpc++) {
1340 new_rsc_order(first_rsc, first_tasks[first_lpc], then_rsc, then_tasks[then_lpc],
1341 pe_order_anti_colocation, data_set);
1342 }
1343 }
1344 }
1345
1346 void
1347 pcmk__new_colocation(const char *id, const char *node_attr, int score,
1348 pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
1349 const char *state_lh, const char *state_rh,
1350 bool influence, pe_working_set_t *data_set)
1351 {
1352 pcmk__colocation_t *new_con = NULL;
1353
1354 if (score == 0) {
1355 crm_trace("Ignoring colocation '%s' because score is 0", id);
1356 return;
1357 }
1358 if ((rsc_lh == NULL) || (rsc_rh == NULL)) {
1359 pcmk__config_err("Ignoring colocation '%s' because resource "
1360 "does not exist", id);
1361 return;
1362 }
1363
1364 new_con = calloc(1, sizeof(pcmk__colocation_t));
1365 if (new_con == NULL) {
1366 return;
1367 }
1368
1369 if (pcmk__str_eq(state_lh, RSC_ROLE_STARTED_S, pcmk__str_null_matches | pcmk__str_casei)) {
1370 state_lh = RSC_ROLE_UNKNOWN_S;
1371 }
1372
1373 if (pcmk__str_eq(state_rh, RSC_ROLE_STARTED_S, pcmk__str_null_matches | pcmk__str_casei)) {
1374 state_rh = RSC_ROLE_UNKNOWN_S;
1375 }
1376
1377 new_con->id = id;
1378 new_con->rsc_lh = rsc_lh;
1379 new_con->rsc_rh = rsc_rh;
1380 new_con->score = score;
1381 new_con->role_lh = text2role(state_lh);
1382 new_con->role_rh = text2role(state_rh);
1383 new_con->node_attribute = node_attr;
1384 new_con->influence = influence;
1385
1386 if (node_attr == NULL) {
1387 node_attr = CRM_ATTR_UNAME;
1388 }
1389
1390 pe_rsc_trace(rsc_lh, "%s ==> %s (%s %d)", rsc_lh->id, rsc_rh->id, node_attr, score);
1391
1392 rsc_lh->rsc_cons = g_list_insert_sorted(rsc_lh->rsc_cons, new_con, sort_cons_priority_rh);
1393
1394 rsc_rh->rsc_cons_lhs =
1395 g_list_insert_sorted(rsc_rh->rsc_cons_lhs, new_con, sort_cons_priority_lh);
1396
1397 data_set->colocation_constraints = g_list_append(data_set->colocation_constraints, new_con);
1398
1399 if (score <= -INFINITY) {
1400 anti_colocation_order(rsc_lh, new_con->role_lh, rsc_rh, new_con->role_rh, data_set);
1401 anti_colocation_order(rsc_rh, new_con->role_rh, rsc_lh, new_con->role_lh, data_set);
1402 }
1403 }
1404
1405
1406 int
1407 new_rsc_order(pe_resource_t * lh_rsc, const char *lh_task,
1408 pe_resource_t * rh_rsc, const char *rh_task,
1409 enum pe_ordering type, pe_working_set_t * data_set)
1410 {
1411 char *lh_key = NULL;
1412 char *rh_key = NULL;
1413
1414 CRM_CHECK(lh_rsc != NULL, return -1);
1415 CRM_CHECK(lh_task != NULL, return -1);
1416 CRM_CHECK(rh_rsc != NULL, return -1);
1417 CRM_CHECK(rh_task != NULL, return -1);
1418
1419 #if 0
1420
1421
1422
1423 if (validate_order_resources(lh_rsc, lh_task, rh_rsc, rh_task)) {
1424 return -1;
1425 }
1426 #endif
1427
1428 lh_key = pcmk__op_key(lh_rsc->id, lh_task, 0);
1429 rh_key = pcmk__op_key(rh_rsc->id, rh_task, 0);
1430
1431 return custom_action_order(lh_rsc, lh_key, NULL, rh_rsc, rh_key, NULL, type, data_set);
1432 }
1433
1434 static char *
1435 task_from_action_or_key(pe_action_t *action, const char *key)
1436 {
1437 char *res = NULL;
1438
1439 if (action) {
1440 res = strdup(action->task);
1441 } else if (key) {
1442 parse_op_key(key, NULL, &res, NULL);
1443 }
1444 return res;
1445 }
1446
1447
1448
1449
1450
1451 static void
1452 handle_migration_ordering(pe__ordering_t *order, pe_working_set_t *data_set)
1453 {
1454 char *lh_task = NULL;
1455 char *rh_task = NULL;
1456 gboolean rh_migratable;
1457 gboolean lh_migratable;
1458
1459 if (order->lh_rsc == NULL || order->rh_rsc == NULL) {
1460 return;
1461 } else if (order->lh_rsc == order->rh_rsc) {
1462 return;
1463
1464
1465 } else if (is_parent(order->lh_rsc, order->rh_rsc)) {
1466 return;
1467 } else if (is_parent(order->rh_rsc, order->lh_rsc)) {
1468 return;
1469 }
1470
1471 lh_migratable = pcmk_is_set(order->lh_rsc->flags, pe_rsc_allow_migrate);
1472 rh_migratable = pcmk_is_set(order->rh_rsc->flags, pe_rsc_allow_migrate);
1473
1474
1475
1476 if (lh_migratable == FALSE && rh_migratable == FALSE) {
1477 return;
1478 }
1479
1480
1481
1482
1483
1484 lh_task = task_from_action_or_key(order->lh_action, order->lh_action_task);
1485 rh_task = task_from_action_or_key(order->rh_action, order->rh_action_task);
1486 if (lh_task == NULL || rh_task == NULL) {
1487 goto cleanup_order;
1488 }
1489
1490 if (pcmk__str_eq(lh_task, RSC_START, pcmk__str_casei) && pcmk__str_eq(rh_task, RSC_START, pcmk__str_casei)) {
1491 int flags = pe_order_optional;
1492
1493 if (lh_migratable && rh_migratable) {
1494
1495
1496 custom_action_order(order->lh_rsc,
1497 pcmk__op_key(order->lh_rsc->id, RSC_MIGRATED, 0),
1498 NULL, order->rh_rsc,
1499 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
1500 NULL, flags, data_set);
1501 }
1502
1503 if (rh_migratable) {
1504 if (lh_migratable) {
1505 pe__set_order_flags(flags, pe_order_apply_first_non_migratable);
1506 }
1507
1508
1509
1510 custom_action_order(order->lh_rsc,
1511 pcmk__op_key(order->lh_rsc->id, RSC_START, 0),
1512 NULL, order->rh_rsc,
1513 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
1514 NULL, flags, data_set);
1515 }
1516
1517 } else if (rh_migratable == TRUE && pcmk__str_eq(lh_task, RSC_STOP, pcmk__str_casei) && pcmk__str_eq(rh_task, RSC_STOP, pcmk__str_casei)) {
1518 int flags = pe_order_optional;
1519
1520 if (lh_migratable) {
1521 pe__set_order_flags(flags, pe_order_apply_first_non_migratable);
1522 }
1523
1524
1525
1526
1527 custom_action_order(order->lh_rsc,
1528 pcmk__op_key(order->lh_rsc->id, RSC_STOP, 0), NULL,
1529 order->rh_rsc,
1530 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
1531 NULL, flags, data_set);
1532
1533
1534
1535 if (order->rh_rsc->partial_migration_target) {
1536 custom_action_order(order->lh_rsc,
1537 pcmk__op_key(order->lh_rsc->id, RSC_STOP, 0),
1538 NULL, order->rh_rsc,
1539 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATED, 0),
1540 NULL, flags, data_set);
1541 }
1542
1543 } else if (pcmk__str_eq(lh_task, RSC_PROMOTE, pcmk__str_casei) && pcmk__str_eq(rh_task, RSC_START, pcmk__str_casei)) {
1544 int flags = pe_order_optional;
1545
1546 if (rh_migratable) {
1547
1548
1549 custom_action_order(order->lh_rsc,
1550 pcmk__op_key(order->lh_rsc->id, RSC_PROMOTE, 0),
1551 NULL, order->rh_rsc,
1552 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
1553 NULL, flags, data_set);
1554 }
1555
1556 } else if (pcmk__str_eq(lh_task, RSC_DEMOTE, pcmk__str_casei) && pcmk__str_eq(rh_task, RSC_STOP, pcmk__str_casei)) {
1557 int flags = pe_order_optional;
1558
1559 if (rh_migratable) {
1560
1561
1562 custom_action_order(order->lh_rsc, pcmk__op_key(order->lh_rsc->id, RSC_DEMOTE, 0), NULL,
1563 order->rh_rsc, pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0), NULL,
1564 flags, data_set);
1565
1566
1567
1568 if (order->rh_rsc->partial_migration_target) {
1569 custom_action_order(order->lh_rsc,
1570 pcmk__op_key(order->lh_rsc->id, RSC_DEMOTE, 0),
1571 NULL, order->rh_rsc,
1572 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATED, 0),
1573 NULL, flags, data_set);
1574 }
1575 }
1576 }
1577
1578 cleanup_order:
1579 free(lh_task);
1580 free(rh_task);
1581 }
1582
1583
1584 int
1585 custom_action_order(pe_resource_t * lh_rsc, char *lh_action_task, pe_action_t * lh_action,
1586 pe_resource_t * rh_rsc, char *rh_action_task, pe_action_t * rh_action,
1587 enum pe_ordering type, pe_working_set_t * data_set)
1588 {
1589 pe__ordering_t *order = NULL;
1590
1591 if (lh_rsc == NULL && lh_action) {
1592 lh_rsc = lh_action->rsc;
1593 }
1594 if (rh_rsc == NULL && rh_action) {
1595 rh_rsc = rh_action->rsc;
1596 }
1597
1598 if ((lh_action == NULL && lh_rsc == NULL)
1599 || (rh_action == NULL && rh_rsc == NULL)) {
1600 crm_err("Invalid ordering (bug?)");
1601 free(lh_action_task);
1602 free(rh_action_task);
1603 return -1;
1604 }
1605
1606 order = calloc(1, sizeof(pe__ordering_t));
1607
1608 crm_trace("Creating[%d] %s %s %s - %s %s %s", data_set->order_id,
1609 lh_rsc?lh_rsc->id:"NA", lh_action_task?lh_action_task:"NA", lh_action?lh_action->uuid:"NA",
1610 rh_rsc?rh_rsc->id:"NA", rh_action_task?rh_action_task:"NA", rh_action?rh_action->uuid:"NA");
1611
1612
1613
1614 order->id = data_set->order_id++;
1615 order->type = type;
1616 order->lh_rsc = lh_rsc;
1617 order->rh_rsc = rh_rsc;
1618 order->lh_action = lh_action;
1619 order->rh_action = rh_action;
1620 order->lh_action_task = lh_action_task;
1621 order->rh_action_task = rh_action_task;
1622
1623 if (order->lh_action_task == NULL && lh_action) {
1624 order->lh_action_task = strdup(lh_action->uuid);
1625 }
1626
1627 if (order->rh_action_task == NULL && rh_action) {
1628 order->rh_action_task = strdup(rh_action->uuid);
1629 }
1630
1631 if (order->lh_rsc == NULL && lh_action) {
1632 order->lh_rsc = lh_action->rsc;
1633 }
1634
1635 if (order->rh_rsc == NULL && rh_action) {
1636 order->rh_rsc = rh_action->rsc;
1637 }
1638
1639 data_set->ordering_constraints = g_list_prepend(data_set->ordering_constraints, order);
1640 handle_migration_ordering(order, data_set);
1641
1642 return order->id;
1643 }
1644
1645 enum pe_ordering
1646 get_asymmetrical_flags(enum pe_order_kind kind)
1647 {
1648 enum pe_ordering flags = pe_order_optional;
1649
1650 if (kind == pe_order_kind_mandatory) {
1651 pe__set_order_flags(flags, pe_order_asymmetrical);
1652 } else if (kind == pe_order_kind_serialize) {
1653 pe__set_order_flags(flags, pe_order_serialize_only);
1654 }
1655 return flags;
1656 }
1657
1658 enum pe_ordering
1659 get_flags(const char *id, enum pe_order_kind kind,
1660 const char *action_first, const char *action_then, gboolean invert)
1661 {
1662 enum pe_ordering flags = pe_order_optional;
1663
1664 if (invert && kind == pe_order_kind_mandatory) {
1665 crm_trace("Upgrade %s: implies left", id);
1666 pe__set_order_flags(flags, pe_order_implies_first);
1667
1668 } else if (kind == pe_order_kind_mandatory) {
1669 crm_trace("Upgrade %s: implies right", id);
1670 pe__set_order_flags(flags, pe_order_implies_then);
1671 if (pcmk__strcase_any_of(action_first, RSC_START, RSC_PROMOTE, NULL)) {
1672 crm_trace("Upgrade %s: runnable", id);
1673 pe__set_order_flags(flags, pe_order_runnable_left);
1674 }
1675
1676 } else if (kind == pe_order_kind_serialize) {
1677 pe__set_order_flags(flags, pe_order_serialize_only);
1678 }
1679
1680 return flags;
1681 }
1682
1683 static gboolean
1684 unpack_order_set(xmlNode * set, enum pe_order_kind parent_kind, pe_resource_t ** rsc,
1685 pe_action_t ** begin, pe_action_t ** end, pe_action_t ** inv_begin,
1686 pe_action_t ** inv_end, const char *parent_symmetrical_s,
1687 pe_working_set_t * data_set)
1688 {
1689 xmlNode *xml_rsc = NULL;
1690 GList *set_iter = NULL;
1691 GList *resources = NULL;
1692
1693 pe_resource_t *last = NULL;
1694 pe_resource_t *resource = NULL;
1695
1696 int local_kind = parent_kind;
1697 gboolean sequential = FALSE;
1698 enum pe_ordering flags = pe_order_optional;
1699 gboolean symmetrical = TRUE;
1700
1701 char *key = NULL;
1702 const char *id = ID(set);
1703 const char *action = crm_element_value(set, "action");
1704 const char *sequential_s = crm_element_value(set, "sequential");
1705 const char *kind_s = crm_element_value(set, XML_ORDER_ATTR_KIND);
1706
1707
1708
1709
1710
1711
1712
1713 if (action == NULL) {
1714 action = RSC_START;
1715 }
1716
1717 if (kind_s) {
1718 local_kind = get_ordering_type(set);
1719 }
1720 if (sequential_s == NULL) {
1721 sequential_s = "1";
1722 }
1723
1724 sequential = crm_is_true(sequential_s);
1725
1726 symmetrical = order_is_symmetrical(set, parent_kind, parent_symmetrical_s);
1727 if (symmetrical) {
1728 flags = get_flags(id, local_kind, action, action, FALSE);
1729 } else {
1730 flags = get_asymmetrical_flags(local_kind);
1731 }
1732
1733 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
1734 xml_rsc = pcmk__xe_next(xml_rsc)) {
1735
1736 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1737 EXPAND_CONSTRAINT_IDREF(id, resource, ID(xml_rsc));
1738 resources = g_list_append(resources, resource);
1739 }
1740 }
1741
1742 if (pcmk__list_of_1(resources)) {
1743 crm_trace("Single set: %s", id);
1744 *rsc = resource;
1745 *end = NULL;
1746 *begin = NULL;
1747 *inv_end = NULL;
1748 *inv_begin = NULL;
1749 goto done;
1750 }
1751
1752
1753
1754
1755
1756
1757
1758 *rsc = NULL;
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768 set_iter = resources;
1769 while (set_iter != NULL) {
1770 resource = (pe_resource_t *) set_iter->data;
1771 set_iter = set_iter->next;
1772
1773 key = pcmk__op_key(resource->id, action, 0);
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783 if (local_kind == pe_order_kind_serialize) {
1784
1785
1786 GList *gIter = NULL;
1787
1788 for (gIter = set_iter; gIter != NULL; gIter = gIter->next) {
1789 pe_resource_t *then_rsc = (pe_resource_t *) gIter->data;
1790 char *then_key = pcmk__op_key(then_rsc->id, action, 0);
1791
1792 custom_action_order(resource, strdup(key), NULL, then_rsc, then_key, NULL,
1793 flags, data_set);
1794 }
1795
1796 } else if (sequential) {
1797 if (last != NULL) {
1798 new_rsc_order(last, action, resource, action, flags, data_set);
1799 }
1800 last = resource;
1801 }
1802 free(key);
1803 }
1804
1805 if (symmetrical == FALSE) {
1806 goto done;
1807 }
1808
1809 last = NULL;
1810 action = invert_action(action);
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825 flags = get_flags(id, local_kind, action, action, TRUE);
1826
1827 set_iter = resources;
1828 while (set_iter != NULL) {
1829 resource = (pe_resource_t *) set_iter->data;
1830 set_iter = set_iter->next;
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842 if (sequential) {
1843 if (last != NULL) {
1844 new_rsc_order(resource, action, last, action, flags, data_set);
1845 }
1846 last = resource;
1847 }
1848 }
1849
1850 done:
1851 g_list_free(resources);
1852 return TRUE;
1853 }
1854
1855 static gboolean
1856 order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kind kind,
1857 pe_working_set_t * data_set, gboolean invert, gboolean symmetrical)
1858 {
1859
1860 xmlNode *xml_rsc = NULL;
1861 xmlNode *xml_rsc_2 = NULL;
1862
1863 pe_resource_t *rsc_1 = NULL;
1864 pe_resource_t *rsc_2 = NULL;
1865
1866 const char *action_1 = crm_element_value(set1, "action");
1867 const char *action_2 = crm_element_value(set2, "action");
1868
1869 const char *sequential_1 = crm_element_value(set1, "sequential");
1870 const char *sequential_2 = crm_element_value(set2, "sequential");
1871
1872 const char *require_all_s = crm_element_value(set1, "require-all");
1873 gboolean require_all = require_all_s ? crm_is_true(require_all_s) : TRUE;
1874
1875 enum pe_ordering flags = pe_order_none;
1876
1877 if (action_1 == NULL) {
1878 action_1 = RSC_START;
1879 };
1880
1881 if (action_2 == NULL) {
1882 action_2 = RSC_START;
1883 };
1884
1885 if (invert) {
1886 action_1 = invert_action(action_1);
1887 action_2 = invert_action(action_2);
1888 }
1889
1890 if(pcmk__str_eq(RSC_STOP, action_1, pcmk__str_casei) || pcmk__str_eq(RSC_DEMOTE, action_1, pcmk__str_casei)) {
1891
1892
1893
1894
1895 require_all = TRUE;
1896 }
1897
1898 if (symmetrical == FALSE) {
1899 flags = get_asymmetrical_flags(kind);
1900 } else {
1901 flags = get_flags(id, kind, action_2, action_1, invert);
1902 }
1903
1904
1905 if (!require_all) {
1906 char *task = crm_strdup_printf(CRM_OP_RELAXED_SET ":%s", ID(set1));
1907 pe_action_t *unordered_action = get_pseudo_op(task, data_set);
1908
1909 free(task);
1910 pe__set_action_flags(unordered_action, pe_action_requires_any);
1911
1912 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
1913 xml_rsc = pcmk__xe_next(xml_rsc)) {
1914
1915 if (!pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1916 continue;
1917 }
1918
1919 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
1920
1921
1922
1923 custom_action_order(rsc_1, pcmk__op_key(rsc_1->id, action_1, 0),
1924 NULL, NULL, NULL, unordered_action,
1925 pe_order_one_or_more|pe_order_implies_then_printed,
1926 data_set);
1927 }
1928 for (xml_rsc_2 = pcmk__xe_first_child(set2); xml_rsc_2 != NULL;
1929 xml_rsc_2 = pcmk__xe_next(xml_rsc_2)) {
1930
1931 if (!pcmk__str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1932 continue;
1933 }
1934
1935 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
1936
1937
1938
1939 custom_action_order(NULL, NULL, unordered_action,
1940 rsc_2, pcmk__op_key(rsc_2->id, action_2, 0),
1941 NULL, flags|pe_order_runnable_left, data_set);
1942 }
1943
1944 return TRUE;
1945 }
1946
1947 if (crm_is_true(sequential_1)) {
1948 if (invert == FALSE) {
1949
1950 const char *rid = NULL;
1951
1952 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
1953 xml_rsc = pcmk__xe_next(xml_rsc)) {
1954
1955 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1956 rid = ID(xml_rsc);
1957 }
1958 }
1959 EXPAND_CONSTRAINT_IDREF(id, rsc_1, rid);
1960
1961 } else {
1962
1963 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
1964 xml_rsc = pcmk__xe_next(xml_rsc)) {
1965
1966 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1967 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
1968 break;
1969 }
1970 }
1971 }
1972 }
1973
1974 if (crm_is_true(sequential_2)) {
1975 if (invert == FALSE) {
1976
1977 for (xml_rsc = pcmk__xe_first_child(set2); xml_rsc != NULL;
1978 xml_rsc = pcmk__xe_next(xml_rsc)) {
1979
1980 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1981 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
1982 break;
1983 }
1984 }
1985
1986 } else {
1987
1988 const char *rid = NULL;
1989
1990 for (xml_rsc = pcmk__xe_first_child(set2); xml_rsc != NULL;
1991 xml_rsc = pcmk__xe_next(xml_rsc)) {
1992
1993 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
1994 rid = ID(xml_rsc);
1995 }
1996 }
1997 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
1998 }
1999 }
2000
2001 if (rsc_1 != NULL && rsc_2 != NULL) {
2002 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
2003
2004 } else if (rsc_1 != NULL) {
2005 for (xml_rsc = pcmk__xe_first_child(set2); xml_rsc != NULL;
2006 xml_rsc = pcmk__xe_next(xml_rsc)) {
2007
2008 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2009 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
2010 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
2011 }
2012 }
2013
2014 } else if (rsc_2 != NULL) {
2015 xmlNode *xml_rsc = NULL;
2016
2017 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
2018 xml_rsc = pcmk__xe_next(xml_rsc)) {
2019
2020 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2021 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
2022 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
2023 }
2024 }
2025
2026 } else {
2027 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
2028 xml_rsc = pcmk__xe_next(xml_rsc)) {
2029
2030 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2031 xmlNode *xml_rsc_2 = NULL;
2032
2033 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
2034
2035 for (xml_rsc_2 = pcmk__xe_first_child(set2);
2036 xml_rsc_2 != NULL;
2037 xml_rsc_2 = pcmk__xe_next(xml_rsc_2)) {
2038
2039 if (pcmk__str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2040 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
2041 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
2042 }
2043 }
2044 }
2045 }
2046 }
2047
2048 return TRUE;
2049 }
2050
2051 static gboolean
2052 unpack_order_tags(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * data_set)
2053 {
2054 const char *id = NULL;
2055 const char *id_first = NULL;
2056 const char *id_then = NULL;
2057 const char *action_first = NULL;
2058 const char *action_then = NULL;
2059
2060 pe_resource_t *rsc_first = NULL;
2061 pe_resource_t *rsc_then = NULL;
2062 pe_tag_t *tag_first = NULL;
2063 pe_tag_t *tag_then = NULL;
2064
2065 xmlNode *new_xml = NULL;
2066 xmlNode *rsc_set_first = NULL;
2067 xmlNode *rsc_set_then = NULL;
2068 gboolean any_sets = FALSE;
2069
2070 *expanded_xml = NULL;
2071
2072 CRM_CHECK(xml_obj != NULL, return FALSE);
2073
2074 id = ID(xml_obj);
2075 if (id == NULL) {
2076 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
2077 crm_element_name(xml_obj));
2078 return FALSE;
2079 }
2080
2081
2082 expand_tags_in_sets(xml_obj, &new_xml, data_set);
2083 if (new_xml) {
2084
2085 crm_log_xml_trace(new_xml, "Expanded rsc_order...");
2086 *expanded_xml = new_xml;
2087 return TRUE;
2088 }
2089
2090 id_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST);
2091 id_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN);
2092 if (id_first == NULL || id_then == NULL) {
2093 return TRUE;
2094 }
2095
2096 if (valid_resource_or_tag(data_set, id_first, &rsc_first, &tag_first) == FALSE) {
2097 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
2098 "valid resource or tag", id, id_first);
2099 return FALSE;
2100 }
2101
2102 if (valid_resource_or_tag(data_set, id_then, &rsc_then, &tag_then) == FALSE) {
2103 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
2104 "valid resource or tag", id, id_then);
2105 return FALSE;
2106 }
2107
2108 if (rsc_first && rsc_then) {
2109
2110 return TRUE;
2111 }
2112
2113 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
2114 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
2115
2116 new_xml = copy_xml(xml_obj);
2117
2118
2119 if (tag_to_set(new_xml, &rsc_set_first, XML_ORDER_ATTR_FIRST, TRUE, data_set) == FALSE) {
2120 free_xml(new_xml);
2121 return FALSE;
2122 }
2123
2124 if (rsc_set_first) {
2125 if (action_first) {
2126
2127
2128 crm_xml_add(rsc_set_first, "action", action_first);
2129 xml_remove_prop(new_xml, XML_ORDER_ATTR_FIRST_ACTION);
2130 }
2131 any_sets = TRUE;
2132 }
2133
2134
2135 if (tag_to_set(new_xml, &rsc_set_then, XML_ORDER_ATTR_THEN, TRUE, data_set) == FALSE) {
2136 free_xml(new_xml);
2137 return FALSE;
2138 }
2139
2140 if (rsc_set_then) {
2141 if (action_then) {
2142
2143
2144 crm_xml_add(rsc_set_then, "action", action_then);
2145 xml_remove_prop(new_xml, XML_ORDER_ATTR_THEN_ACTION);
2146 }
2147 any_sets = TRUE;
2148 }
2149
2150 if (any_sets) {
2151 crm_log_xml_trace(new_xml, "Expanded rsc_order...");
2152 *expanded_xml = new_xml;
2153 } else {
2154 free_xml(new_xml);
2155 }
2156
2157 return TRUE;
2158 }
2159
2160 gboolean
2161 unpack_rsc_order(xmlNode * xml_obj, pe_working_set_t * data_set)
2162 {
2163 gboolean any_sets = FALSE;
2164
2165 pe_resource_t *rsc = NULL;
2166
2167
2168
2169
2170
2171 pe_action_t *set_end = NULL;
2172 pe_action_t *set_begin = NULL;
2173
2174 pe_action_t *set_inv_end = NULL;
2175 pe_action_t *set_inv_begin = NULL;
2176
2177 xmlNode *set = NULL;
2178 xmlNode *last = NULL;
2179
2180 xmlNode *orig_xml = NULL;
2181 xmlNode *expanded_xml = NULL;
2182
2183
2184
2185
2186
2187
2188
2189
2190 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
2191 const char *invert = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL);
2192 enum pe_order_kind kind = get_ordering_type(xml_obj);
2193
2194 gboolean invert_bool = order_is_symmetrical(xml_obj, kind, NULL);
2195 gboolean rc = TRUE;
2196
2197 rc = unpack_order_tags(xml_obj, &expanded_xml, data_set);
2198 if (expanded_xml) {
2199 orig_xml = xml_obj;
2200 xml_obj = expanded_xml;
2201
2202 } else if (rc == FALSE) {
2203 return FALSE;
2204 }
2205
2206 for (set = pcmk__xe_first_child(xml_obj); set != NULL;
2207 set = pcmk__xe_next(set)) {
2208
2209 if (pcmk__str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, pcmk__str_none)) {
2210 any_sets = TRUE;
2211 set = expand_idref(set, data_set->input);
2212 if (unpack_order_set(set, kind, &rsc, &set_begin, &set_end,
2213 &set_inv_begin, &set_inv_end, invert, data_set) == FALSE) {
2214 return FALSE;
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252 } else if (
2253 last) {
2254 if (order_rsc_sets(id, last, set, kind, data_set, FALSE, invert_bool) == FALSE) {
2255 return FALSE;
2256 }
2257
2258 if (invert_bool
2259 && order_rsc_sets(id, set, last, kind, data_set, TRUE, invert_bool) == FALSE) {
2260 return FALSE;
2261 }
2262
2263 }
2264 last = set;
2265
2266
2267
2268
2269
2270
2271
2272 }
2273 }
2274
2275 if (expanded_xml) {
2276 free_xml(expanded_xml);
2277 xml_obj = orig_xml;
2278 }
2279
2280 if (any_sets == FALSE) {
2281 return unpack_simple_rsc_order(xml_obj, data_set);
2282 }
2283
2284 return TRUE;
2285 }
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298 static bool
2299 unpack_influence(const char *coloc_id, const pe_resource_t *rsc,
2300 const char *influence_s)
2301 {
2302 if (influence_s != NULL) {
2303 int influence_i = 0;
2304
2305 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
2306 pcmk__config_err("Constraint '%s' has invalid value for "
2307 XML_COLOC_ATTR_INFLUENCE " (using default)",
2308 coloc_id);
2309 } else {
2310 return (influence_i == TRUE);
2311 }
2312 }
2313 return pcmk_is_set(rsc->flags, pe_rsc_critical);
2314 }
2315
2316 static gboolean
2317 unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
2318 const char *influence_s, pe_working_set_t *data_set)
2319 {
2320 xmlNode *xml_rsc = NULL;
2321 pe_resource_t *with = NULL;
2322 pe_resource_t *resource = NULL;
2323 const char *set_id = ID(set);
2324 const char *role = crm_element_value(set, "role");
2325 const char *sequential = crm_element_value(set, "sequential");
2326 const char *ordering = crm_element_value(set, "ordering");
2327 int local_score = score;
2328
2329 const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE);
2330
2331 if (score_s) {
2332 local_score = char2score(score_s);
2333 }
2334 if (local_score == 0) {
2335 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
2336 coloc_id, set_id);
2337 return TRUE;
2338 }
2339
2340 if(ordering == NULL) {
2341 ordering = "group";
2342 }
2343
2344 if (sequential != NULL && crm_is_true(sequential) == FALSE) {
2345 return TRUE;
2346
2347 } else if ((local_score > 0)
2348 && pcmk__str_eq(ordering, "group", pcmk__str_casei)) {
2349 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
2350 xml_rsc = pcmk__xe_next(xml_rsc)) {
2351
2352 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2353 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
2354 if (with != NULL) {
2355 pe_rsc_trace(resource, "Colocating %s with %s", resource->id, with->id);
2356 pcmk__new_colocation(set_id, NULL, local_score, resource,
2357 with, role, role,
2358 unpack_influence(coloc_id, resource,
2359 influence_s),
2360 data_set);
2361 }
2362
2363 with = resource;
2364 }
2365 }
2366 } else if (local_score > 0) {
2367 pe_resource_t *last = NULL;
2368 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
2369 xml_rsc = pcmk__xe_next(xml_rsc)) {
2370
2371 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2372 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
2373 if (last != NULL) {
2374 pe_rsc_trace(resource, "Colocating %s with %s", last->id, resource->id);
2375 pcmk__new_colocation(set_id, NULL, local_score, last,
2376 resource, role, role,
2377 unpack_influence(coloc_id, last,
2378 influence_s),
2379 data_set);
2380 }
2381
2382 last = resource;
2383 }
2384 }
2385
2386 } else {
2387
2388
2389
2390
2391
2392 for (xml_rsc = pcmk__xe_first_child(set); xml_rsc != NULL;
2393 xml_rsc = pcmk__xe_next(xml_rsc)) {
2394
2395 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2396 xmlNode *xml_rsc_with = NULL;
2397 bool influence = true;
2398
2399 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
2400 influence = unpack_influence(coloc_id, resource, influence_s);
2401
2402 for (xml_rsc_with = pcmk__xe_first_child(set);
2403 xml_rsc_with != NULL;
2404 xml_rsc_with = pcmk__xe_next(xml_rsc_with)) {
2405
2406 if (pcmk__str_eq((const char *)xml_rsc_with->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2407 if (pcmk__str_eq(resource->id, ID(xml_rsc_with), pcmk__str_casei)) {
2408 break;
2409 }
2410 EXPAND_CONSTRAINT_IDREF(set_id, with, ID(xml_rsc_with));
2411 pe_rsc_trace(resource, "Anti-Colocating %s with %s", resource->id,
2412 with->id);
2413 pcmk__new_colocation(set_id, NULL, local_score,
2414 resource, with, role, role,
2415 influence, data_set);
2416 }
2417 }
2418 }
2419 }
2420 }
2421
2422 return TRUE;
2423 }
2424
2425 static gboolean
2426 colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
2427 const char *influence_s, pe_working_set_t *data_set)
2428 {
2429 xmlNode *xml_rsc = NULL;
2430 pe_resource_t *rsc_1 = NULL;
2431 pe_resource_t *rsc_2 = NULL;
2432
2433 const char *role_1 = crm_element_value(set1, "role");
2434 const char *role_2 = crm_element_value(set2, "role");
2435
2436 const char *sequential_1 = crm_element_value(set1, "sequential");
2437 const char *sequential_2 = crm_element_value(set2, "sequential");
2438
2439 if (score == 0) {
2440 crm_trace("Ignoring colocation '%s' between sets because score is 0",
2441 id);
2442 return TRUE;
2443 }
2444 if (sequential_1 == NULL || crm_is_true(sequential_1)) {
2445
2446 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
2447 xml_rsc = pcmk__xe_next(xml_rsc)) {
2448
2449 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2450 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
2451 break;
2452 }
2453 }
2454 }
2455
2456 if (sequential_2 == NULL || crm_is_true(sequential_2)) {
2457
2458 const char *rid = NULL;
2459
2460 for (xml_rsc = pcmk__xe_first_child(set2); xml_rsc != NULL;
2461 xml_rsc = pcmk__xe_next(xml_rsc)) {
2462
2463 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2464 rid = ID(xml_rsc);
2465 }
2466 }
2467 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
2468 }
2469
2470 if (rsc_1 != NULL && rsc_2 != NULL) {
2471 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
2472 unpack_influence(id, rsc_1, influence_s),
2473 data_set);
2474
2475 } else if (rsc_1 != NULL) {
2476 bool influence = unpack_influence(id, rsc_1, influence_s);
2477
2478 for (xml_rsc = pcmk__xe_first_child(set2); xml_rsc != NULL;
2479 xml_rsc = pcmk__xe_next(xml_rsc)) {
2480
2481 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2482 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
2483 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
2484 role_2, influence, data_set);
2485 }
2486 }
2487
2488 } else if (rsc_2 != NULL) {
2489 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
2490 xml_rsc = pcmk__xe_next(xml_rsc)) {
2491
2492 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2493 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
2494 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
2495 role_2,
2496 unpack_influence(id, rsc_1, influence_s),
2497 data_set);
2498 }
2499 }
2500
2501 } else {
2502 for (xml_rsc = pcmk__xe_first_child(set1); xml_rsc != NULL;
2503 xml_rsc = pcmk__xe_next(xml_rsc)) {
2504
2505 if (pcmk__str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2506 xmlNode *xml_rsc_2 = NULL;
2507 bool influence = true;
2508
2509 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
2510 influence = unpack_influence(id, rsc_1, influence_s);
2511
2512 for (xml_rsc_2 = pcmk__xe_first_child(set2);
2513 xml_rsc_2 != NULL;
2514 xml_rsc_2 = pcmk__xe_next(xml_rsc_2)) {
2515
2516 if (pcmk__str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, pcmk__str_none)) {
2517 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
2518 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
2519 role_1, role_2, influence,
2520 data_set);
2521 }
2522 }
2523 }
2524 }
2525 }
2526
2527 return TRUE;
2528 }
2529
2530 static void
2531 unpack_simple_colocation(xmlNode *xml_obj, const char *id,
2532 const char *influence_s, pe_working_set_t *data_set)
2533 {
2534 int score_i = 0;
2535
2536 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
2537 const char *id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
2538 const char *id_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
2539 const char *state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
2540 const char *state_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
2541 const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR);
2542 const char *symmetrical = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL);
2543
2544
2545 const char *instance_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_INSTANCE);
2546 const char *instance_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_INSTANCE);
2547
2548 pe_resource_t *rsc_lh = pe_find_constraint_resource(data_set->resources, id_lh);
2549 pe_resource_t *rsc_rh = pe_find_constraint_resource(data_set->resources, id_rh);
2550
2551 if (rsc_lh == NULL) {
2552 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2553 "does not exist", id, id_lh);
2554 return;
2555
2556 } else if (rsc_rh == NULL) {
2557 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2558 "does not exist", id, id_rh);
2559 return;
2560
2561 } else if (instance_lh && pe_rsc_is_clone(rsc_lh) == FALSE) {
2562 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2563 "is not a clone but instance '%s' was requested",
2564 id, id_lh, instance_lh);
2565 return;
2566
2567 } else if (instance_rh && pe_rsc_is_clone(rsc_rh) == FALSE) {
2568 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2569 "is not a clone but instance '%s' was requested",
2570 id, id_rh, instance_rh);
2571 return;
2572 }
2573
2574 if (instance_lh) {
2575 rsc_lh = find_clone_instance(rsc_lh, instance_lh, data_set);
2576 if (rsc_lh == NULL) {
2577 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
2578 "does not have an instance '%s'",
2579 id, id_lh, instance_lh);
2580 return;
2581 }
2582 }
2583
2584 if (instance_rh) {
2585 rsc_rh = find_clone_instance(rsc_rh, instance_rh, data_set);
2586 if (rsc_rh == NULL) {
2587 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
2588 "does not have an instance '%s'",
2589 "'%s'", id, id_rh, instance_rh);
2590 return;
2591 }
2592 }
2593
2594 if (crm_is_true(symmetrical)) {
2595 pcmk__config_warn("The colocation constraint '"
2596 XML_CONS_ATTR_SYMMETRICAL
2597 "' attribute has been removed");
2598 }
2599
2600 if (score) {
2601 score_i = char2score(score);
2602 }
2603
2604 pcmk__new_colocation(id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh,
2605 unpack_influence(id, rsc_lh, influence_s), data_set);
2606 }
2607
2608 static gboolean
2609 unpack_colocation_tags(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * data_set)
2610 {
2611 const char *id = NULL;
2612 const char *id_lh = NULL;
2613 const char *id_rh = NULL;
2614 const char *state_lh = NULL;
2615 const char *state_rh = NULL;
2616
2617 pe_resource_t *rsc_lh = NULL;
2618 pe_resource_t *rsc_rh = NULL;
2619
2620 pe_tag_t *tag_lh = NULL;
2621 pe_tag_t *tag_rh = NULL;
2622
2623 xmlNode *new_xml = NULL;
2624 xmlNode *rsc_set_lh = NULL;
2625 xmlNode *rsc_set_rh = NULL;
2626 gboolean any_sets = FALSE;
2627
2628 *expanded_xml = NULL;
2629
2630 CRM_CHECK(xml_obj != NULL, return FALSE);
2631
2632 id = ID(xml_obj);
2633 if (id == NULL) {
2634 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
2635 crm_element_name(xml_obj));
2636 return FALSE;
2637 }
2638
2639
2640 expand_tags_in_sets(xml_obj, &new_xml, data_set);
2641 if (new_xml) {
2642
2643 crm_log_xml_trace(new_xml, "Expanded rsc_colocation...");
2644 *expanded_xml = new_xml;
2645 return TRUE;
2646 }
2647
2648 id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
2649 id_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
2650 if (id_lh == NULL || id_rh == NULL) {
2651 return TRUE;
2652 }
2653
2654 if (valid_resource_or_tag(data_set, id_lh, &rsc_lh, &tag_lh) == FALSE) {
2655 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
2656 "valid resource or tag", id, id_lh);
2657 return FALSE;
2658 }
2659
2660 if (valid_resource_or_tag(data_set, id_rh, &rsc_rh, &tag_rh) == FALSE) {
2661 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
2662 "valid resource or tag", id, id_rh);
2663 return FALSE;
2664 }
2665
2666 if (rsc_lh && rsc_rh) {
2667
2668 return TRUE;
2669 }
2670
2671 if (tag_lh && tag_rh) {
2672
2673 pcmk__config_err("Ignoring constraint '%s' because two templates or "
2674 "tags cannot be colocated", id);
2675 return FALSE;
2676 }
2677
2678 state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
2679 state_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
2680
2681 new_xml = copy_xml(xml_obj);
2682
2683
2684 if (tag_to_set(new_xml, &rsc_set_lh, XML_COLOC_ATTR_SOURCE, TRUE, data_set) == FALSE) {
2685 free_xml(new_xml);
2686 return FALSE;
2687 }
2688
2689 if (rsc_set_lh) {
2690 if (state_lh) {
2691
2692
2693 crm_xml_add(rsc_set_lh, "role", state_lh);
2694 xml_remove_prop(new_xml, XML_COLOC_ATTR_SOURCE_ROLE);
2695 }
2696 any_sets = TRUE;
2697 }
2698
2699
2700 if (tag_to_set(new_xml, &rsc_set_rh, XML_COLOC_ATTR_TARGET, TRUE, data_set) == FALSE) {
2701 free_xml(new_xml);
2702 return FALSE;
2703 }
2704
2705 if (rsc_set_rh) {
2706 if (state_rh) {
2707
2708
2709 crm_xml_add(rsc_set_rh, "role", state_rh);
2710 xml_remove_prop(new_xml, XML_COLOC_ATTR_TARGET_ROLE);
2711 }
2712 any_sets = TRUE;
2713 }
2714
2715 if (any_sets) {
2716 crm_log_xml_trace(new_xml, "Expanded rsc_colocation...");
2717 *expanded_xml = new_xml;
2718 } else {
2719 free_xml(new_xml);
2720 }
2721
2722 return TRUE;
2723 }
2724
2725 static void
2726 unpack_rsc_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
2727 {
2728 int score_i = 0;
2729 xmlNode *set = NULL;
2730 xmlNode *last = NULL;
2731 gboolean any_sets = FALSE;
2732
2733 xmlNode *orig_xml = NULL;
2734 xmlNode *expanded_xml = NULL;
2735
2736 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
2737 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
2738 const char *influence_s = crm_element_value(xml_obj,
2739 XML_COLOC_ATTR_INFLUENCE);
2740
2741 if (score) {
2742 score_i = char2score(score);
2743 }
2744
2745 if (!unpack_colocation_tags(xml_obj, &expanded_xml, data_set)) {
2746 return;
2747 }
2748 if (expanded_xml) {
2749 orig_xml = xml_obj;
2750 xml_obj = expanded_xml;
2751 }
2752
2753 for (set = pcmk__xe_first_child(xml_obj); set != NULL;
2754 set = pcmk__xe_next(set)) {
2755
2756 if (pcmk__str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, pcmk__str_none)) {
2757 any_sets = TRUE;
2758 set = expand_idref(set, data_set->input);
2759 if (!unpack_colocation_set(set, score_i, id, influence_s,
2760 data_set)) {
2761 return;
2762 }
2763 if ((last != NULL) && !colocate_rsc_sets(id, last, set, score_i,
2764 influence_s, data_set)) {
2765 return;
2766 }
2767 last = set;
2768 }
2769 }
2770
2771 if (expanded_xml) {
2772 free_xml(expanded_xml);
2773 xml_obj = orig_xml;
2774 }
2775
2776 if (!any_sets) {
2777 unpack_simple_colocation(xml_obj, id, influence_s, data_set);
2778 }
2779 }
2780
2781 gboolean
2782 rsc_ticket_new(const char *id, pe_resource_t * rsc_lh, pe_ticket_t * ticket,
2783 const char *state_lh, const char *loss_policy, pe_working_set_t * data_set)
2784 {
2785 rsc_ticket_t *new_rsc_ticket = NULL;
2786
2787 if (rsc_lh == NULL) {
2788 pcmk__config_err("Ignoring ticket '%s' because resource "
2789 "does not exist", id);
2790 return FALSE;
2791 }
2792
2793 new_rsc_ticket = calloc(1, sizeof(rsc_ticket_t));
2794 if (new_rsc_ticket == NULL) {
2795 return FALSE;
2796 }
2797
2798 if (pcmk__str_eq(state_lh, RSC_ROLE_STARTED_S, pcmk__str_null_matches | pcmk__str_casei)) {
2799 state_lh = RSC_ROLE_UNKNOWN_S;
2800 }
2801
2802 new_rsc_ticket->id = id;
2803 new_rsc_ticket->ticket = ticket;
2804 new_rsc_ticket->rsc_lh = rsc_lh;
2805 new_rsc_ticket->role_lh = text2role(state_lh);
2806
2807 if (pcmk__str_eq(loss_policy, "fence", pcmk__str_casei)) {
2808 if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
2809 new_rsc_ticket->loss_policy = loss_ticket_fence;
2810 } else {
2811 pcmk__config_err("Resetting '" XML_TICKET_ATTR_LOSS_POLICY
2812 "' for ticket '%s' to 'stop' "
2813 "because fencing is not configured", ticket->id);
2814 loss_policy = "stop";
2815 }
2816 }
2817
2818 if (new_rsc_ticket->loss_policy == loss_ticket_fence) {
2819 crm_debug("On loss of ticket '%s': Fence the nodes running %s (%s)",
2820 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2821 role2text(new_rsc_ticket->role_lh));
2822
2823 } else if (pcmk__str_eq(loss_policy, "freeze", pcmk__str_casei)) {
2824 crm_debug("On loss of ticket '%s': Freeze %s (%s)",
2825 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2826 role2text(new_rsc_ticket->role_lh));
2827 new_rsc_ticket->loss_policy = loss_ticket_freeze;
2828
2829 } else if (pcmk__str_eq(loss_policy, "demote", pcmk__str_casei)) {
2830 crm_debug("On loss of ticket '%s': Demote %s (%s)",
2831 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2832 role2text(new_rsc_ticket->role_lh));
2833 new_rsc_ticket->loss_policy = loss_ticket_demote;
2834
2835 } else if (pcmk__str_eq(loss_policy, "stop", pcmk__str_casei)) {
2836 crm_debug("On loss of ticket '%s': Stop %s (%s)",
2837 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2838 role2text(new_rsc_ticket->role_lh));
2839 new_rsc_ticket->loss_policy = loss_ticket_stop;
2840
2841 } else {
2842 if (new_rsc_ticket->role_lh == RSC_ROLE_PROMOTED) {
2843 crm_debug("On loss of ticket '%s': Default to demote %s (%s)",
2844 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2845 role2text(new_rsc_ticket->role_lh));
2846 new_rsc_ticket->loss_policy = loss_ticket_demote;
2847
2848 } else {
2849 crm_debug("On loss of ticket '%s': Default to stop %s (%s)",
2850 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
2851 role2text(new_rsc_ticket->role_lh));
2852 new_rsc_ticket->loss_policy = loss_ticket_stop;
2853 }
2854 }
2855
2856 pe_rsc_trace(rsc_lh, "%s (%s) ==> %s", rsc_lh->id, role2text(new_rsc_ticket->role_lh),
2857 ticket->id);
2858
2859 rsc_lh->rsc_tickets = g_list_append(rsc_lh->rsc_tickets, new_rsc_ticket);
2860
2861 data_set->ticket_constraints = g_list_append(data_set->ticket_constraints, new_rsc_ticket);
2862
2863 if (new_rsc_ticket->ticket->granted == FALSE || new_rsc_ticket->ticket->standby) {
2864 rsc_ticket_constraint(rsc_lh, new_rsc_ticket, data_set);
2865 }
2866
2867 return TRUE;
2868 }
2869
2870 static gboolean
2871 unpack_rsc_ticket_set(xmlNode * set, pe_ticket_t * ticket, const char *loss_policy,
2872 pe_working_set_t * data_set)
2873 {
2874 xmlNode *xml_rsc = NULL;
2875 pe_resource_t *resource = NULL;
2876 const char *set_id = NULL;
2877 const char *role = NULL;
2878
2879 CRM_CHECK(set != NULL, return FALSE);
2880 CRM_CHECK(ticket != NULL, return FALSE);
2881
2882 set_id = ID(set);
2883 if (set_id == NULL) {
2884 pcmk__config_err("Ignoring <" XML_CONS_TAG_RSC_SET "> without "
2885 XML_ATTR_ID);
2886 return FALSE;
2887 }
2888
2889 role = crm_element_value(set, "role");
2890
2891 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
2892 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
2893
2894 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
2895 pe_rsc_trace(resource, "Resource '%s' depends on ticket '%s'",
2896 resource->id, ticket->id);
2897 rsc_ticket_new(set_id, resource, ticket, role, loss_policy, data_set);
2898 }
2899
2900 return TRUE;
2901 }
2902
2903 static gboolean
2904 unpack_simple_rsc_ticket(xmlNode * xml_obj, pe_working_set_t * data_set)
2905 {
2906 const char *id = NULL;
2907 const char *ticket_str = crm_element_value(xml_obj, XML_TICKET_ATTR_TICKET);
2908 const char *loss_policy = crm_element_value(xml_obj, XML_TICKET_ATTR_LOSS_POLICY);
2909
2910 pe_ticket_t *ticket = NULL;
2911
2912 const char *id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
2913 const char *state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
2914
2915
2916 const char *instance_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_INSTANCE);
2917
2918 pe_resource_t *rsc_lh = NULL;
2919
2920 CRM_CHECK(xml_obj != NULL, return FALSE);
2921
2922 id = ID(xml_obj);
2923 if (id == NULL) {
2924 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
2925 crm_element_name(xml_obj));
2926 return FALSE;
2927 }
2928
2929 if (ticket_str == NULL) {
2930 pcmk__config_err("Ignoring constraint '%s' without ticket specified",
2931 id);
2932 return FALSE;
2933 } else {
2934 ticket = g_hash_table_lookup(data_set->tickets, ticket_str);
2935 }
2936
2937 if (ticket == NULL) {
2938 pcmk__config_err("Ignoring constraint '%s' because ticket '%s' "
2939 "does not exist", id, ticket_str);
2940 return FALSE;
2941 }
2942
2943 if (id_lh == NULL) {
2944 pcmk__config_err("Ignoring constraint '%s' without resource", id);
2945 return FALSE;
2946 } else {
2947 rsc_lh = pe_find_constraint_resource(data_set->resources, id_lh);
2948 }
2949
2950 if (rsc_lh == NULL) {
2951 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2952 "does not exist", id, id_lh);
2953 return FALSE;
2954
2955 } else if (instance_lh && pe_rsc_is_clone(rsc_lh) == FALSE) {
2956 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
2957 "is not a clone but instance '%s' was requested",
2958 id, id_lh, instance_lh);
2959 return FALSE;
2960 }
2961
2962 if (instance_lh) {
2963 rsc_lh = find_clone_instance(rsc_lh, instance_lh, data_set);
2964 if (rsc_lh == NULL) {
2965 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
2966 "does not have an instance '%s'",
2967 "'%s'", id, id_lh, instance_lh);
2968 return FALSE;
2969 }
2970 }
2971
2972 rsc_ticket_new(id, rsc_lh, ticket, state_lh, loss_policy, data_set);
2973 return TRUE;
2974 }
2975
2976 static gboolean
2977 unpack_rsc_ticket_tags(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * data_set)
2978 {
2979 const char *id = NULL;
2980 const char *id_lh = NULL;
2981 const char *state_lh = NULL;
2982
2983 pe_resource_t *rsc_lh = NULL;
2984 pe_tag_t *tag_lh = NULL;
2985
2986 xmlNode *new_xml = NULL;
2987 xmlNode *rsc_set_lh = NULL;
2988 gboolean any_sets = FALSE;
2989
2990 *expanded_xml = NULL;
2991
2992 CRM_CHECK(xml_obj != NULL, return FALSE);
2993
2994 id = ID(xml_obj);
2995 if (id == NULL) {
2996 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
2997 crm_element_name(xml_obj));
2998 return FALSE;
2999 }
3000
3001
3002 expand_tags_in_sets(xml_obj, &new_xml, data_set);
3003 if (new_xml) {
3004
3005 crm_log_xml_trace(new_xml, "Expanded rsc_ticket...");
3006 *expanded_xml = new_xml;
3007 return TRUE;
3008 }
3009
3010 id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
3011 if (id_lh == NULL) {
3012 return TRUE;
3013 }
3014
3015 if (valid_resource_or_tag(data_set, id_lh, &rsc_lh, &tag_lh) == FALSE) {
3016 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
3017 "valid resource or tag", id, id_lh);
3018 return FALSE;
3019
3020 } else if (rsc_lh) {
3021
3022 return TRUE;
3023 }
3024
3025 state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
3026
3027 new_xml = copy_xml(xml_obj);
3028
3029
3030 if (tag_to_set(new_xml, &rsc_set_lh, XML_COLOC_ATTR_SOURCE, FALSE, data_set) == FALSE) {
3031 free_xml(new_xml);
3032 return FALSE;
3033 }
3034
3035 if (rsc_set_lh) {
3036 if (state_lh) {
3037
3038
3039 crm_xml_add(rsc_set_lh, "role", state_lh);
3040 xml_remove_prop(new_xml, XML_COLOC_ATTR_SOURCE_ROLE);
3041 }
3042 any_sets = TRUE;
3043 }
3044
3045 if (any_sets) {
3046 crm_log_xml_trace(new_xml, "Expanded rsc_ticket...");
3047 *expanded_xml = new_xml;
3048 } else {
3049 free_xml(new_xml);
3050 }
3051
3052 return TRUE;
3053 }
3054
3055 gboolean
3056 unpack_rsc_ticket(xmlNode * xml_obj, pe_working_set_t * data_set)
3057 {
3058 xmlNode *set = NULL;
3059 gboolean any_sets = FALSE;
3060
3061 const char *id = NULL;
3062 const char *ticket_str = crm_element_value(xml_obj, XML_TICKET_ATTR_TICKET);
3063 const char *loss_policy = crm_element_value(xml_obj, XML_TICKET_ATTR_LOSS_POLICY);
3064
3065 pe_ticket_t *ticket = NULL;
3066
3067 xmlNode *orig_xml = NULL;
3068 xmlNode *expanded_xml = NULL;
3069
3070 gboolean rc = TRUE;
3071
3072 CRM_CHECK(xml_obj != NULL, return FALSE);
3073
3074 id = ID(xml_obj);
3075 if (id == NULL) {
3076 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
3077 crm_element_name(xml_obj));
3078 return FALSE;
3079 }
3080
3081 if (data_set->tickets == NULL) {
3082 data_set->tickets = pcmk__strkey_table(free, destroy_ticket);
3083 }
3084
3085 if (ticket_str == NULL) {
3086 pcmk__config_err("Ignoring constraint '%s' without ticket", id);
3087 return FALSE;
3088 } else {
3089 ticket = g_hash_table_lookup(data_set->tickets, ticket_str);
3090 }
3091
3092 if (ticket == NULL) {
3093 ticket = ticket_new(ticket_str, data_set);
3094 if (ticket == NULL) {
3095 return FALSE;
3096 }
3097 }
3098
3099 rc = unpack_rsc_ticket_tags(xml_obj, &expanded_xml, data_set);
3100 if (expanded_xml) {
3101 orig_xml = xml_obj;
3102 xml_obj = expanded_xml;
3103
3104 } else if (rc == FALSE) {
3105 return FALSE;
3106 }
3107
3108 for (set = pcmk__xe_first_child(xml_obj); set != NULL;
3109 set = pcmk__xe_next(set)) {
3110
3111 if (pcmk__str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, pcmk__str_none)) {
3112 any_sets = TRUE;
3113 set = expand_idref(set, data_set->input);
3114 if (unpack_rsc_ticket_set(set, ticket, loss_policy, data_set) == FALSE) {
3115 return FALSE;
3116 }
3117 }
3118 }
3119
3120 if (expanded_xml) {
3121 free_xml(expanded_xml);
3122 xml_obj = orig_xml;
3123 }
3124
3125 if (any_sets == FALSE) {
3126 return unpack_simple_rsc_ticket(xml_obj, data_set);
3127 }
3128
3129 return TRUE;
3130 }