This source file includes following definitions.
- build_ticket_modify_xml
- add_attribute_xml
- pcmk__get_ticket_state
- pcmk__ticket_constraints
- pcmk_ticket_constraints
- delete_single_ticket
- pcmk__ticket_delete
- pcmk_ticket_delete
- pcmk__ticket_get_attr
- pcmk_ticket_get_attr
- pcmk__ticket_info
- pcmk_ticket_info
- pcmk__ticket_remove_attr
- pcmk_ticket_remove_attr
- pcmk__ticket_set_attr
- pcmk_ticket_set_attr
- pcmk__ticket_state
- pcmk_ticket_state
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/cib/internal.h>
13 #include <crm/pengine/internal.h>
14
15 #include <pacemaker.h>
16 #include <pacemaker-internal.h>
17
18 #include "libpacemaker_private.h"
19
20 static int
21 build_ticket_modify_xml(cib_t *cib, const char *ticket_id, xmlNode **ticket_state_xml,
22 xmlNode **xml_top)
23 {
24 int rc = pcmk__get_ticket_state(cib, ticket_id, ticket_state_xml);
25
26 if (rc == pcmk_rc_ok || rc == pcmk_rc_duplicate_id) {
27
28 *xml_top = *ticket_state_xml;
29
30 } else if (rc == ENXIO) {
31
32 xmlNode *xml_obj = NULL;
33
34 *xml_top = pcmk__xe_create(NULL, PCMK_XE_STATUS);
35 xml_obj = pcmk__xe_create(*xml_top, PCMK_XE_TICKETS);
36 *ticket_state_xml = pcmk__xe_create(xml_obj, PCMK__XE_TICKET_STATE);
37 crm_xml_add(*ticket_state_xml, PCMK_XA_ID, ticket_id);
38
39 rc = pcmk_rc_ok;
40
41 } else {
42
43 pcmk__xml_free(*ticket_state_xml);
44 }
45
46 return rc;
47 }
48
49 static void
50 add_attribute_xml(pcmk_scheduler_t *scheduler, const char *ticket_id,
51 GHashTable *attr_set, xmlNode **ticket_state_xml)
52 {
53 GHashTableIter hash_iter;
54 char *key = NULL;
55 char *value = NULL;
56 pcmk__ticket_t *ticket = NULL;
57
58 ticket = g_hash_table_lookup(scheduler->priv->ticket_constraints,
59 ticket_id);
60 g_hash_table_iter_init(&hash_iter, attr_set);
61 while (g_hash_table_iter_next(&hash_iter, (gpointer *) & key, (gpointer *) & value)) {
62 crm_xml_add(*ticket_state_xml, key, value);
63
64 if (pcmk__str_eq(key, PCMK__XA_GRANTED, pcmk__str_none)
65 && ((ticket == NULL)
66 || !pcmk_is_set(ticket->flags, pcmk__ticket_granted))
67 && crm_is_true(value)) {
68
69 char *now = pcmk__ttoa(time(NULL));
70
71 crm_xml_add(*ticket_state_xml, PCMK_XA_LAST_GRANTED, now);
72 free(now);
73 }
74 }
75 }
76
77 int
78 pcmk__get_ticket_state(cib_t *cib, const char *ticket_id, xmlNode **state)
79 {
80 int rc = pcmk_rc_ok;
81 xmlNode *xml_search = NULL;
82 char *xpath = NULL;
83
84 pcmk__assert((cib != NULL) && (state != NULL));
85 *state = NULL;
86
87 if (ticket_id != NULL) {
88 xpath = crm_strdup_printf("/" PCMK_XE_CIB "/" PCMK_XE_STATUS "/" PCMK_XE_TICKETS
89 "/" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"%s\"]",
90 ticket_id);
91 } else {
92 xpath = crm_strdup_printf("/" PCMK_XE_CIB "/" PCMK_XE_STATUS "/" PCMK_XE_TICKETS);
93 }
94
95 rc = cib->cmds->query(cib, xpath, &xml_search, cib_sync_call|cib_xpath);
96 rc = pcmk_legacy2rc(rc);
97
98 if (rc == pcmk_rc_ok) {
99 crm_log_xml_debug(xml_search, "Match");
100
101 if (xml_search->children != NULL && ticket_id != NULL) {
102 rc = pcmk_rc_duplicate_id;
103 }
104 }
105
106 free(xpath);
107
108 *state = xml_search;
109 return rc;
110 }
111
112 int
113 pcmk__ticket_constraints(pcmk__output_t *out, cib_t *cib, const char *ticket_id)
114 {
115 int rc = pcmk_rc_ok;
116 xmlNode *result = NULL;
117 const char *xpath_base = NULL;
118 char *xpath = NULL;
119
120 pcmk__assert((out != NULL) && (cib != NULL));
121
122 xpath_base = pcmk_cib_xpath_for(PCMK_XE_CONSTRAINTS);
123 pcmk__assert(xpath_base != NULL);
124
125 if (ticket_id != NULL) {
126 xpath = crm_strdup_printf("%s/" PCMK_XE_RSC_TICKET "[@" PCMK_XA_TICKET "=\"%s\"]",
127 xpath_base, ticket_id);
128 } else {
129 xpath = crm_strdup_printf("%s/" PCMK_XE_RSC_TICKET, xpath_base);
130 }
131
132 rc = cib->cmds->query(cib, xpath, &result, cib_sync_call|cib_xpath);
133 rc = pcmk_legacy2rc(rc);
134
135 if (result != NULL) {
136 out->message(out, "ticket-constraints", result);
137 pcmk__xml_free(result);
138 }
139
140 free(xpath);
141 return rc;
142 }
143
144 int
145 pcmk_ticket_constraints(xmlNodePtr *xml, const char *ticket_id)
146 {
147 pcmk__output_t *out = NULL;
148 int rc = pcmk_rc_ok;
149 cib_t *cib = NULL;
150
151 rc = pcmk__setup_output_cib_sched(&out, &cib, NULL, xml);
152 if (rc != pcmk_rc_ok) {
153 goto done;
154 }
155
156 rc = pcmk__ticket_constraints(out, cib, ticket_id);
157
158 done:
159 if (cib != NULL) {
160 cib__clean_up_connection(&cib);
161 }
162
163 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
164 return rc;
165 }
166
167 static int
168 delete_single_ticket(xmlNode *child, void *userdata)
169 {
170 int rc = pcmk_rc_ok;
171 cib_t *cib = (cib_t *) userdata;
172
173 rc = cib->cmds->remove(cib, PCMK_XE_STATUS, child, cib_sync_call);
174 rc = pcmk_legacy2rc(rc);
175
176 return rc;
177 }
178
179 int
180 pcmk__ticket_delete(pcmk__output_t *out, cib_t *cib, pcmk_scheduler_t *scheduler,
181 const char *ticket_id, bool force)
182 {
183 int rc = pcmk_rc_ok;
184 xmlNode *state = NULL;
185
186 pcmk__assert((cib != NULL) && (scheduler != NULL));
187
188 if (ticket_id == NULL) {
189 return EINVAL;
190 }
191
192 if (!force) {
193 pcmk__ticket_t *ticket = NULL;
194
195 ticket = g_hash_table_lookup(scheduler->priv->ticket_constraints,
196 ticket_id);
197 if (ticket == NULL) {
198 return ENXIO;
199 }
200
201 if (pcmk_is_set(ticket->flags, pcmk__ticket_granted)) {
202 return EACCES;
203 }
204 }
205
206 rc = pcmk__get_ticket_state(cib, ticket_id, &state);
207
208 if (rc == pcmk_rc_duplicate_id) {
209 out->info(out, "Multiple " PCMK__XE_TICKET_STATE "s match ticket=%s",
210 ticket_id);
211
212 } else if (rc == ENXIO) {
213 return pcmk_rc_ok;
214
215 } else if (rc != pcmk_rc_ok) {
216 return rc;
217 }
218
219 crm_log_xml_debug(state, "Delete");
220
221 if (rc == pcmk_rc_duplicate_id) {
222 rc = pcmk__xe_foreach_child(state, NULL, delete_single_ticket, cib);
223 } else {
224 rc = delete_single_ticket(state, cib);
225 }
226
227 if (rc == pcmk_rc_ok) {
228 out->info(out, "Cleaned up %s", ticket_id);
229 }
230
231 pcmk__xml_free(state);
232 return rc;
233 }
234
235 int
236 pcmk_ticket_delete(xmlNodePtr *xml, const char *ticket_id, bool force)
237 {
238 pcmk_scheduler_t *scheduler = NULL;
239 pcmk__output_t *out = NULL;
240 cib_t *cib = NULL;
241 int rc = pcmk_rc_ok;
242
243 rc = pcmk__setup_output_cib_sched(&out, &cib, &scheduler, xml);
244 if (rc != pcmk_rc_ok) {
245 goto done;
246 }
247
248 rc = pcmk__ticket_delete(out, cib, scheduler, ticket_id, force);
249
250 done:
251 if (cib != NULL) {
252 cib__clean_up_connection(&cib);
253 }
254
255 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
256 pe_free_working_set(scheduler);
257 return rc;
258 }
259
260 int
261 pcmk__ticket_get_attr(pcmk__output_t *out, pcmk_scheduler_t *scheduler,
262 const char *ticket_id, const char *attr_name,
263 const char *attr_default)
264 {
265 int rc = pcmk_rc_ok;
266 const char *attr_value = NULL;
267 pcmk__ticket_t *ticket = NULL;
268
269 pcmk__assert((out != NULL) && (scheduler != NULL));
270
271 if (ticket_id == NULL || attr_name == NULL) {
272 return EINVAL;
273 }
274
275 ticket = g_hash_table_lookup(scheduler->priv->ticket_constraints,
276 ticket_id);
277
278 if (ticket != NULL) {
279 attr_value = g_hash_table_lookup(ticket->state, attr_name);
280 }
281
282 if (attr_value != NULL) {
283 out->message(out, "ticket-attribute", ticket_id, attr_name, attr_value);
284 } else if (attr_default != NULL) {
285 out->message(out, "ticket-attribute", ticket_id, attr_name, attr_default);
286 } else {
287 rc = ENXIO;
288 }
289
290 return rc;
291 }
292
293 int
294 pcmk_ticket_get_attr(xmlNodePtr *xml, const char *ticket_id,
295 const char *attr_name, const char *attr_default)
296 {
297 pcmk_scheduler_t *scheduler = NULL;
298 pcmk__output_t *out = NULL;
299 int rc = pcmk_rc_ok;
300
301 rc = pcmk__setup_output_cib_sched(&out, NULL, &scheduler, xml);
302 if (rc != pcmk_rc_ok) {
303 goto done;
304 }
305
306 rc = pcmk__ticket_get_attr(out, scheduler, ticket_id, attr_name, attr_default);
307
308 done:
309 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
310 pe_free_working_set(scheduler);
311 return rc;
312 }
313
314 int
315 pcmk__ticket_info(pcmk__output_t *out, pcmk_scheduler_t *scheduler,
316 const char *ticket_id, bool details, bool raw)
317 {
318 int rc = pcmk_rc_ok;
319
320 pcmk__assert((out != NULL) && (scheduler != NULL));
321
322 if (ticket_id != NULL) {
323 GHashTable *tickets = NULL;
324 pcmk__ticket_t *ticket = NULL;
325
326 ticket = g_hash_table_lookup(scheduler->priv->ticket_constraints,
327 ticket_id);
328 if (ticket == NULL) {
329 return ENXIO;
330 }
331
332
333
334
335 tickets = pcmk__strkey_table(free, NULL);
336 g_hash_table_insert(tickets, strdup(ticket->id), ticket);
337 out->message(out, "ticket-list", tickets, false, raw, details);
338 g_hash_table_destroy(tickets);
339
340 } else {
341 out->message(out, "ticket-list", scheduler->priv->ticket_constraints,
342 false, raw, details);
343 }
344
345 return rc;
346 }
347
348 int
349 pcmk_ticket_info(xmlNodePtr *xml, const char *ticket_id)
350 {
351 pcmk_scheduler_t *scheduler = NULL;
352 pcmk__output_t *out = NULL;
353 int rc = pcmk_rc_ok;
354
355 rc = pcmk__setup_output_cib_sched(&out, NULL, &scheduler, xml);
356 if (rc != pcmk_rc_ok) {
357 goto done;
358 }
359
360 pe__register_messages(out);
361
362
363
364
365
366 rc = pcmk__ticket_info(out, scheduler, ticket_id, false, false);
367
368 done:
369 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
370 pe_free_working_set(scheduler);
371 return rc;
372 }
373
374 int
375 pcmk__ticket_remove_attr(pcmk__output_t *out, cib_t *cib, pcmk_scheduler_t *scheduler,
376 const char *ticket_id, GList *attr_delete, bool force)
377 {
378 xmlNode *ticket_state_xml = NULL;
379 xmlNode *xml_top = NULL;
380 int rc = pcmk_rc_ok;
381
382 pcmk__assert((out != NULL) && (cib != NULL) && (scheduler != NULL));
383
384 if (ticket_id == NULL) {
385 return EINVAL;
386 }
387
388
389 if (attr_delete == NULL) {
390 return pcmk_rc_ok;
391 }
392
393 rc = build_ticket_modify_xml(cib, ticket_id, &ticket_state_xml, &xml_top);
394
395 if (rc == pcmk_rc_duplicate_id) {
396 out->info(out, "Multiple " PCMK__XE_TICKET_STATE "s match ticket=%s", ticket_id);
397 } else if (rc != pcmk_rc_ok) {
398 pcmk__xml_free(ticket_state_xml);
399 return rc;
400 }
401
402 for (GList *list_iter = attr_delete; list_iter != NULL; list_iter = list_iter->next) {
403 const char *key = list_iter->data;
404
405 if (!force && pcmk__str_eq(key, PCMK__XA_GRANTED, pcmk__str_none)) {
406 pcmk__xml_free(ticket_state_xml);
407 return EACCES;
408 }
409
410 pcmk__xe_remove_attr(ticket_state_xml, key);
411 }
412
413 crm_log_xml_debug(xml_top, "Replace");
414 rc = cib->cmds->replace(cib, PCMK_XE_STATUS, ticket_state_xml, cib_sync_call);
415 rc = pcmk_legacy2rc(rc);
416
417 pcmk__xml_free(xml_top);
418 return rc;
419 }
420
421 int
422 pcmk_ticket_remove_attr(xmlNodePtr *xml, const char *ticket_id, GList *attr_delete, bool force)
423 {
424 pcmk_scheduler_t *scheduler = NULL;
425 pcmk__output_t *out = NULL;
426 int rc = pcmk_rc_ok;
427 cib_t *cib = NULL;
428
429 rc = pcmk__setup_output_cib_sched(&out, &cib, &scheduler, xml);
430 if (rc != pcmk_rc_ok) {
431 goto done;
432 }
433
434 rc = pcmk__ticket_remove_attr(out, cib, scheduler, ticket_id, attr_delete, force);
435
436 done:
437 if (cib != NULL) {
438 cib__clean_up_connection(&cib);
439 }
440
441 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
442 pe_free_working_set(scheduler);
443 return rc;
444 }
445
446 int
447 pcmk__ticket_set_attr(pcmk__output_t *out, cib_t *cib, pcmk_scheduler_t *scheduler,
448 const char *ticket_id, GHashTable *attr_set, bool force)
449 {
450 xmlNode *ticket_state_xml = NULL;
451 xmlNode *xml_top = NULL;
452 int rc = pcmk_rc_ok;
453
454 pcmk__assert((out != NULL) && (cib != NULL) && (scheduler != NULL));
455
456 if (ticket_id == NULL) {
457 return EINVAL;
458 }
459
460
461 if (attr_set == NULL || g_hash_table_size(attr_set) == 0) {
462 return pcmk_rc_ok;
463 }
464
465 rc = build_ticket_modify_xml(cib, ticket_id, &ticket_state_xml, &xml_top);
466
467 if (rc == pcmk_rc_duplicate_id) {
468 out->info(out, "Multiple " PCMK__XE_TICKET_STATE "s match ticket=%s", ticket_id);
469 } else if (rc != pcmk_rc_ok) {
470 pcmk__xml_free(ticket_state_xml);
471 return rc;
472 }
473
474 if (!force && g_hash_table_lookup(attr_set, PCMK__XA_GRANTED)) {
475 pcmk__xml_free(ticket_state_xml);
476 return EACCES;
477 }
478
479 add_attribute_xml(scheduler, ticket_id, attr_set, &ticket_state_xml);
480
481 crm_log_xml_debug(xml_top, "Update");
482 rc = cib->cmds->modify(cib, PCMK_XE_STATUS, xml_top, cib_sync_call);
483 rc = pcmk_legacy2rc(rc);
484
485 pcmk__xml_free(xml_top);
486 return rc;
487 }
488
489 int
490 pcmk_ticket_set_attr(xmlNodePtr *xml, const char *ticket_id, GHashTable *attr_set,
491 bool force)
492 {
493 pcmk_scheduler_t *scheduler = NULL;
494 pcmk__output_t *out = NULL;
495 int rc = pcmk_rc_ok;
496 cib_t *cib = NULL;
497
498 rc = pcmk__setup_output_cib_sched(&out, &cib, &scheduler, xml);
499 if (rc != pcmk_rc_ok) {
500 goto done;
501 }
502
503 rc = pcmk__ticket_set_attr(out, cib, scheduler, ticket_id, attr_set, force);
504
505 done:
506 if (cib != NULL) {
507 cib__clean_up_connection(&cib);
508 }
509
510 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
511 pe_free_working_set(scheduler);
512 return rc;
513 }
514
515 int
516 pcmk__ticket_state(pcmk__output_t *out, cib_t *cib, const char *ticket_id)
517 {
518 xmlNode *state_xml = NULL;
519 int rc = pcmk_rc_ok;
520
521 pcmk__assert((out != NULL) && (cib != NULL));
522
523 rc = pcmk__get_ticket_state(cib, ticket_id, &state_xml);
524
525 if (rc == pcmk_rc_duplicate_id) {
526 out->info(out, "Multiple " PCMK__XE_TICKET_STATE "s match ticket=%s",
527 ticket_id);
528 }
529
530 if (state_xml != NULL) {
531 out->message(out, "ticket-state", state_xml);
532 pcmk__xml_free(state_xml);
533 }
534
535 return rc;
536 }
537
538 int
539 pcmk_ticket_state(xmlNodePtr *xml, const char *ticket_id)
540 {
541 pcmk__output_t *out = NULL;
542 int rc = pcmk_rc_ok;
543 cib_t *cib = NULL;
544
545 rc = pcmk__setup_output_cib_sched(&out, &cib, NULL, xml);
546 if (rc != pcmk_rc_ok) {
547 goto done;
548 }
549
550 rc = pcmk__ticket_state(out, cib, ticket_id);
551
552 done:
553 if (cib != NULL) {
554 cib__clean_up_connection(&cib);
555 }
556
557 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
558 return rc;
559 }