pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
cib_ops.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdio.h>
13#include <unistd.h>
14#include <stdlib.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <time.h>
18
19#include <sys/param.h>
20#include <sys/types.h>
21
22#include <crm/crm.h>
23#include <crm/cib/internal.h>
24#include <crm/msg_xml.h>
25
26#include <crm/common/xml.h>
28
29int
30cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
31 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
32{
33 xmlNode *obj_root = NULL;
34 int result = pcmk_ok;
35
36 crm_trace("Processing %s for %s section",
37 op, pcmk__s(section, "unspecified"));
38
39 if (options & cib_xpath) {
40 return cib_process_xpath(op, options, section, req, input,
41 existing_cib, result_cib, answer);
42 }
43
44 CRM_CHECK(*answer == NULL, free_xml(*answer));
45 *answer = NULL;
46
47 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
48 section = NULL;
49 }
50
51 obj_root = pcmk_find_cib_element(existing_cib, section);
52
53 if (obj_root == NULL) {
54 result = -ENXIO;
55
56 } else if (options & cib_no_children) {
57 const char *tag = TYPE(obj_root);
58 xmlNode *shallow = create_xml_node(*answer, tag);
59
60 copy_in_properties(shallow, obj_root);
61 *answer = shallow;
62
63 } else {
64 *answer = obj_root;
65 }
66
67 if (result == pcmk_ok && *answer == NULL) {
68 crm_err("Error creating query response");
69 result = -ENOMSG;
70 }
71
72 return result;
73}
74
75int
76cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
77 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
78{
79 int result = pcmk_ok;
80
81 crm_trace("Processing \"%s\" event", op);
82 *answer = NULL;
83 free_xml(*result_cib);
84 *result_cib = createEmptyCib(0);
85
86 copy_in_properties(*result_cib, existing_cib);
88
89 return result;
90}
91
92int
93cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
94 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
95 xmlNode ** answer)
96{
97 int rc = 0;
98 int new_version = 0;
99 int current_version = 0;
100 int max_version = 0;
101 const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
102 const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
103
104 *answer = NULL;
105 crm_trace("Processing \"%s\" event with max=%s", op, max);
106
107 if (value != NULL) {
108 current_version = get_schema_version(value);
109 }
110
111 if (max) {
112 max_version = get_schema_version(max);
113 }
114
115 rc = update_validation(result_cib, &new_version, max_version, TRUE,
116 !(options & cib_verbose));
117 if (new_version > current_version) {
119 cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
120 cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
121 return pcmk_ok;
122 }
123
124 return rc;
125}
126
127int
128cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
129 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
130{
131 int result = pcmk_ok;
132
133 crm_trace("Processing %s for epoch='%s'", op,
134 pcmk__s(crm_element_value(existing_cib, XML_ATTR_GENERATION), ""));
135
136 *answer = NULL;
137 cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
138
139 return result;
140}
141
142int
143cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
144{
145 char *new_value = NULL;
146 char *old_value = NULL;
147 int int_value = -1;
148
149 if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
150 old_value = crm_element_value_copy(xml_obj, field);
151 }
152 if (old_value != NULL) {
153 int_value = atoi(old_value);
154 new_value = pcmk__itoa(++int_value);
155 } else {
156 new_value = strdup("1");
157 CRM_ASSERT(new_value != NULL);
158 }
159
160 crm_trace("Update %s from %s to %s",
161 field, pcmk__s(old_value, "unset"), new_value);
162 crm_xml_add(xml_obj, field, new_value);
163
164 free(new_value);
165 free(old_value);
166
167 return pcmk_ok;
168}
169
170int
171cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
172 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
173 xmlNode ** answer)
174{
175 const char *tag = NULL;
176 int result = pcmk_ok;
177
178 crm_trace("Processing %s for %s section",
179 op, pcmk__s(section, "unspecified"));
180
181 if (options & cib_xpath) {
182 return cib_process_xpath(op, options, section, req, input,
183 existing_cib, result_cib, answer);
184 }
185
186 *answer = NULL;
187
188 if (input == NULL) {
189 return -EINVAL;
190 }
191
192 tag = crm_element_name(input);
193
194 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
195 section = NULL;
196
197 } else if (pcmk__str_eq(tag, section, pcmk__str_casei)) {
198 section = NULL;
199 }
200
201 if (pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
202 int updates = 0;
203 int epoch = 0;
204 int admin_epoch = 0;
205
206 int replace_updates = 0;
207 int replace_epoch = 0;
208 int replace_admin_epoch = 0;
209
210 const char *reason = NULL;
211 const char *peer = crm_element_value(req, F_ORIG);
212 const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
213
214 if (digest) {
216 char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
217 version ? version :
219
220 if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
221 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
222 digest_verify, digest);
223 reason = "digest mismatch";
224
225 } else {
226 crm_info("Digest matched on replace from %s: %s", peer, digest);
227 }
228 free(digest_verify);
229
230 } else {
231 crm_trace("No digest to verify");
232 }
233
234 cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
235 cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
236
237 if (replace_admin_epoch < admin_epoch) {
239
240 } else if (replace_admin_epoch > admin_epoch) {
241 /* no more checks */
242
243 } else if (replace_epoch < epoch) {
244 reason = XML_ATTR_GENERATION;
245
246 } else if (replace_epoch > epoch) {
247 /* no more checks */
248
249 } else if (replace_updates < updates) {
250 reason = XML_ATTR_NUMUPDATES;
251 }
252
253 if (reason != NULL) {
254 crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
255 " current %s is greater than the replacement",
256 replace_admin_epoch, replace_epoch,
257 replace_updates, peer, admin_epoch, epoch, updates, reason);
259 } else {
260 crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
261 admin_epoch, epoch, updates,
262 replace_admin_epoch, replace_epoch, replace_updates, peer);
263 }
264
265 free_xml(*result_cib);
266 *result_cib = copy_xml(input);
267
268 } else {
269 xmlNode *obj_root = NULL;
270 gboolean ok = TRUE;
271
272 obj_root = pcmk_find_cib_element(*result_cib, section);
273 ok = replace_xml_child(NULL, obj_root, input, FALSE);
274 if (ok == FALSE) {
275 crm_trace("No matching object to replace");
276 result = -ENXIO;
277 }
278 }
279
280 return result;
281}
282
283int
284cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
285 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
286{
287 xmlNode *obj_root = NULL;
288
289 crm_trace("Processing \"%s\" event", op);
290
291 if (options & cib_xpath) {
292 return cib_process_xpath(op, options, section, req, input,
293 existing_cib, result_cib, answer);
294 }
295
296 if (input == NULL) {
297 crm_err("Cannot perform modification with no data");
298 return -EINVAL;
299 }
300
301 obj_root = pcmk_find_cib_element(*result_cib, section);
302 if(pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
303 xmlNode *child = NULL;
304 for (child = pcmk__xml_first_child(input); child;
305 child = pcmk__xml_next(child)) {
306 if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
307 crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
308 }
309 }
310
311 } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
312 crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
313 }
314
315 return pcmk_ok;
316}
317
318int
319cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
320 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
321{
322 xmlNode *obj_root = NULL;
323
324 crm_trace("Processing \"%s\" event", op);
325
326 if (options & cib_xpath) {
327 return cib_process_xpath(op, options, section, req, input,
328 existing_cib, result_cib, answer);
329 }
330
331 if (input == NULL) {
332 crm_err("Cannot perform modification with no data");
333 return -EINVAL;
334 }
335
336 obj_root = pcmk_find_cib_element(*result_cib, section);
337 if (obj_root == NULL) {
338 xmlNode *tmp_section = NULL;
339 const char *path = pcmk_cib_parent_name_for(section);
340
341 if (path == NULL) {
342 return -EINVAL;
343 }
344
345 tmp_section = create_xml_node(NULL, section);
346 cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
347 NULL, result_cib, answer);
348 free_xml(tmp_section);
349
350 obj_root = pcmk_find_cib_element(*result_cib, section);
351 }
352
353 CRM_CHECK(obj_root != NULL, return -EINVAL);
354
355 if (update_xml_child(obj_root, input) == FALSE) {
356 if (options & cib_can_create) {
357 add_node_copy(obj_root, input);
358 } else {
359 return -ENXIO;
360 }
361 }
362
363 if(options & cib_mixed_update) {
364 int max = 0, lpc;
365 xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
366
367 if (xpathObj) {
368 max = numXpathResults(xpathObj);
369 crm_log_xml_trace(*result_cib, "Mixed result");
370 }
371
372 for (lpc = 0; lpc < max; lpc++) {
373 xmlNode *match = getXpathResult(xpathObj, lpc);
374 xmlChar *match_path = xmlGetNodePath(match);
375
376 crm_debug("Destroying %s", match_path);
377 free(match_path);
378 free_xml(match);
379 }
380
381 freeXpathObject(xpathObj);
382 }
383 return pcmk_ok;
384}
385
386static int
387update_cib_object(xmlNode * parent, xmlNode * update)
388{
389 int result = pcmk_ok;
390 xmlNode *target = NULL;
391 xmlNode *a_child = NULL;
392 const char *replace = NULL;
393 const char *object_id = NULL;
394 const char *object_name = NULL;
395
396 CRM_CHECK(update != NULL, return -EINVAL);
397 CRM_CHECK(parent != NULL, return -EINVAL);
398
399 object_name = crm_element_name(update);
400 CRM_CHECK(object_name != NULL, return -EINVAL);
401
402 object_id = ID(update);
403 crm_trace("Processing update for <%s%s%s%s>", object_name,
404 ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
405 ((object_id == NULL)? "" : "'"));
406
407 if (object_id == NULL) {
408 /* placeholder object */
409 target = find_xml_node(parent, object_name, FALSE);
410
411 } else {
412 target = pcmk__xe_match(parent, object_name, XML_ATTR_ID, object_id);
413 }
414
415 if (target == NULL) {
416 target = create_xml_node(parent, object_name);
417 }
418
419 crm_trace("Found node <%s%s%s%s> to update", object_name,
420 ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
421 ((object_id == NULL)? "" : "'"));
422
423 replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
424 if (replace != NULL) {
425 xmlNode *remove = NULL;
426 int last = 0, lpc = 0, len = 0;
427
428 len = strlen(replace);
429 while (lpc <= len) {
430 if (replace[lpc] == ',' || replace[lpc] == 0) {
431 char *replace_item = NULL;
432
433 if (last == lpc) {
434 /* nothing to do */
435 last = lpc + 1;
436 goto incr;
437 }
438
439 replace_item = strndup(replace + last, lpc - last);
440 remove = find_xml_node(target, replace_item, FALSE);
441 if (remove != NULL) {
442 crm_trace("Replacing node <%s> in <%s>",
443 replace_item, crm_element_name(target));
444 free_xml(remove);
445 remove = NULL;
446 }
447 free(replace_item);
448 last = lpc + 1;
449 }
450 incr:
451 lpc++;
452 }
455 }
456
457 copy_in_properties(target, update);
458
459 if (xml_acl_denied(target)) {
460 crm_notice("Cannot update <%s id=%s>", pcmk__s(object_name, "<null>"), pcmk__s(object_id, "<null>"));
461 return -EACCES;
462 }
463
464 crm_trace("Processing children of <%s%s%s%s>", object_name,
465 ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
466 ((object_id == NULL)? "" : "'"));
467
468 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
469 a_child = pcmk__xml_next(a_child)) {
470 int tmp_result = 0;
471
472 crm_trace("Updating child <%s%s%s%s>", crm_element_name(a_child),
473 ((ID(a_child) == NULL)? "" : " id='"),
474 pcmk__s(ID(a_child), ""), ((ID(a_child) == NULL)? "" : "'"));
475
476 tmp_result = update_cib_object(target, a_child);
477
478 /* only the first error is likely to be interesting */
479 if (tmp_result != pcmk_ok) {
480 crm_err("Error updating child <%s%s%s%s>",
481 crm_element_name(a_child),
482 ((ID(a_child) == NULL)? "" : " id='"),
483 pcmk__s(ID(a_child), ""),
484 ((ID(a_child) == NULL)? "" : "'"));
485
486 if (result == pcmk_ok) {
487 result = tmp_result;
488 }
489 }
490 }
491
492 crm_trace("Finished handling update for <%s%s%s%s>", object_name,
493 ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
494 ((object_id == NULL)? "" : "'"));
495
496 return result;
497}
498
499static int
500add_cib_object(xmlNode * parent, xmlNode * new_obj)
501{
502 const char *object_name = NULL;
503 const char *object_id = NULL;
504 xmlNode *equiv_node = NULL;
505
506 if ((parent == NULL) || (new_obj == NULL)) {
507 return -EINVAL;
508 }
509
510 object_name = crm_element_name(new_obj);
511 if (object_name == NULL) {
512 return -EINVAL;
513 }
514
515 object_id = ID(new_obj);
516
517 crm_trace("Processing creation of <%s%s%s%s>", object_name,
518 ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
519 ((object_id == NULL)? "" : "'"));
520
521 if (object_id == NULL) {
522 equiv_node = find_xml_node(parent, object_name, FALSE);
523 } else {
524 equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
525 object_id);
526 }
527 if (equiv_node != NULL) {
528 return -EEXIST;
529 }
530
531 return update_cib_object(parent, new_obj);
532}
533
534int
535cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
536 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
537{
538 xmlNode *failed = NULL;
539 int result = pcmk_ok;
540 xmlNode *update_section = NULL;
541
542 crm_trace("Processing %s for %s section",
543 op, pcmk__s(section, "unspecified"));
544 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
545 section = NULL;
546
547 } else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
548 section = NULL;
549
550 } else if (pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
551 section = NULL;
552 }
553
554 CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
555
556 if (input == NULL) {
557 crm_err("Cannot perform modification with no data");
558 return -EINVAL;
559 }
560
561 if (section == NULL) {
562 return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
563 answer);
564 }
565
566 failed = create_xml_node(NULL, XML_TAG_FAILED);
567
568 update_section = pcmk_find_cib_element(*result_cib, section);
569 if (pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
570 xmlNode *a_child = NULL;
571
572 for (a_child = pcmk__xml_first_child(input); a_child != NULL;
573 a_child = pcmk__xml_next(a_child)) {
574 result = add_cib_object(update_section, a_child);
575 if (update_results(failed, a_child, op, result)) {
576 break;
577 }
578 }
579
580 } else {
581 result = add_cib_object(update_section, input);
582 update_results(failed, input, op, result);
583 }
584
585 if ((result == pcmk_ok) && xml_has_children(failed)) {
586 result = -EINVAL;
587 }
588
589 if (result != pcmk_ok) {
590 crm_log_xml_err(failed, "CIB Update failures");
591 *answer = failed;
592
593 } else {
594 free_xml(failed);
595 }
596
597 return result;
598}
599
600int
601cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
602 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
603{
604 const char *originator = NULL;
605
606 if (req != NULL) {
607 originator = crm_element_value(req, F_ORIG);
608 }
609
610 crm_trace("Processing \"%s\" event from %s%s",
611 op, originator,
612 (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
613
614 free_xml(*result_cib);
615 *result_cib = copy_xml(existing_cib);
616 return xml_apply_patchset(*result_cib, input, TRUE);
617}
618
619gboolean
620cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
621{
622 int lpc = 0, max = 0;
623 gboolean config_changes = FALSE;
624 xmlXPathObject *xpathObj = NULL;
625 int format = 1;
626
627 CRM_ASSERT(diff != NULL);
628
629 if (*diff == NULL && last != NULL && next != NULL) {
630 *diff = diff_xml_object(last, next, FALSE);
631 }
632
633 if (*diff == NULL) {
634 goto done;
635 }
636
637 crm_element_value_int(*diff, "format", &format);
638 /* This function only applies to v1 diffs. */
639 CRM_LOG_ASSERT(format == 1);
640
641 xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
642 if (numXpathResults(xpathObj) > 0) {
643 config_changes = TRUE;
644 goto done;
645 }
646 freeXpathObject(xpathObj);
647
648 /*
649 * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
650 * This always contains every field and would produce a false positive
651 * every time if the checked value existed
652 */
653 xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
654 max = numXpathResults(xpathObj);
655
656 for (lpc = 0; lpc < max; lpc++) {
657 xmlNode *top = getXpathResult(xpathObj, lpc);
658
659 if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
660 config_changes = TRUE;
661 goto done;
662 }
664 config_changes = TRUE;
665 goto done;
666 }
667
668 if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
669 config_changes = TRUE;
670 goto done;
671 }
672 if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
673 config_changes = TRUE;
674 goto done;
675 }
676 if (crm_element_value(top, "remote-clear-port") != NULL) {
677 config_changes = TRUE;
678 goto done;
679 }
680 if (crm_element_value(top, "remote-tls-port") != NULL) {
681 config_changes = TRUE;
682 goto done;
683 }
684 }
685
686 done:
687 freeXpathObject(xpathObj);
688 return config_changes;
689}
690
691int
692cib_process_xpath(const char *op, int options, const char *section,
693 const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
694 xmlNode **result_cib, xmlNode **answer)
695{
696 int lpc = 0;
697 int max = 0;
698 int rc = pcmk_ok;
699 bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
700
701 xmlXPathObjectPtr xpathObj = NULL;
702
703 crm_trace("Processing \"%s\" event", op);
704
705 if (is_query) {
706 xpathObj = xpath_search(existing_cib, section);
707 } else {
708 xpathObj = xpath_search(*result_cib, section);
709 }
710
711 max = numXpathResults(xpathObj);
712
713 if ((max < 1)
714 && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
715 crm_debug("%s was already removed", section);
716
717 } else if (max < 1) {
718 crm_debug("%s: %s does not exist", op, section);
719 rc = -ENXIO;
720
721 } else if (is_query) {
722 if (max > 1) {
723 *answer = create_xml_node(NULL, "xpath-query");
724 }
725 }
726
727 if (pcmk_is_set(options, cib_multiple)
728 && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
729 dedupXpathResults(xpathObj);
730 }
731
732 for (lpc = 0; lpc < max; lpc++) {
733 xmlChar *path = NULL;
734 xmlNode *match = getXpathResult(xpathObj, lpc);
735
736 if (match == NULL) {
737 continue;
738 }
739
740 path = xmlGetNodePath(match);
741 crm_debug("Processing %s op for %s with %s", op, section, path);
742 free(path);
743
744 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
745 if (match == *result_cib) {
746 /* Attempting to delete the whole "/cib" */
747 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
748 rc = -EINVAL;
749 break;
750 }
751
752 free_xml(match);
753 if ((options & cib_multiple) == 0) {
754 break;
755 }
756
757 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
758 if (update_xml_child(match, input) == FALSE) {
759 rc = -ENXIO;
760 } else if ((options & cib_multiple) == 0) {
761 break;
762 }
763
764 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
765 add_node_copy(match, input);
766 break;
767
768 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
769
770 if (options & cib_no_children) {
771 const char *tag = TYPE(match);
772 xmlNode *shallow = create_xml_node(*answer, tag);
773
774 copy_in_properties(shallow, match);
775
776 if (*answer == NULL) {
777 *answer = shallow;
778 }
779
780 } else if (options & cib_xpath_address) {
781 char *path = NULL;
782 xmlNode *parent = match;
783
784 while (parent && parent->type == XML_ELEMENT_NODE) {
785 const char *id = crm_element_value(parent, XML_ATTR_ID);
786 char *new_path = NULL;
787
788 if (id) {
789 new_path = crm_strdup_printf("/%s[@id='%s']%s",
790 parent->name, id,
791 (path? path : ""));
792 } else {
793 new_path = crm_strdup_printf("/%s%s", parent->name,
794 (path? path : ""));
795 }
796 free(path);
797 path = new_path;
798 parent = parent->parent;
799 }
800 crm_trace("Got: %s", path);
801
802 if (*answer == NULL) {
803 *answer = create_xml_node(NULL, "xpath-query");
804 }
805 parent = create_xml_node(*answer, "xpath-query-path");
807 free(path);
808
809 } else if (*answer) {
810 add_node_copy(*answer, match);
811
812 } else {
813 *answer = match;
814 }
815
816 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
818 xmlNode *parent = match->parent;
819
820 free_xml(match);
821 if (input != NULL) {
823 }
824
825 if ((options & cib_multiple) == 0) {
826 break;
827 }
828 }
829 }
830
831 freeXpathObject(xpathObj);
832 return rc;
833}
834
835/* remove this function */
836gboolean
837update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
838{
839 xmlNode *xml_node = NULL;
840 gboolean was_error = FALSE;
841 const char *error_msg = NULL;
842
843 if (return_code != pcmk_ok) {
844 error_msg = pcmk_strerror(return_code);
845
846 was_error = TRUE;
847 xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
848 add_node_copy(xml_node, target);
849
852 crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
853 crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
854
855 crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
856 }
857
858 return was_error;
859}
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:613
#define F_CIB_SCHEMA_MAX
Definition: internal.h:63
#define PCMK__CIB_REQUEST_QUERY
Definition: internal.h:24
#define PCMK__CIB_REQUEST_REPLACE
Definition: internal.h:29
#define PCMK__CIB_REQUEST_DELETE
Definition: internal.h:27
#define PCMK__CIB_REQUEST_CREATE
Definition: internal.h:25
#define PCMK__CIB_REQUEST_MODIFY
Definition: internal.h:26
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:43
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition: cib_utils.c:89
const char * parent
Definition: cib.c:25
const char * path
Definition: cib.c:26
int cib_process_delete(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:284
int cib_process_xpath(const char *op, int options, const char *section, const xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:692
int cib_process_query(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:30
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:319
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:535
int cib_process_bump(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:128
int cib_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:171
int cib_update_counter(xmlNode *xml_obj, const char *field, gboolean reset)
Definition: cib_ops.c:143
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:601
int cib_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:93
gboolean cib_config_changed(xmlNode *last, xmlNode *next, xmlNode **diff)
Definition: cib_ops.c:620
int cib_process_erase(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:76
gboolean update_results(xmlNode *failed, xmlNode *target, const char *operation, int return_code)
Definition: cib_ops.c:837
@ cib_no_children
Definition: cib_types.h:56
@ cib_force_diff
Definition: cib_types.h:67
@ cib_xpath
Definition: cib_types.h:52
@ cib_mixed_update
Definition: cib_types.h:58
@ cib_verbose
Prefer stderr to logs.
Definition: cib_types.h:51
@ cib_can_create
Definition: cib_types.h:54
@ cib_multiple
Definition: cib_types.h:53
@ cib_xpath_address
Definition: cib_types.h:57
const char * pcmk_cib_parent_name_for(const char *element_name)
Get the parent element name of a given CIB element name.
Definition: cib.c:131
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
uint32_t version
Definition: remote.c:1
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
A dumping ground.
#define CRM_FEATURE_SET
Definition: crm.h:69
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
#define crm_log_xml_err(xml, text)
Definition: logging.h:368
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define XML_TAG_CIB
Definition: msg_xml.h:115
#define ID(x)
Definition: msg_xml.h:468
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:118
#define XML_TAG_DIFF_REMOVED
Definition: msg_xml.h:420
#define XML_CIB_ATTR_REPLACE
Definition: msg_xml.h:272
#define TYPE(x)
Definition: msg_xml.h:469
#define XML_TAG_FAILED
Definition: msg_xml.h:116
#define XML_FAILCIB_ATTR_OBJTYPE
Definition: msg_xml.h:178
#define XML_FAILCIB_ATTR_ID
Definition: msg_xml.h:177
#define XML_CIB_TAG_SECTION_ALL
Definition: msg_xml.h:183
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define F_ORIG
Definition: msg_xml.h:57
#define XML_CIB_TAG_CONFIGURATION
Definition: msg_xml.h:184
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:120
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:126
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:127
#define XML_FAIL_TAG_CIB
Definition: msg_xml.h:175
#define XML_FAILCIB_ATTR_OP
Definition: msg_xml.h:179
#define XML_ATTR_GENERATION
Definition: msg_xml.h:125
#define XML_ATTR_DIGEST
Definition: msg_xml.h:119
#define XML_FAILCIB_ATTR_REASON
Definition: msg_xml.h:180
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:553
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:714
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
pcmk__action_result_t result
Definition: pcmk_fence.c:35
const char * target
Definition: pcmk_fence.c:29
char * strndup(const char *str, size_t len)
const char * pcmk_strerror(int rc)
Definition: results.c:148
#define pcmk_err_old_data
Definition: results.h:75
#define CRM_ASSERT(expr)
Definition: results.h:42
#define pcmk_ok
Definition: results.h:68
@ pcmk__str_none
@ pcmk__str_casei
Wrappers for and extensions to libxml2.
gboolean update_xml_child(xmlNode *child, xmlNode *to_update)
Definition: xml.c:2749
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:2136
int get_schema_version(const char *name)
Definition: schemas.c:1033
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:139
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
Definition: xml.c:2816
int update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform, gboolean to_logs)
Update CIB XML to most recent schema version.
Definition: schemas.c:1050
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:101
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: patchset.c:1317
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
char * calculate_xml_versioned_digest(xmlNode *input, gboolean sort, gboolean do_filter, const char *version)
Calculate and return digest of XML tree.
Definition: digest.c:170
void free_xml(xmlNode *child)
Definition: xml.c:885
void copy_in_properties(xmlNode *target, xmlNode *src)
Definition: xml.c:545
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
Definition: xml.c:470
xmlNode * diff_xml_object(xmlNode *left, xmlNode *right, gboolean suppress)
Definition: patchset.c:1411
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:727
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:891
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2145
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:520