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