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