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