pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
cib_ops.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2023 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 <glib.h>
23#include <libxml/tree.h>
24
25#include <crm/crm.h>
26#include <crm/cib/internal.h>
27#include <crm/msg_xml.h>
28
29#include <crm/common/xml.h>
31
32// @TODO: Free this via crm_exit() when libcib gets merged with libcrmcommon
33static GHashTable *operation_table = NULL;
34
35static const cib__operation_t cib_ops[] = {
36 {
39 },
40 {
45 },
46 {
51 },
52 {
58 },
59 {
64 },
65 {
70 },
71 {
77 },
78 {
81 },
82 {
87 },
88 {
90 },
91 {
93 },
94 {
95 // @COMPAT: Drop cib__op_attr_modifies when we drop legacy mode support
98 },
99 {
101 },
102 {
109 },
110 {
113 },
114 {
116 },
117 {
119 },
120 {
122 },
123 {
129 },
130};
131
141int
142cib__get_operation(const char *op, const cib__operation_t **operation)
143{
144 CRM_ASSERT((op != NULL) && (operation != NULL));
145
146 if (operation_table == NULL) {
147 operation_table = pcmk__strkey_table(NULL, NULL);
148
149 for (int lpc = 0; lpc < PCMK__NELEM(cib_ops); lpc++) {
150 const cib__operation_t *oper = &(cib_ops[lpc]);
151
152 g_hash_table_insert(operation_table, (gpointer) oper->name,
153 (gpointer) oper);
154 }
155 }
156
157 *operation = g_hash_table_lookup(operation_table, op);
158 if (*operation == NULL) {
159 crm_err("Operation %s is invalid", op);
160 return EINVAL;
161 }
162 return pcmk_rc_ok;
163}
164
165int
166cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
167 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
168{
169 xmlNode *obj_root = NULL;
170 int result = pcmk_ok;
171
172 crm_trace("Processing %s for %s section",
173 op, pcmk__s(section, "unspecified"));
174
175 if (options & cib_xpath) {
176 return cib_process_xpath(op, options, section, req, input,
177 existing_cib, result_cib, answer);
178 }
179
180 CRM_CHECK(*answer == NULL, free_xml(*answer));
181 *answer = NULL;
182
183 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
184 section = NULL;
185 }
186
187 obj_root = pcmk_find_cib_element(existing_cib, section);
188
189 if (obj_root == NULL) {
190 result = -ENXIO;
191
192 } else if (options & cib_no_children) {
193 xmlNode *shallow = create_xml_node(*answer,
194 (const char *) obj_root->name);
195
196 copy_in_properties(shallow, obj_root);
197 *answer = shallow;
198
199 } else {
200 *answer = obj_root;
201 }
202
203 if (result == pcmk_ok && *answer == NULL) {
204 crm_err("Error creating query response");
205 result = -ENOMSG;
206 }
207
208 return result;
209}
210
211static int
212update_counter(xmlNode *xml_obj, const char *field, bool reset)
213{
214 char *new_value = NULL;
215 char *old_value = NULL;
216 int int_value = -1;
217
218 if (!reset && crm_element_value(xml_obj, field) != NULL) {
219 old_value = crm_element_value_copy(xml_obj, field);
220 }
221 if (old_value != NULL) {
222 int_value = atoi(old_value);
223 new_value = pcmk__itoa(++int_value);
224 } else {
225 new_value = strdup("1");
226 CRM_ASSERT(new_value != NULL);
227 }
228
229 crm_trace("Update %s from %s to %s",
230 field, pcmk__s(old_value, "unset"), new_value);
231 crm_xml_add(xml_obj, field, new_value);
232
233 free(new_value);
234 free(old_value);
235
236 return pcmk_ok;
237}
238
239int
240cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
241 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
242{
243 int result = pcmk_ok;
244
245 crm_trace("Processing \"%s\" event", op);
246
247 if (*result_cib != existing_cib) {
248 free_xml(*result_cib);
249 }
250 *result_cib = createEmptyCib(0);
251 copy_in_properties(*result_cib, existing_cib);
252 update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, false);
253 *answer = NULL;
254
255 return result;
256}
257
258int
259cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
260 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
261 xmlNode ** answer)
262{
263 int rc = 0;
264 int new_version = 0;
265 int current_version = 0;
266 int max_version = 0;
267 const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
268 const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
269
270 *answer = NULL;
271 crm_trace("Processing \"%s\" event with max=%s", op, max);
272
273 if (value != NULL) {
274 current_version = get_schema_version(value);
275 }
276
277 if (max) {
278 max_version = get_schema_version(max);
279 }
280
281 rc = update_validation(result_cib, &new_version, max_version, TRUE,
282 !(options & cib_verbose));
283 if (new_version > current_version) {
284 update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, false);
285 update_counter(*result_cib, XML_ATTR_GENERATION, true);
286 update_counter(*result_cib, XML_ATTR_NUMUPDATES, true);
287 return pcmk_ok;
288 }
289
290 return rc;
291}
292
293int
294cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
295 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
296{
297 int result = pcmk_ok;
298
299 crm_trace("Processing %s for epoch='%s'", op,
300 pcmk__s(crm_element_value(existing_cib, XML_ATTR_GENERATION), ""));
301
302 *answer = NULL;
303 update_counter(*result_cib, XML_ATTR_GENERATION, false);
304
305 return result;
306}
307
308int
309cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
310 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
311 xmlNode ** answer)
312{
313 int result = pcmk_ok;
314
315 crm_trace("Processing %s for %s section",
316 op, pcmk__s(section, "unspecified"));
317
318 if (options & cib_xpath) {
319 return cib_process_xpath(op, options, section, req, input,
320 existing_cib, result_cib, answer);
321 }
322
323 *answer = NULL;
324
325 if (input == NULL) {
326 return -EINVAL;
327 }
328
329 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
330 section = NULL;
331
332 } else if (pcmk__xe_is(input, section)) {
333 section = NULL;
334 }
335
336 if (pcmk__xe_is(input, XML_TAG_CIB)) {
337 int updates = 0;
338 int epoch = 0;
339 int admin_epoch = 0;
340
341 int replace_updates = 0;
342 int replace_epoch = 0;
343 int replace_admin_epoch = 0;
344
345 const char *reason = NULL;
346 const char *peer = crm_element_value(req, F_ORIG);
347 const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
348
349 if (digest) {
351 char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
352 version ? version :
354
355 if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
356 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
357 digest_verify, digest);
358 reason = "digest mismatch";
359
360 } else {
361 crm_info("Digest matched on replace from %s: %s", peer, digest);
362 }
363 free(digest_verify);
364
365 } else {
366 crm_trace("No digest to verify");
367 }
368
369 cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
370 cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
371
372 if (replace_admin_epoch < admin_epoch) {
374
375 } else if (replace_admin_epoch > admin_epoch) {
376 /* no more checks */
377
378 } else if (replace_epoch < epoch) {
379 reason = XML_ATTR_GENERATION;
380
381 } else if (replace_epoch > epoch) {
382 /* no more checks */
383
384 } else if (replace_updates < updates) {
385 reason = XML_ATTR_NUMUPDATES;
386 }
387
388 if (reason != NULL) {
389 crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
390 " current %s is greater than the replacement",
391 replace_admin_epoch, replace_epoch,
392 replace_updates, peer, admin_epoch, epoch, updates, reason);
394 } else {
395 crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
396 admin_epoch, epoch, updates,
397 replace_admin_epoch, replace_epoch, replace_updates, peer);
398 }
399
400 if (*result_cib != existing_cib) {
401 free_xml(*result_cib);
402 }
403 *result_cib = copy_xml(input);
404
405 } else {
406 xmlNode *obj_root = NULL;
407 gboolean ok = TRUE;
408
409 obj_root = pcmk_find_cib_element(*result_cib, section);
410 ok = replace_xml_child(NULL, obj_root, input, FALSE);
411 if (ok == FALSE) {
412 crm_trace("No matching object to replace");
413 result = -ENXIO;
414 }
415 }
416
417 return result;
418}
419
420int
421cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
422 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
423{
424 xmlNode *obj_root = NULL;
425
426 crm_trace("Processing \"%s\" event", op);
427
428 if (options & cib_xpath) {
429 return cib_process_xpath(op, options, section, req, input,
430 existing_cib, result_cib, answer);
431 }
432
433 if (input == NULL) {
434 crm_err("Cannot perform modification with no data");
435 return -EINVAL;
436 }
437
438 obj_root = pcmk_find_cib_element(*result_cib, section);
439 if (pcmk__xe_is(input, section)) {
440 xmlNode *child = NULL;
441 for (child = pcmk__xml_first_child(input); child;
442 child = pcmk__xml_next(child)) {
443 if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
444 crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
445 }
446 }
447
448 } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
449 crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
450 }
451
452 return pcmk_ok;
453}
454
455int
456cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
457 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
458{
459 xmlNode *obj_root = NULL;
460
461 crm_trace("Processing \"%s\" event", op);
462
463 if (options & cib_xpath) {
464 return cib_process_xpath(op, options, section, req, input,
465 existing_cib, result_cib, answer);
466 }
467
468 if (input == NULL) {
469 crm_err("Cannot perform modification with no data");
470 return -EINVAL;
471 }
472
473 obj_root = pcmk_find_cib_element(*result_cib, section);
474 if (obj_root == NULL) {
475 xmlNode *tmp_section = NULL;
476 const char *path = pcmk_cib_parent_name_for(section);
477
478 if (path == NULL) {
479 return -EINVAL;
480 }
481
482 tmp_section = create_xml_node(NULL, section);
483 cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
484 NULL, result_cib, answer);
485 free_xml(tmp_section);
486
487 obj_root = pcmk_find_cib_element(*result_cib, section);
488 }
489
490 CRM_CHECK(obj_root != NULL, return -EINVAL);
491
492 if (update_xml_child(obj_root, input) == FALSE) {
493 if (options & cib_can_create) {
494 add_node_copy(obj_root, input);
495 } else {
496 return -ENXIO;
497 }
498 }
499
500 // @COMPAT cib_mixed_update is deprecated as of 2.1.7
501 if (pcmk_is_set(options, cib_mixed_update)) {
502 int max = 0, lpc;
503 xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
504
505 if (xpathObj) {
506 max = numXpathResults(xpathObj);
507 crm_log_xml_trace(*result_cib, "Mixed result");
508 }
509
510 for (lpc = 0; lpc < max; lpc++) {
511 xmlNode *match = getXpathResult(xpathObj, lpc);
512 xmlChar *match_path = xmlGetNodePath(match);
513
514 crm_debug("Destroying %s", match_path);
515 free(match_path);
516 free_xml(match);
517 }
518
519 freeXpathObject(xpathObj);
520 }
521 return pcmk_ok;
522}
523
524static int
525update_cib_object(xmlNode * parent, xmlNode * update)
526{
527 int result = pcmk_ok;
528 xmlNode *target = NULL;
529 xmlNode *a_child = NULL;
530 const char *replace = NULL;
531 const char *object_id = NULL;
532 const char *object_name = NULL;
533
534 CRM_CHECK(update != NULL, return -EINVAL);
535 CRM_CHECK(parent != NULL, return -EINVAL);
536
537 object_name = (const char *) update->name;
538 CRM_CHECK(object_name != NULL, return -EINVAL);
539
540 object_id = ID(update);
541 crm_trace("Processing update for <%s%s%s%s>", object_name,
542 ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
543 pcmk__s(object_id, ""),
544 ((object_id == NULL)? "" : "'"));
545
546 if (object_id == NULL) {
547 /* placeholder object */
548 target = find_xml_node(parent, object_name, FALSE);
549
550 } else {
551 target = pcmk__xe_match(parent, object_name, XML_ATTR_ID, object_id);
552 }
553
554 if (target == NULL) {
555 target = create_xml_node(parent, object_name);
556 }
557
558 crm_trace("Found node <%s%s%s%s> to update", object_name,
559 ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
560 pcmk__s(object_id, ""),
561 ((object_id == NULL)? "" : "'"));
562
563 // @COMPAT: XML_CIB_ATTR_REPLACE is unused internally. Remove at break.
564 replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
565 if (replace != NULL) {
566 int last = 0;
567 int len = strlen(replace);
568
569 for (int lpc = 0; lpc <= len; ++lpc) {
570 if (replace[lpc] == ',' || replace[lpc] == 0) {
571 if (last != lpc) {
572 char *replace_item = strndup(replace + last, lpc - last);
573 xmlNode *remove = find_xml_node(target, replace_item,
574 FALSE);
575
576 if (remove != NULL) {
577 crm_trace("Replacing node <%s> in <%s>",
578 replace_item, target->name);
579 free_xml(remove);
580 }
581 free(replace_item);
582 }
583 last = lpc + 1;
584 }
585 }
588 }
589
590 copy_in_properties(target, update);
591
592 if (xml_acl_denied(target)) {
593 crm_notice("Cannot update <%s " XML_ATTR_ID "=%s>",
594 pcmk__s(object_name, "<null>"),
595 pcmk__s(object_id, "<null>"));
596 return -EACCES;
597 }
598
599 crm_trace("Processing children of <%s%s%s%s>", object_name,
600 ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
601 pcmk__s(object_id, ""),
602 ((object_id == NULL)? "" : "'"));
603
604 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
605 a_child = pcmk__xml_next(a_child)) {
606 int tmp_result = 0;
607
608 crm_trace("Updating child <%s%s%s%s>", a_child->name,
609 ((ID(a_child) == NULL)? "" : " " XML_ATTR_ID "='"),
610 pcmk__s(ID(a_child), ""), ((ID(a_child) == NULL)? "" : "'"));
611
612 tmp_result = update_cib_object(target, a_child);
613
614 /* only the first error is likely to be interesting */
615 if (tmp_result != pcmk_ok) {
616 crm_err("Error updating child <%s%s%s%s>",
617 a_child->name,
618 ((ID(a_child) == NULL)? "" : " " XML_ATTR_ID "='"),
619 pcmk__s(ID(a_child), ""),
620 ((ID(a_child) == NULL)? "" : "'"));
621
622 if (result == pcmk_ok) {
623 result = tmp_result;
624 }
625 }
626 }
627
628 crm_trace("Finished handling update for <%s%s%s%s>", object_name,
629 ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
630 pcmk__s(object_id, ""),
631 ((object_id == NULL)? "" : "'"));
632
633 return result;
634}
635
636static int
637add_cib_object(xmlNode * parent, xmlNode * new_obj)
638{
639 const char *object_name = NULL;
640 const char *object_id = NULL;
641 xmlNode *equiv_node = NULL;
642
643 if ((parent == NULL) || (new_obj == NULL)) {
644 return -EINVAL;
645 }
646
647 object_name = (const char *) new_obj->name;
648 if (object_name == NULL) {
649 return -EINVAL;
650 }
651
652 object_id = ID(new_obj);
653
654 crm_trace("Processing creation of <%s%s%s%s>", object_name,
655 ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
656 pcmk__s(object_id, ""),
657 ((object_id == NULL)? "" : "'"));
658
659 if (object_id == NULL) {
660 equiv_node = find_xml_node(parent, object_name, FALSE);
661 } else {
662 equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
663 object_id);
664 }
665 if (equiv_node != NULL) {
666 return -EEXIST;
667 }
668
669 return update_cib_object(parent, new_obj);
670}
671
672static bool
673update_results(xmlNode *failed, xmlNode *target, const char *operation,
674 int return_code)
675{
676 xmlNode *xml_node = NULL;
677 bool was_error = false;
678 const char *error_msg = NULL;
679
680 if (return_code != pcmk_ok) {
681 error_msg = pcmk_strerror(return_code);
682
683 was_error = true;
684 xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
685 add_node_copy(xml_node, target);
686
689 (const char *) target->name);
690 crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
691 crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
692
693 crm_warn("Action %s failed: %s (cde=%d)",
694 operation, error_msg, return_code);
695 }
696
697 return was_error;
698}
699
700int
701cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
702 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
703{
704 xmlNode *failed = NULL;
705 int result = pcmk_ok;
706 xmlNode *update_section = NULL;
707
708 crm_trace("Processing %s for %s section",
709 op, pcmk__s(section, "unspecified"));
710 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
711 section = NULL;
712
713 } else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
714 section = NULL;
715
716 } else if (pcmk__xe_is(input, XML_TAG_CIB)) {
717 section = NULL;
718 }
719
720 CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
721
722 if (input == NULL) {
723 crm_err("Cannot perform modification with no data");
724 return -EINVAL;
725 }
726
727 if (section == NULL) {
728 return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
729 answer);
730 }
731
732 failed = create_xml_node(NULL, XML_TAG_FAILED);
733
734 update_section = pcmk_find_cib_element(*result_cib, section);
735 if (pcmk__xe_is(input, section)) {
736 xmlNode *a_child = NULL;
737
738 for (a_child = pcmk__xml_first_child(input); a_child != NULL;
739 a_child = pcmk__xml_next(a_child)) {
740 result = add_cib_object(update_section, a_child);
741 if (update_results(failed, a_child, op, result)) {
742 break;
743 }
744 }
745
746 } else {
747 result = add_cib_object(update_section, input);
748 update_results(failed, input, op, result);
749 }
750
751 if ((result == pcmk_ok) && (failed->children != NULL)) {
752 result = -EINVAL;
753 }
754
755 if (result != pcmk_ok) {
756 crm_log_xml_err(failed, "CIB Update failures");
757 *answer = failed;
758
759 } else {
760 free_xml(failed);
761 }
762
763 return result;
764}
765
766int
767cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
768 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
769{
770 const char *originator = NULL;
771
772 if (req != NULL) {
773 originator = crm_element_value(req, F_ORIG);
774 }
775
776 crm_trace("Processing \"%s\" event from %s%s",
777 op, originator,
778 (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
779
780 if (*result_cib != existing_cib) {
781 free_xml(*result_cib);
782 }
783 *result_cib = copy_xml(existing_cib);
784
785 return xml_apply_patchset(*result_cib, input, TRUE);
786}
787
788// @COMPAT: v1-only
789bool
790cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff)
791{
792 int lpc = 0, max = 0;
793 bool config_changes = false;
794 xmlXPathObject *xpathObj = NULL;
795 int format = 1;
796
797 CRM_ASSERT(diff != NULL);
798
799 if (*diff == NULL && last != NULL && next != NULL) {
800 *diff = diff_xml_object(last, next, FALSE);
801 }
802
803 if (*diff == NULL) {
804 goto done;
805 }
806
807 crm_element_value_int(*diff, PCMK_XA_FORMAT, &format);
808 CRM_LOG_ASSERT(format == 1);
809
810 xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
811 if (numXpathResults(xpathObj) > 0) {
812 config_changes = true;
813 goto done;
814 }
815 freeXpathObject(xpathObj);
816
817 /*
818 * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
819 * This always contains every field and would produce a false positive
820 * every time if the checked value existed
821 */
822 xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
823 max = numXpathResults(xpathObj);
824
825 for (lpc = 0; lpc < max; lpc++) {
826 xmlNode *top = getXpathResult(xpathObj, lpc);
827
828 if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
829 config_changes = true;
830 goto done;
831 }
833 config_changes = true;
834 goto done;
835 }
836
837 if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
838 config_changes = true;
839 goto done;
840 }
841 if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
842 config_changes = true;
843 goto done;
844 }
845 if (crm_element_value(top, "remote-clear-port") != NULL) {
846 config_changes = true;
847 goto done;
848 }
849 if (crm_element_value(top, "remote-tls-port") != NULL) {
850 config_changes = true;
851 goto done;
852 }
853 }
854
855 done:
856 freeXpathObject(xpathObj);
857 return config_changes;
858}
859
860int
861cib_process_xpath(const char *op, int options, const char *section,
862 const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
863 xmlNode **result_cib, xmlNode **answer)
864{
865 int lpc = 0;
866 int max = 0;
867 int rc = pcmk_ok;
868 bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
869
870 xmlXPathObjectPtr xpathObj = NULL;
871
872 crm_trace("Processing \"%s\" event", op);
873
874 if (is_query) {
875 xpathObj = xpath_search(existing_cib, section);
876 } else {
877 xpathObj = xpath_search(*result_cib, section);
878 }
879
880 max = numXpathResults(xpathObj);
881
882 if ((max < 1)
883 && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
884 crm_debug("%s was already removed", section);
885
886 } else if (max < 1) {
887 crm_debug("%s: %s does not exist", op, section);
888 rc = -ENXIO;
889
890 } else if (is_query) {
891 if (max > 1) {
892 *answer = create_xml_node(NULL, "xpath-query");
893 }
894 }
895
896 if (pcmk_is_set(options, cib_multiple)
897 && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
898 dedupXpathResults(xpathObj);
899 }
900
901 for (lpc = 0; lpc < max; lpc++) {
902 xmlChar *path = NULL;
903 xmlNode *match = getXpathResult(xpathObj, lpc);
904
905 if (match == NULL) {
906 continue;
907 }
908
909 path = xmlGetNodePath(match);
910 crm_debug("Processing %s op for %s with %s", op, section, path);
911 free(path);
912
913 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
914 if (match == *result_cib) {
915 /* Attempting to delete the whole "/cib" */
916 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
917 rc = -EINVAL;
918 break;
919 }
920
921 free_xml(match);
922 if ((options & cib_multiple) == 0) {
923 break;
924 }
925
926 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
927 if (update_xml_child(match, input) == FALSE) {
928 rc = -ENXIO;
929 } else if ((options & cib_multiple) == 0) {
930 break;
931 }
932
933 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
934 add_node_copy(match, input);
935 break;
936
937 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
938
939 if (options & cib_no_children) {
940 xmlNode *shallow = create_xml_node(*answer,
941 (const char *) match->name);
942
943 copy_in_properties(shallow, match);
944
945 if (*answer == NULL) {
946 *answer = shallow;
947 }
948
949 } else if (options & cib_xpath_address) {
950 char *path = NULL;
951 xmlNode *parent = match;
952
953 while (parent && parent->type == XML_ELEMENT_NODE) {
954 const char *id = crm_element_value(parent, XML_ATTR_ID);
955 char *new_path = NULL;
956
957 if (id) {
958 new_path = crm_strdup_printf("/%s[@" XML_ATTR_ID "='%s']"
959 "%s",
960 parent->name, id,
961 pcmk__s(path, ""));
962 } else {
963 new_path = crm_strdup_printf("/%s%s", parent->name,
964 pcmk__s(path, ""));
965 }
966 free(path);
967 path = new_path;
968 parent = parent->parent;
969 }
970 crm_trace("Got: %s", path);
971
972 if (*answer == NULL) {
973 *answer = create_xml_node(NULL, "xpath-query");
974 }
975 parent = create_xml_node(*answer, "xpath-query-path");
977 free(path);
978
979 } else if (*answer) {
980 add_node_copy(*answer, match);
981
982 } else {
983 *answer = match;
984 }
985
986 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
988 xmlNode *parent = match->parent;
989
990 free_xml(match);
991 if (input != NULL) {
993 }
994
995 if ((options & cib_multiple) == 0) {
996 break;
997 }
998 }
999 }
1000
1001 freeXpathObject(xpathObj);
1002 return rc;
1003}
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition acl.c:605
#define PCMK__CIB_REQUEST_SYNC_TO_ONE
Definition internal.h:20
#define PCMK__CIB_REQUEST_ABS_DELETE
Definition internal.h:31
#define F_CIB_SCHEMA_MAX
Definition internal.h:62
#define PCMK__CIB_REQUEST_SYNC_TO_ALL
Definition internal.h:19
#define PCMK__CIB_REQUEST_PRIMARY
Definition internal.h:18
#define PCMK__CIB_REQUEST_COMMIT_TRANSACT
Definition internal.h:34
#define PCMK__CIB_REQUEST_IS_PRIMARY
Definition internal.h:21
@ cib__op_attr_none
No special attributes.
Definition internal.h:79
@ cib__op_attr_transaction
Supported in a transaction.
Definition internal.h:85
@ cib__op_attr_privileged
Requires privileges.
Definition internal.h:81
@ cib__op_attr_local
Must only be processed locally.
Definition internal.h:82
@ cib__op_attr_replaces
Replaces CIB.
Definition internal.h:83
@ cib__op_attr_modifies
Modifies CIB.
Definition internal.h:80
@ cib__op_attr_writes_through
Writes to disk on success.
Definition internal.h:84
#define PCMK__CIB_REQUEST_SECONDARY
Definition internal.h:17
#define PCMK__CIB_REQUEST_QUERY
Definition internal.h:23
#define PCMK__CIB_REQUEST_REPLACE
Definition internal.h:28
#define PCMK__CIB_REQUEST_DELETE
Definition internal.h:26
#define PCMK__CIB_REQUEST_APPLY_PATCH
Definition internal.h:29
#define PCMK__CIB_REQUEST_BUMP
Definition internal.h:22
#define PCMK__CIB_REQUEST_CREATE
Definition internal.h:24
#define PCMK__CIB_REQUEST_NOOP
Definition internal.h:32
#define PCMK__CIB_REQUEST_MODIFY
Definition internal.h:25
#define PCMK__CIB_REQUEST_SHUTDOWN
Definition internal.h:33
@ cib__op_create
Definition internal.h:98
@ cib__op_is_primary
Definition internal.h:101
@ cib__op_primary
Definition internal.h:105
@ cib__op_sync_all
Definition internal.h:110
@ cib__op_delete
Definition internal.h:99
@ cib__op_commit_transact
Definition internal.h:97
@ cib__op_apply_patch
Definition internal.h:95
@ cib__op_bump
Definition internal.h:96
@ cib__op_erase
Definition internal.h:100
@ cib__op_abs_delete
Definition internal.h:94
@ cib__op_shutdown
Definition internal.h:109
@ cib__op_replace
Definition internal.h:107
@ cib__op_sync_one
Definition internal.h:111
@ cib__op_upgrade
Definition internal.h:112
@ cib__op_query
Definition internal.h:106
@ cib__op_noop
Definition internal.h:103
@ cib__op_modify
Definition internal.h:102
@ cib__op_ping
Definition internal.h:104
@ cib__op_secondary
Definition internal.h:108
#define PCMK__CIB_REQUEST_UPGRADE
Definition internal.h:30
#define PCMK__CIB_REQUEST_ERASE
Definition internal.h:27
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition cib_utils.c:44
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition cib_utils.c:238
const char * parent
Definition cib.c:27
const char * path
Definition cib.c:28
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:421
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:861
int cib__get_operation(const char *op, const cib__operation_t **operation)
Definition cib_ops.c:142
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:166
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:456
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:701
bool cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff)
Definition cib_ops.c:790
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:294
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:309
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:767
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:259
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:240
@ cib_no_children
Definition cib_types.h:60
@ cib_force_diff
Definition cib_types.h:120
@ cib_xpath
Definition cib_types.h:56
@ cib_mixed_update
Definition cib_types.h:64
@ cib_verbose
Prefer stderr to logs.
Definition cib_types.h:55
@ cib_can_create
Definition cib_types.h:58
@ cib_multiple
Definition cib_types.h:57
@ cib_xpath_address
Definition cib_types.h:61
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:150
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition cib.c:172
#define PCMK__NELEM(a)
Definition internal.h:46
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:99
A dumping ground.
#define CRM_FEATURE_SET
Definition crm.h:70
#define CRM_OP_PING
Definition crm.h:133
#define crm_info(fmt, args...)
Definition logging.h:382
#define crm_warn(fmt, args...)
Definition logging.h:380
#define CRM_LOG_ASSERT(expr)
Definition logging.h:222
#define crm_log_xml_err(xml, text)
Definition logging.h:388
#define crm_notice(fmt, args...)
Definition logging.h:381
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_err(fmt, args...)
Definition logging.h:379
#define crm_log_xml_trace(xml, text)
Definition logging.h:393
#define crm_trace(fmt, args...)
Definition logging.h:385
#define XML_TAG_CIB
Definition msg_xml.h:137
#define ID(x)
Definition msg_xml.h:474
#define XML_ATTR_CRM_VERSION
Definition msg_xml.h:140
#define PCMK_XA_FORMAT
Definition msg_xml.h:51
#define XML_TAG_DIFF_REMOVED
Definition msg_xml.h:426
#define XML_CIB_ATTR_REPLACE
Definition msg_xml.h:284
#define XML_TAG_FAILED
Definition msg_xml.h:138
#define XML_FAILCIB_ATTR_OBJTYPE
Definition msg_xml.h:197
#define XML_FAILCIB_ATTR_ID
Definition msg_xml.h:196
#define XML_CIB_TAG_SECTION_ALL
Definition msg_xml.h:202
#define XML_ATTR_ID
Definition msg_xml.h:156
#define F_ORIG
Definition msg_xml.h:79
#define XML_CIB_TAG_CONFIGURATION
Definition msg_xml.h:203
#define XML_ATTR_VALIDATION
Definition msg_xml.h:142
#define XML_ATTR_GENERATION_ADMIN
Definition msg_xml.h:148
#define XML_ATTR_NUMUPDATES
Definition msg_xml.h:149
#define XML_FAIL_TAG_CIB
Definition msg_xml.h:194
#define XML_FAILCIB_ATTR_OP
Definition msg_xml.h:198
#define XML_ATTR_GENERATION
Definition msg_xml.h:147
#define XML_ATTR_DIGEST
Definition msg_xml.h:141
#define XML_FAILCIB_ATTR_REASON
Definition msg_xml.h:199
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:483
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:644
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:302
pcmk__action_result_t result
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
const char * pcmk_strerror(int rc)
Definition results.c:149
#define pcmk_err_old_data
Definition results.h:75
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:154
#define pcmk_ok
Definition results.h:68
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:608
@ pcmk__str_none
@ pcmk__str_casei
const char * name
Definition internal.h:124
Wrappers for and extensions to libxml2.
gboolean update_xml_child(xmlNode *child, xmlNode *to_update)
Definition xml.c:2307
int get_schema_version(const char *name)
Definition schemas.c:967
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
Definition xml.c:2374
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:984
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition xpath.c:101
void copy_in_properties(xmlNode *target, const xmlNode *src)
Definition xml.c:456
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition xpath.c:58
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition patchset.c:1099
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:167
void free_xml(xmlNode *child)
Definition xml.c:783
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
Definition xml.c:384
xmlNode * diff_xml_object(xmlNode *left, xmlNode *right, gboolean suppress)
Definition patchset.c:1186
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition xml.c:622
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition xpath.c:139
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:789
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:638
void xml_remove_prop(xmlNode *obj, const char *name)
Definition xml.c:1696
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:429