This source file includes following definitions.
- ticket_role_matches
- constraints_for_ticket
- rsc_ticket_new
- unpack_rsc_ticket_set
- unpack_simple_rsc_ticket
- unpack_rsc_ticket_tags
- pcmk__unpack_rsc_ticket
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <glib.h>
14
15 #include <crm/crm.h>
16 #include <crm/pengine/status.h>
17 #include <pacemaker-internal.h>
18
19 #include "libpacemaker_private.h"
20
21
22
23
24
25
26
27
28
29
30 static bool
31 ticket_role_matches(pe_resource_t *rsc_lh, rsc_ticket_t *rsc_ticket)
32 {
33 if ((rsc_ticket->role_lh == RSC_ROLE_UNKNOWN)
34 || (rsc_ticket->role_lh == rsc_lh->role)) {
35 return true;
36 }
37 pe_rsc_trace(rsc_lh, "LH: Skipping constraint: \"%s\" state filter",
38 role2text(rsc_ticket->role_lh));
39 return false;
40 }
41
42
43
44
45
46
47
48
49 static void
50 constraints_for_ticket(pe_resource_t *rsc_lh, rsc_ticket_t *rsc_ticket,
51 pe_working_set_t *data_set)
52 {
53 GList *gIter = NULL;
54
55 CRM_CHECK((rsc_lh != NULL) && (rsc_ticket != NULL), return);
56
57 if (rsc_ticket->ticket->granted && !rsc_ticket->ticket->standby) {
58 return;
59 }
60
61 if (rsc_lh->children) {
62 pe_rsc_trace(rsc_lh, "Processing ticket dependencies from %s", rsc_lh->id);
63 for (gIter = rsc_lh->children; gIter != NULL; gIter = gIter->next) {
64 constraints_for_ticket((pe_resource_t *) gIter->data, rsc_ticket,
65 data_set);
66 }
67 return;
68 }
69
70 pe_rsc_trace(rsc_lh, "%s: Processing ticket dependency on %s (%s, %s)",
71 rsc_lh->id, rsc_ticket->ticket->id, rsc_ticket->id,
72 role2text(rsc_ticket->role_lh));
73
74 if (!rsc_ticket->ticket->granted && (rsc_lh->running_on != NULL)) {
75
76 switch (rsc_ticket->loss_policy) {
77 case loss_ticket_stop:
78 resource_location(rsc_lh, NULL, -INFINITY, "__loss_of_ticket__",
79 data_set);
80 break;
81
82 case loss_ticket_demote:
83
84 if (rsc_ticket->role_lh != RSC_ROLE_PROMOTED) {
85 resource_location(rsc_lh, NULL, -INFINITY,
86 "__loss_of_ticket__", data_set);
87 }
88 break;
89
90 case loss_ticket_fence:
91 if (!ticket_role_matches(rsc_lh, rsc_ticket)) {
92 return;
93 }
94
95 resource_location(rsc_lh, NULL, -INFINITY, "__loss_of_ticket__",
96 data_set);
97
98 for (gIter = rsc_lh->running_on; gIter != NULL;
99 gIter = gIter->next) {
100 pe_fence_node(data_set, (pe_node_t *) gIter->data,
101 "deadman ticket was lost", FALSE);
102 }
103 break;
104
105 case loss_ticket_freeze:
106 if (!ticket_role_matches(rsc_lh, rsc_ticket)) {
107 return;
108 }
109 if (rsc_lh->running_on != NULL) {
110 pe__clear_resource_flags(rsc_lh, pe_rsc_managed);
111 pe__set_resource_flags(rsc_lh, pe_rsc_block);
112 }
113 break;
114 }
115
116 } else if (!rsc_ticket->ticket->granted) {
117
118 if ((rsc_ticket->role_lh != RSC_ROLE_PROMOTED)
119 || (rsc_ticket->loss_policy == loss_ticket_stop)) {
120 resource_location(rsc_lh, NULL, -INFINITY, "__no_ticket__",
121 data_set);
122 }
123
124 } else if (rsc_ticket->ticket->standby) {
125
126 if ((rsc_ticket->role_lh != RSC_ROLE_PROMOTED)
127 || (rsc_ticket->loss_policy == loss_ticket_stop)) {
128 resource_location(rsc_lh, NULL, -INFINITY, "__ticket_standby__",
129 data_set);
130 }
131 }
132 }
133
134 static void
135 rsc_ticket_new(const char *id, pe_resource_t *rsc_lh, pe_ticket_t *ticket,
136 const char *state_lh, const char *loss_policy,
137 pe_working_set_t *data_set)
138 {
139 rsc_ticket_t *new_rsc_ticket = NULL;
140
141 if (rsc_lh == NULL) {
142 pcmk__config_err("Ignoring ticket '%s' because resource "
143 "does not exist", id);
144 return;
145 }
146
147 new_rsc_ticket = calloc(1, sizeof(rsc_ticket_t));
148 if (new_rsc_ticket == NULL) {
149 return;
150 }
151
152 if (pcmk__str_eq(state_lh, RSC_ROLE_STARTED_S,
153 pcmk__str_null_matches|pcmk__str_casei)) {
154 state_lh = RSC_ROLE_UNKNOWN_S;
155 }
156
157 new_rsc_ticket->id = id;
158 new_rsc_ticket->ticket = ticket;
159 new_rsc_ticket->rsc_lh = rsc_lh;
160 new_rsc_ticket->role_lh = text2role(state_lh);
161
162 if (pcmk__str_eq(loss_policy, "fence", pcmk__str_casei)) {
163 if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
164 new_rsc_ticket->loss_policy = loss_ticket_fence;
165 } else {
166 pcmk__config_err("Resetting '" XML_TICKET_ATTR_LOSS_POLICY
167 "' for ticket '%s' to 'stop' "
168 "because fencing is not configured", ticket->id);
169 loss_policy = "stop";
170 }
171 }
172
173 if (new_rsc_ticket->loss_policy == loss_ticket_fence) {
174 crm_debug("On loss of ticket '%s': Fence the nodes running %s (%s)",
175 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
176 role2text(new_rsc_ticket->role_lh));
177
178 } else if (pcmk__str_eq(loss_policy, "freeze", pcmk__str_casei)) {
179 crm_debug("On loss of ticket '%s': Freeze %s (%s)",
180 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
181 role2text(new_rsc_ticket->role_lh));
182 new_rsc_ticket->loss_policy = loss_ticket_freeze;
183
184 } else if (pcmk__str_eq(loss_policy, "demote", pcmk__str_casei)) {
185 crm_debug("On loss of ticket '%s': Demote %s (%s)",
186 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
187 role2text(new_rsc_ticket->role_lh));
188 new_rsc_ticket->loss_policy = loss_ticket_demote;
189
190 } else if (pcmk__str_eq(loss_policy, "stop", pcmk__str_casei)) {
191 crm_debug("On loss of ticket '%s': Stop %s (%s)",
192 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
193 role2text(new_rsc_ticket->role_lh));
194 new_rsc_ticket->loss_policy = loss_ticket_stop;
195
196 } else {
197 if (new_rsc_ticket->role_lh == RSC_ROLE_PROMOTED) {
198 crm_debug("On loss of ticket '%s': Default to demote %s (%s)",
199 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
200 role2text(new_rsc_ticket->role_lh));
201 new_rsc_ticket->loss_policy = loss_ticket_demote;
202
203 } else {
204 crm_debug("On loss of ticket '%s': Default to stop %s (%s)",
205 new_rsc_ticket->ticket->id, new_rsc_ticket->rsc_lh->id,
206 role2text(new_rsc_ticket->role_lh));
207 new_rsc_ticket->loss_policy = loss_ticket_stop;
208 }
209 }
210
211 pe_rsc_trace(rsc_lh, "%s (%s) ==> %s",
212 rsc_lh->id, role2text(new_rsc_ticket->role_lh), ticket->id);
213
214 rsc_lh->rsc_tickets = g_list_append(rsc_lh->rsc_tickets, new_rsc_ticket);
215
216 data_set->ticket_constraints = g_list_append(data_set->ticket_constraints,
217 new_rsc_ticket);
218
219 if (!(new_rsc_ticket->ticket->granted) || new_rsc_ticket->ticket->standby) {
220 constraints_for_ticket(rsc_lh, new_rsc_ticket, data_set);
221 }
222 }
223
224
225 static int
226 unpack_rsc_ticket_set(xmlNode *set, pe_ticket_t *ticket,
227 const char *loss_policy, pe_working_set_t *data_set)
228 {
229 const char *set_id = NULL;
230 const char *role = NULL;
231
232 CRM_CHECK(set != NULL, return EINVAL);
233 CRM_CHECK(ticket != NULL, return EINVAL);
234
235 set_id = ID(set);
236 if (set_id == NULL) {
237 pcmk__config_err("Ignoring <" XML_CONS_TAG_RSC_SET "> without "
238 XML_ATTR_ID);
239 return pcmk_rc_schema_validation;
240 }
241
242 role = crm_element_value(set, "role");
243
244 for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
245 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
246
247 pe_resource_t *resource = NULL;
248
249 resource = pcmk__find_constraint_resource(data_set->resources,
250 ID(xml_rsc));
251 if (resource == NULL) {
252 pcmk__config_err("%s: No resource found for %s",
253 set_id, ID(xml_rsc));
254 return pcmk_rc_schema_validation;
255 }
256 pe_rsc_trace(resource, "Resource '%s' depends on ticket '%s'",
257 resource->id, ticket->id);
258 rsc_ticket_new(set_id, resource, ticket, role, loss_policy, data_set);
259 }
260
261 return pcmk_rc_ok;
262 }
263
264 static void
265 unpack_simple_rsc_ticket(xmlNode *xml_obj, pe_working_set_t *data_set)
266 {
267 const char *id = NULL;
268 const char *ticket_str = crm_element_value(xml_obj, XML_TICKET_ATTR_TICKET);
269 const char *loss_policy = crm_element_value(xml_obj,
270 XML_TICKET_ATTR_LOSS_POLICY);
271
272 pe_ticket_t *ticket = NULL;
273
274 const char *id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
275 const char *state_lh = crm_element_value(xml_obj,
276 XML_COLOC_ATTR_SOURCE_ROLE);
277
278
279 const char *instance_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_INSTANCE);
280
281 pe_resource_t *rsc_lh = NULL;
282
283 CRM_CHECK(xml_obj != NULL, return);
284
285 id = ID(xml_obj);
286 if (id == NULL) {
287 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
288 crm_element_name(xml_obj));
289 return;
290 }
291
292 if (ticket_str == NULL) {
293 pcmk__config_err("Ignoring constraint '%s' without ticket specified",
294 id);
295 return;
296 } else {
297 ticket = g_hash_table_lookup(data_set->tickets, ticket_str);
298 }
299
300 if (ticket == NULL) {
301 pcmk__config_err("Ignoring constraint '%s' because ticket '%s' "
302 "does not exist", id, ticket_str);
303 return;
304 }
305
306 if (id_lh == NULL) {
307 pcmk__config_err("Ignoring constraint '%s' without resource", id);
308 return;
309 } else {
310 rsc_lh = pcmk__find_constraint_resource(data_set->resources, id_lh);
311 }
312
313 if (rsc_lh == NULL) {
314 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
315 "does not exist", id, id_lh);
316 return;
317
318 } else if ((instance_lh != NULL) && !pe_rsc_is_clone(rsc_lh)) {
319 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
320 "is not a clone but instance '%s' was requested",
321 id, id_lh, instance_lh);
322 return;
323 }
324
325 if (instance_lh != NULL) {
326 rsc_lh = find_clone_instance(rsc_lh, instance_lh, data_set);
327 if (rsc_lh == NULL) {
328 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
329 "does not have an instance '%s'",
330 "'%s'", id, id_lh, instance_lh);
331 return;
332 }
333 }
334
335 rsc_ticket_new(id, rsc_lh, ticket, state_lh, loss_policy, data_set);
336 }
337
338
339 static int
340 unpack_rsc_ticket_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
341 pe_working_set_t *data_set)
342 {
343 const char *id = NULL;
344 const char *id_lh = NULL;
345 const char *state_lh = NULL;
346
347 pe_resource_t *rsc_lh = NULL;
348 pe_tag_t *tag_lh = NULL;
349
350 xmlNode *rsc_set_lh = NULL;
351
352 *expanded_xml = NULL;
353
354 CRM_CHECK(xml_obj != NULL, return EINVAL);
355
356 id = ID(xml_obj);
357 if (id == NULL) {
358 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
359 crm_element_name(xml_obj));
360 return pcmk_rc_schema_validation;
361 }
362
363
364 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
365 if (*expanded_xml != NULL) {
366 crm_log_xml_trace(*expanded_xml, "Expanded rsc_ticket");
367 return pcmk_rc_ok;
368 }
369
370 id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
371 if (id_lh == NULL) {
372 return pcmk_rc_ok;
373 }
374
375 if (!pcmk__valid_resource_or_tag(data_set, id_lh, &rsc_lh, &tag_lh)) {
376 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
377 "valid resource or tag", id, id_lh);
378 return pcmk_rc_schema_validation;
379
380 } else if (rsc_lh) {
381
382 return pcmk_rc_ok;
383 }
384
385 state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
386
387 *expanded_xml = copy_xml(xml_obj);
388
389
390 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set_lh, XML_COLOC_ATTR_SOURCE,
391 false, data_set)) {
392 free_xml(*expanded_xml);
393 *expanded_xml = NULL;
394 return pcmk_rc_schema_validation;
395 }
396
397 if (rsc_set_lh != NULL) {
398 if (state_lh != NULL) {
399
400 crm_xml_add(rsc_set_lh, "role", state_lh);
401 xml_remove_prop(*expanded_xml, XML_COLOC_ATTR_SOURCE_ROLE);
402 }
403
404 } else {
405 free_xml(*expanded_xml);
406 *expanded_xml = NULL;
407 }
408
409 return pcmk_rc_ok;
410 }
411
412 void
413 pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pe_working_set_t *data_set)
414 {
415 xmlNode *set = NULL;
416 bool any_sets = false;
417
418 const char *id = NULL;
419 const char *ticket_str = crm_element_value(xml_obj, XML_TICKET_ATTR_TICKET);
420 const char *loss_policy = crm_element_value(xml_obj, XML_TICKET_ATTR_LOSS_POLICY);
421
422 pe_ticket_t *ticket = NULL;
423
424 xmlNode *orig_xml = NULL;
425 xmlNode *expanded_xml = NULL;
426
427 CRM_CHECK(xml_obj != NULL, return);
428
429 id = ID(xml_obj);
430 if (id == NULL) {
431 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
432 crm_element_name(xml_obj));
433 return;
434 }
435
436 if (data_set->tickets == NULL) {
437 data_set->tickets = pcmk__strkey_table(free, destroy_ticket);
438 }
439
440 if (ticket_str == NULL) {
441 pcmk__config_err("Ignoring constraint '%s' without ticket", id);
442 return;
443 } else {
444 ticket = g_hash_table_lookup(data_set->tickets, ticket_str);
445 }
446
447 if (ticket == NULL) {
448 ticket = ticket_new(ticket_str, data_set);
449 if (ticket == NULL) {
450 return;
451 }
452 }
453
454 if (unpack_rsc_ticket_tags(xml_obj, &expanded_xml,
455 data_set) != pcmk_rc_ok) {
456 return;
457 }
458 if (expanded_xml != NULL) {
459 orig_xml = xml_obj;
460 xml_obj = expanded_xml;
461 }
462
463 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
464 set = crm_next_same_xml(set)) {
465
466 any_sets = true;
467 set = expand_idref(set, data_set->input);
468 if ((set == NULL)
469 || (unpack_rsc_ticket_set(set, ticket, loss_policy,
470 data_set) != pcmk_rc_ok)) {
471 if (expanded_xml != NULL) {
472 free_xml(expanded_xml);
473 }
474 return;
475 }
476 }
477
478 if (expanded_xml) {
479 free_xml(expanded_xml);
480 xml_obj = orig_xml;
481 }
482
483 if (!any_sets) {
484 unpack_simple_rsc_ticket(xml_obj, data_set);
485 }
486 }