root/lib/cib/cib_ops.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_process_query
  2. update_counter
  3. cib_process_erase
  4. cib_process_upgrade
  5. cib_process_bump
  6. cib_process_replace
  7. cib_process_delete
  8. cib_process_modify
  9. update_cib_object
  10. add_cib_object
  11. update_results
  12. cib_process_create
  13. cib_process_diff
  14. cib__config_changed_v1
  15. cib_process_xpath

   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 <crm/crm.h>
  23 #include <crm/cib/internal.h>
  24 #include <crm/msg_xml.h>
  25 
  26 #include <crm/common/xml.h>
  27 #include <crm/common/xml_internal.h>
  28 
  29 int
  30 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
  75 static int
  76 update_counter(xmlNode *xml_obj, const char *field, bool reset)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78     char *new_value = NULL;
  79     char *old_value = NULL;
  80     int int_value = -1;
  81 
  82     if (!reset && crm_element_value(xml_obj, field) != NULL) {
  83         old_value = crm_element_value_copy(xml_obj, field);
  84     }
  85     if (old_value != NULL) {
  86         int_value = atoi(old_value);
  87         new_value = pcmk__itoa(++int_value);
  88     } else {
  89         new_value = strdup("1");
  90         CRM_ASSERT(new_value != NULL);
  91     }
  92 
  93     crm_trace("Update %s from %s to %s",
  94               field, pcmk__s(old_value, "unset"), new_value);
  95     crm_xml_add(xml_obj, field, new_value);
  96 
  97     free(new_value);
  98     free(old_value);
  99 
 100     return pcmk_ok;
 101 }
 102 
 103 int
 104 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 105                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 106 {
 107     int result = pcmk_ok;
 108 
 109     crm_trace("Processing \"%s\" event", op);
 110     *answer = NULL;
 111     free_xml(*result_cib);
 112     *result_cib = createEmptyCib(0);
 113 
 114     copy_in_properties(*result_cib, existing_cib);
 115     update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, false);
 116 
 117     return result;
 118 }
 119 
 120 int
 121 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 122                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 123                     xmlNode ** answer)
 124 {
 125     int rc = 0;
 126     int new_version = 0;
 127     int current_version = 0;
 128     int max_version = 0;
 129     const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
 130     const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 131 
 132     *answer = NULL;
 133     crm_trace("Processing \"%s\" event with max=%s", op, max);
 134 
 135     if (value != NULL) {
 136         current_version = get_schema_version(value);
 137     }
 138 
 139     if (max) {
 140         max_version = get_schema_version(max);
 141     }
 142 
 143     rc = update_validation(result_cib, &new_version, max_version, TRUE,
 144                            !(options & cib_verbose));
 145     if (new_version > current_version) {
 146         update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, false);
 147         update_counter(*result_cib, XML_ATTR_GENERATION, true);
 148         update_counter(*result_cib, XML_ATTR_NUMUPDATES, true);
 149         return pcmk_ok;
 150     }
 151 
 152     return rc;
 153 }
 154 
 155 int
 156 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 157                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 158 {
 159     int result = pcmk_ok;
 160 
 161     crm_trace("Processing %s for epoch='%s'", op,
 162               pcmk__s(crm_element_value(existing_cib, XML_ATTR_GENERATION), ""));
 163 
 164     *answer = NULL;
 165     update_counter(*result_cib, XML_ATTR_GENERATION, false);
 166 
 167     return result;
 168 }
 169 
 170 int
 171 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
 215             const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
 216             char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
 217                                                                  version ? version :
 218                                                                  CRM_FEATURE_SET);
 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) {
 238             reason = XML_ATTR_GENERATION_ADMIN;
 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);
 258             result = -pcmk_err_old_data;
 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 
 283 int
 284 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 318 int
 319 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 386 static int
 387 update_cib_object(xmlNode * parent, xmlNode * update)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)? "" : " " XML_ATTR_ID "='"),
 405               pcmk__s(object_id, ""),
 406               ((object_id == NULL)? "" : "'"));
 407 
 408     if (object_id == NULL) {
 409         /*  placeholder object */
 410         target = find_xml_node(parent, object_name, FALSE);
 411 
 412     } else {
 413         target = pcmk__xe_match(parent, object_name, XML_ATTR_ID, object_id);
 414     }
 415 
 416     if (target == NULL) {
 417         target = create_xml_node(parent, object_name);
 418     }
 419 
 420     crm_trace("Found node <%s%s%s%s> to update", object_name,
 421               ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
 422               pcmk__s(object_id, ""),
 423               ((object_id == NULL)? "" : "'"));
 424 
 425     // @COMPAT: XML_CIB_ATTR_REPLACE is unused internally. Remove at break.
 426     replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
 427     if (replace != NULL) {
 428         xmlNode *remove = NULL;
 429         int last = 0, lpc = 0, len = 0;
 430 
 431         len = strlen(replace);
 432         while (lpc <= len) {
 433             if (replace[lpc] == ',' || replace[lpc] == 0) {
 434                 char *replace_item = NULL;
 435 
 436                 if (last == lpc) {
 437                     /* nothing to do */
 438                     last = lpc + 1;
 439                     goto incr;
 440                 }
 441 
 442                 replace_item = strndup(replace + last, lpc - last);
 443                 remove = find_xml_node(target, replace_item, FALSE);
 444                 if (remove != NULL) {
 445                     crm_trace("Replacing node <%s> in <%s>",
 446                               replace_item, crm_element_name(target));
 447                     free_xml(remove);
 448                     remove = NULL;
 449                 }
 450                 free(replace_item);
 451                 last = lpc + 1;
 452             }
 453   incr:
 454             lpc++;
 455         }
 456         xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
 457         xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
 458     }
 459 
 460     copy_in_properties(target, update);
 461 
 462     if (xml_acl_denied(target)) {
 463         crm_notice("Cannot update <%s " XML_ATTR_ID "=%s>",
 464                    pcmk__s(object_name, "<null>"),
 465                    pcmk__s(object_id, "<null>"));
 466         return -EACCES;
 467     }
 468 
 469     crm_trace("Processing children of <%s%s%s%s>", object_name,
 470               ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
 471               pcmk__s(object_id, ""),
 472               ((object_id == NULL)? "" : "'"));
 473 
 474     for (a_child = pcmk__xml_first_child(update); a_child != NULL;
 475          a_child = pcmk__xml_next(a_child)) {
 476         int tmp_result = 0;
 477 
 478         crm_trace("Updating child <%s%s%s%s>", crm_element_name(a_child),
 479                   ((ID(a_child) == NULL)? "" : " " XML_ATTR_ID "='"),
 480                   pcmk__s(ID(a_child), ""), ((ID(a_child) == NULL)? "" : "'"));
 481 
 482         tmp_result = update_cib_object(target, a_child);
 483 
 484         /*  only the first error is likely to be interesting */
 485         if (tmp_result != pcmk_ok) {
 486             crm_err("Error updating child <%s%s%s%s>",
 487                     crm_element_name(a_child),
 488                     ((ID(a_child) == NULL)? "" : " " XML_ATTR_ID "='"),
 489                     pcmk__s(ID(a_child), ""),
 490                     ((ID(a_child) == NULL)? "" : "'"));
 491 
 492             if (result == pcmk_ok) {
 493                 result = tmp_result;
 494             }
 495         }
 496     }
 497 
 498     crm_trace("Finished handling update for <%s%s%s%s>", object_name,
 499               ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
 500               pcmk__s(object_id, ""),
 501               ((object_id == NULL)? "" : "'"));
 502 
 503     return result;
 504 }
 505 
 506 static int
 507 add_cib_object(xmlNode * parent, xmlNode * new_obj)
     /* [previous][next][first][last][top][bottom][index][help] */
 508 {
 509     const char *object_name = NULL;
 510     const char *object_id = NULL;
 511     xmlNode *equiv_node = NULL;
 512 
 513     if ((parent == NULL) || (new_obj == NULL)) {
 514         return -EINVAL;
 515     }
 516 
 517     object_name = crm_element_name(new_obj);
 518     if (object_name == NULL) {
 519         return -EINVAL;
 520     }
 521 
 522     object_id = ID(new_obj);
 523 
 524     crm_trace("Processing creation of <%s%s%s%s>", object_name,
 525               ((object_id == NULL)? "" : " " XML_ATTR_ID "='"),
 526               pcmk__s(object_id, ""),
 527               ((object_id == NULL)? "" : "'"));
 528 
 529     if (object_id == NULL) {
 530         equiv_node = find_xml_node(parent, object_name, FALSE);
 531     } else {
 532         equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
 533                                     object_id);
 534     }
 535     if (equiv_node != NULL) {
 536         return -EEXIST;
 537     }
 538 
 539     return update_cib_object(parent, new_obj);
 540 }
 541 
 542 static bool
 543 update_results(xmlNode *failed, xmlNode *target, const char *operation,
     /* [previous][next][first][last][top][bottom][index][help] */
 544                int return_code)
 545 {
 546     xmlNode *xml_node = NULL;
 547     bool was_error = false;
 548     const char *error_msg = NULL;
 549 
 550     if (return_code != pcmk_ok) {
 551         error_msg = pcmk_strerror(return_code);
 552 
 553         was_error = true;
 554         xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
 555         add_node_copy(xml_node, target);
 556 
 557         crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
 558         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
 559         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
 560         crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
 561 
 562         crm_warn("Action %s failed: %s (cde=%d)",
 563                  operation, error_msg, return_code);
 564     }
 565 
 566     return was_error;
 567 }
 568 
 569 int
 570 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 571                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 572 {
 573     xmlNode *failed = NULL;
 574     int result = pcmk_ok;
 575     xmlNode *update_section = NULL;
 576 
 577     crm_trace("Processing %s for %s section",
 578               op, pcmk__s(section, "unspecified"));
 579     if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
 580         section = NULL;
 581 
 582     } else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
 583         section = NULL;
 584 
 585     } else if (pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
 586         section = NULL;
 587     }
 588 
 589     CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
 590 
 591     if (input == NULL) {
 592         crm_err("Cannot perform modification with no data");
 593         return -EINVAL;
 594     }
 595 
 596     if (section == NULL) {
 597         return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
 598                                   answer);
 599     }
 600 
 601     failed = create_xml_node(NULL, XML_TAG_FAILED);
 602 
 603     update_section = pcmk_find_cib_element(*result_cib, section);
 604     if (pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
 605         xmlNode *a_child = NULL;
 606 
 607         for (a_child = pcmk__xml_first_child(input); a_child != NULL;
 608              a_child = pcmk__xml_next(a_child)) {
 609             result = add_cib_object(update_section, a_child);
 610             if (update_results(failed, a_child, op, result)) {
 611                 break;
 612             }
 613         }
 614 
 615     } else {
 616         result = add_cib_object(update_section, input);
 617         update_results(failed, input, op, result);
 618     }
 619 
 620     if ((result == pcmk_ok) && xml_has_children(failed)) {
 621         result = -EINVAL;
 622     }
 623 
 624     if (result != pcmk_ok) {
 625         crm_log_xml_err(failed, "CIB Update failures");
 626         *answer = failed;
 627 
 628     } else {
 629         free_xml(failed);
 630     }
 631 
 632     return result;
 633 }
 634 
 635 int
 636 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 637                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 638 {
 639     const char *originator = NULL;
 640 
 641     if (req != NULL) {
 642         originator = crm_element_value(req, F_ORIG);
 643     }
 644 
 645     crm_trace("Processing \"%s\" event from %s%s",
 646               op, originator,
 647               (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
 648 
 649     free_xml(*result_cib);
 650     *result_cib = copy_xml(existing_cib);
 651     return xml_apply_patchset(*result_cib, input, TRUE);
 652 }
 653 
 654 // @COMPAT: v1-only
 655 bool
 656 cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff)
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658     int lpc = 0, max = 0;
 659     bool config_changes = false;
 660     xmlXPathObject *xpathObj = NULL;
 661     int format = 1;
 662 
 663     CRM_ASSERT(diff != NULL);
 664 
 665     if (*diff == NULL && last != NULL && next != NULL) {
 666         *diff = diff_xml_object(last, next, FALSE);
 667     }
 668 
 669     if (*diff == NULL) {
 670         goto done;
 671     }
 672 
 673     crm_element_value_int(*diff, "format", &format);
 674     CRM_LOG_ASSERT(format == 1);
 675 
 676     xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
 677     if (numXpathResults(xpathObj) > 0) {
 678         config_changes = true;
 679         goto done;
 680     }
 681     freeXpathObject(xpathObj);
 682 
 683     /*
 684      * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
 685      * This always contains every field and would produce a false positive
 686      * every time if the checked value existed
 687      */
 688     xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
 689     max = numXpathResults(xpathObj);
 690 
 691     for (lpc = 0; lpc < max; lpc++) {
 692         xmlNode *top = getXpathResult(xpathObj, lpc);
 693 
 694         if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
 695             config_changes = true;
 696             goto done;
 697         }
 698         if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
 699             config_changes = true;
 700             goto done;
 701         }
 702 
 703         if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
 704             config_changes = true;
 705             goto done;
 706         }
 707         if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
 708             config_changes = true;
 709             goto done;
 710         }
 711         if (crm_element_value(top, "remote-clear-port") != NULL) {
 712             config_changes = true;
 713             goto done;
 714         }
 715         if (crm_element_value(top, "remote-tls-port") != NULL) {
 716             config_changes = true;
 717             goto done;
 718         }
 719     }
 720 
 721   done:
 722     freeXpathObject(xpathObj);
 723     return config_changes;
 724 }
 725 
 726 int
 727 cib_process_xpath(const char *op, int options, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 728                   const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
 729                   xmlNode **result_cib, xmlNode **answer)
 730 {
 731     int lpc = 0;
 732     int max = 0;
 733     int rc = pcmk_ok;
 734     bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
 735 
 736     xmlXPathObjectPtr xpathObj = NULL;
 737 
 738     crm_trace("Processing \"%s\" event", op);
 739 
 740     if (is_query) {
 741         xpathObj = xpath_search(existing_cib, section);
 742     } else {
 743         xpathObj = xpath_search(*result_cib, section);
 744     }
 745 
 746     max = numXpathResults(xpathObj);
 747 
 748     if ((max < 1)
 749         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 750         crm_debug("%s was already removed", section);
 751 
 752     } else if (max < 1) {
 753         crm_debug("%s: %s does not exist", op, section);
 754         rc = -ENXIO;
 755 
 756     } else if (is_query) {
 757         if (max > 1) {
 758             *answer = create_xml_node(NULL, "xpath-query");
 759         }
 760     }
 761 
 762     if (pcmk_is_set(options, cib_multiple)
 763         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 764         dedupXpathResults(xpathObj);
 765     }
 766 
 767     for (lpc = 0; lpc < max; lpc++) {
 768         xmlChar *path = NULL;
 769         xmlNode *match = getXpathResult(xpathObj, lpc);
 770 
 771         if (match == NULL) {
 772             continue;
 773         }
 774 
 775         path = xmlGetNodePath(match);
 776         crm_debug("Processing %s op for %s with %s", op, section, path);
 777         free(path);
 778 
 779         if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 780             if (match == *result_cib) {
 781                 /* Attempting to delete the whole "/cib" */
 782                 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
 783                 rc = -EINVAL;
 784                 break;
 785             }
 786 
 787             free_xml(match);
 788             if ((options & cib_multiple) == 0) {
 789                 break;
 790             }
 791 
 792         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
 793             if (update_xml_child(match, input) == FALSE) {
 794                 rc = -ENXIO;
 795             } else if ((options & cib_multiple) == 0) {
 796                 break;
 797             }
 798 
 799         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
 800             add_node_copy(match, input);
 801             break;
 802 
 803         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
 804 
 805             if (options & cib_no_children) {
 806                 const char *tag = TYPE(match);
 807                 xmlNode *shallow = create_xml_node(*answer, tag);
 808 
 809                 copy_in_properties(shallow, match);
 810 
 811                 if (*answer == NULL) {
 812                     *answer = shallow;
 813                 }
 814 
 815             } else if (options & cib_xpath_address) {
 816                 char *path = NULL;
 817                 xmlNode *parent = match;
 818 
 819                 while (parent && parent->type == XML_ELEMENT_NODE) {
 820                     const char *id = crm_element_value(parent, XML_ATTR_ID);
 821                     char *new_path = NULL;
 822 
 823                     if (id) {
 824                         new_path = crm_strdup_printf("/%s[@" XML_ATTR_ID "='%s']"
 825                                                      "%s",
 826                                                      parent->name, id,
 827                                                      pcmk__s(path, ""));
 828                     } else {
 829                         new_path = crm_strdup_printf("/%s%s", parent->name,
 830                                                      pcmk__s(path, ""));
 831                     }
 832                     free(path);
 833                     path = new_path;
 834                     parent = parent->parent;
 835                 }
 836                 crm_trace("Got: %s", path);
 837 
 838                 if (*answer == NULL) {
 839                     *answer = create_xml_node(NULL, "xpath-query");
 840                 }
 841                 parent = create_xml_node(*answer, "xpath-query-path");
 842                 crm_xml_add(parent, XML_ATTR_ID, path);
 843                 free(path);
 844 
 845             } else if (*answer) {
 846                 add_node_copy(*answer, match);
 847 
 848             } else {
 849                 *answer = match;
 850             }
 851 
 852         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
 853                                 pcmk__str_none)) {
 854             xmlNode *parent = match->parent;
 855 
 856             free_xml(match);
 857             if (input != NULL) {
 858                 add_node_copy(parent, input);
 859             }
 860 
 861             if ((options & cib_multiple) == 0) {
 862                 break;
 863             }
 864         }
 865     }
 866 
 867     freeXpathObject(xpathObj);
 868     return rc;
 869 }

/* [previous][next][first][last][top][bottom][index][help] */