root/lib/cib/cib_utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_get_generation
  2. cib_version_details
  3. cib_diff_version_details
  4. get_object_path
  5. get_object_parent
  6. get_object_root
  7. createEmptyCib
  8. cib_acl_enabled
  9. cib_perform_op
  10. cib_create_op
  11. cib_native_callback
  12. cib_native_notify
  13. cib_metadata
  14. verify_cib_options
  15. cib_pref
  16. cib_read_config
  17. cib_internal_config_changed
  18. cib_internal_op
  19. cib_apply_patch_event
  20. cib__signon_query

   1 /*
   2  * Original copyright 2004 International Business Machines
   3  * Later changes copyright 2008-2021 the Pacemaker project contributors
   4  *
   5  * The version control history for this file may have further details.
   6  *
   7  * This source code is licensed under the GNU Lesser General Public License
   8  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   9  */
  10 #include <crm_internal.h>
  11 #include <unistd.h>
  12 #include <stdlib.h>
  13 #include <stdio.h>
  14 #include <stdarg.h>
  15 #include <string.h>
  16 #include <sys/utsname.h>
  17 
  18 #include <glib.h>
  19 
  20 #include <crm/crm.h>
  21 #include <crm/cib/internal.h>
  22 #include <crm/msg_xml.h>
  23 #include <crm/common/xml.h>
  24 #include <crm/common/xml_internal.h>
  25 #include <crm/pengine/rules.h>
  26 
  27 struct config_root_s {
  28     const char *name;
  29     const char *parent;
  30     const char *path;
  31 };
  32 
  33  /*
  34   * "//crm_config" will also work in place of "/cib/configuration/crm_config"
  35   * The / prefix means find starting from the root, whereas the // prefix means
  36   * find anywhere and risks multiple matches
  37   */
  38 /* *INDENT-OFF* */
  39 static struct config_root_s known_paths[] = {
  40     { NULL,                         NULL,                 "//cib" },
  41     { XML_TAG_CIB,                  NULL,                 "//cib" },
  42     { XML_CIB_TAG_STATUS,           "/cib",               "//cib/status" },
  43     { XML_CIB_TAG_CONFIGURATION,    "/cib",               "//cib/configuration" },
  44     { XML_CIB_TAG_CRMCONFIG,        "/cib/configuration", "//cib/configuration/crm_config" },
  45     { XML_CIB_TAG_NODES,            "/cib/configuration", "//cib/configuration/nodes" },
  46     { XML_CIB_TAG_RESOURCES,        "/cib/configuration", "//cib/configuration/resources" },
  47     { XML_CIB_TAG_CONSTRAINTS,      "/cib/configuration", "//cib/configuration/constraints" },
  48     { XML_CIB_TAG_OPCONFIG,         "/cib/configuration", "//cib/configuration/op_defaults" },
  49     { XML_CIB_TAG_RSCCONFIG,        "/cib/configuration", "//cib/configuration/rsc_defaults" },
  50     { XML_CIB_TAG_ACLS,             "/cib/configuration", "//cib/configuration/acls" },
  51     { XML_TAG_FENCING_TOPOLOGY,     "/cib/configuration", "//cib/configuration/fencing-topology" },
  52     { XML_CIB_TAG_TAGS,             "/cib/configuration", "//cib/configuration/tags" },
  53     { XML_CIB_TAG_ALERTS,           "/cib/configuration", "//cib/configuration/alerts" },
  54     { XML_CIB_TAG_SECTION_ALL,      NULL,                 "//cib" },
  55 };
  56 /* *INDENT-ON* */
  57 
  58 xmlNode *
  59 cib_get_generation(cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     xmlNode *the_cib = NULL;
  62     xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
  63 
  64     cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
  65     if (the_cib != NULL) {
  66         copy_in_properties(generation, the_cib);
  67         free_xml(the_cib);
  68     }
  69 
  70     return generation;
  71 }
  72 
  73 gboolean
  74 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76     *epoch = -1;
  77     *updates = -1;
  78     *admin_epoch = -1;
  79 
  80     if (cib == NULL) {
  81         return FALSE;
  82 
  83     } else {
  84         crm_element_value_int(cib, XML_ATTR_GENERATION, epoch);
  85         crm_element_value_int(cib, XML_ATTR_NUMUPDATES, updates);
  86         crm_element_value_int(cib, XML_ATTR_GENERATION_ADMIN, admin_epoch);
  87     }
  88     return TRUE;
  89 }
  90 
  91 gboolean
  92 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
     /* [previous][next][first][last][top][bottom][index][help] */
  93                          int *_admin_epoch, int *_epoch, int *_updates)
  94 {
  95     int add[] = { 0, 0, 0 };
  96     int del[] = { 0, 0, 0 };
  97 
  98     xml_patch_versions(diff, add, del);
  99 
 100     *admin_epoch = add[0];
 101     *epoch = add[1];
 102     *updates = add[2];
 103 
 104     *_admin_epoch = del[0];
 105     *_epoch = del[1];
 106     *_updates = del[2];
 107 
 108     return TRUE;
 109 }
 110 
 111 /*
 112  * The caller should never free the return value
 113  */
 114 
 115 const char *
 116 get_object_path(const char *object_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118     int lpc = 0;
 119     int max = PCMK__NELEM(known_paths);
 120 
 121     for (; lpc < max; lpc++) {
 122         if ((object_type == NULL && known_paths[lpc].name == NULL)
 123             || pcmk__str_eq(object_type, known_paths[lpc].name, pcmk__str_casei)) {
 124             return known_paths[lpc].path;
 125         }
 126     }
 127     return NULL;
 128 }
 129 
 130 const char *
 131 get_object_parent(const char *object_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     int lpc = 0;
 134     int max = PCMK__NELEM(known_paths);
 135 
 136     for (; lpc < max; lpc++) {
 137         if (pcmk__str_eq(object_type, known_paths[lpc].name, pcmk__str_casei)) {
 138             return known_paths[lpc].parent;
 139         }
 140     }
 141     return NULL;
 142 }
 143 
 144 xmlNode *
 145 get_object_root(const char *object_type, xmlNode * the_root)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147     const char *xpath = get_object_path(object_type);
 148 
 149     if (xpath == NULL) {
 150         return the_root;        /* or return NULL? */
 151     }
 152 
 153     return get_xpath_object(xpath, the_root, LOG_TRACE);
 154 }
 155 
 156 /*!
 157  * \brief Create XML for a new (empty) CIB
 158  *
 159  * \param[in] cib_epoch   What to use as "epoch" CIB property
 160  *
 161  * \return Newly created XML for empty CIB
 162  * \note It is the caller's responsibility to free the result with free_xml().
 163  */
 164 xmlNode *
 165 createEmptyCib(int cib_epoch)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     xmlNode *cib_root = NULL, *config = NULL;
 168 
 169     cib_root = create_xml_node(NULL, XML_TAG_CIB);
 170     crm_xml_add(cib_root, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 171     crm_xml_add(cib_root, XML_ATTR_VALIDATION, xml_latest_schema());
 172 
 173     crm_xml_add_int(cib_root, XML_ATTR_GENERATION, cib_epoch);
 174     crm_xml_add_int(cib_root, XML_ATTR_NUMUPDATES, 0);
 175     crm_xml_add_int(cib_root, XML_ATTR_GENERATION_ADMIN, 0);
 176 
 177     config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
 178     create_xml_node(cib_root, XML_CIB_TAG_STATUS);
 179 
 180     create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
 181     create_xml_node(config, XML_CIB_TAG_NODES);
 182     create_xml_node(config, XML_CIB_TAG_RESOURCES);
 183     create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
 184 
 185 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
 186     {
 187         xmlNode *rsc_defaults = create_xml_node(config, XML_CIB_TAG_RSCCONFIG);
 188         xmlNode *meta = create_xml_node(rsc_defaults, XML_TAG_META_SETS);
 189         xmlNode *nvpair = create_xml_node(meta, XML_CIB_TAG_NVPAIR);
 190 
 191         crm_xml_add(meta, XML_ATTR_ID, "build-resource-defaults");
 192         crm_xml_add(nvpair, XML_ATTR_ID, "build-" XML_RSC_ATTR_STICKINESS);
 193         crm_xml_add(nvpair, XML_NVPAIR_ATTR_NAME, XML_RSC_ATTR_STICKINESS);
 194         crm_xml_add_int(nvpair, XML_NVPAIR_ATTR_VALUE,
 195                         PCMK__RESOURCE_STICKINESS_DEFAULT);
 196     }
 197 #endif
 198     return cib_root;
 199 }
 200 
 201 static bool
 202 cib_acl_enabled(xmlNode *xml, const char *user)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204     bool rc = FALSE;
 205 
 206     if(pcmk_acl_required(user)) {
 207         const char *value = NULL;
 208         GHashTable *options = pcmk__strkey_table(free, free);
 209 
 210         cib_read_config(options, xml);
 211         value = cib_pref(options, "enable-acl");
 212         rc = crm_is_true(value);
 213         g_hash_table_destroy(options);
 214     }
 215 
 216     crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
 217     return rc;
 218 }
 219 
 220 int
 221 cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
     /* [previous][next][first][last][top][bottom][index][help] */
 222                const char *section, xmlNode * req, xmlNode * input,
 223                gboolean manage_counters, gboolean * config_changed,
 224                xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
 225 {
 226     int rc = pcmk_ok;
 227     gboolean check_schema = TRUE;
 228     xmlNode *top = NULL;
 229     xmlNode *scratch = NULL;
 230     xmlNode *local_diff = NULL;
 231 
 232     const char *new_version = NULL;
 233     static struct qb_log_callsite *diff_cs = NULL;
 234     const char *user = crm_element_value(req, F_CIB_USER);
 235     bool with_digest = FALSE;
 236 
 237     crm_trace("Begin %s%s%s op",
 238               (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
 239               (is_query? "read-only " : ""), op);
 240 
 241     CRM_CHECK(output != NULL, return -ENOMSG);
 242     CRM_CHECK(result_cib != NULL, return -ENOMSG);
 243     CRM_CHECK(config_changed != NULL, return -ENOMSG);
 244 
 245     if(output) {
 246         *output = NULL;
 247     }
 248 
 249     *result_cib = NULL;
 250     *config_changed = FALSE;
 251 
 252     if (fn == NULL) {
 253         return -EINVAL;
 254     }
 255 
 256     if (is_query) {
 257         xmlNode *cib_ro = current_cib;
 258         xmlNode *cib_filtered = NULL;
 259 
 260         if(cib_acl_enabled(cib_ro, user)) {
 261             if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
 262                 if (cib_filtered == NULL) {
 263                     crm_debug("Pre-filtered the entire cib");
 264                     return -EACCES;
 265                 }
 266                 cib_ro = cib_filtered;
 267                 crm_log_xml_trace(cib_ro, "filtered");
 268             }
 269         }
 270 
 271         rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
 272 
 273         if(output == NULL || *output == NULL) {
 274             /* nothing */
 275 
 276         } else if(cib_filtered == *output) {
 277             cib_filtered = NULL; /* Let them have this copy */
 278 
 279         } else if(*output == current_cib) {
 280             /* They already know not to free it */
 281 
 282         } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
 283             /* We're about to free the document of which *output is a part */
 284             *output = copy_xml(*output);
 285 
 286         } else if((*output)->doc == current_cib->doc) {
 287             /* Give them a copy they can free */
 288             *output = copy_xml(*output);
 289         }
 290 
 291         free_xml(cib_filtered);
 292         return rc;
 293     }
 294 
 295 
 296     if (pcmk_is_set(call_options, cib_zero_copy)) {
 297         /* Conditional on v2 patch style */
 298 
 299         scratch = current_cib;
 300 
 301         /* Create a shallow copy of current_cib for the version details */
 302         current_cib = create_xml_node(NULL, (const char *)scratch->name);
 303         copy_in_properties(current_cib, scratch);
 304         top = current_cib;
 305 
 306         xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
 307         rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
 308 
 309     } else {
 310         scratch = copy_xml(current_cib);
 311         xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
 312         rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
 313 
 314         if(scratch && xml_tracking_changes(scratch) == FALSE) {
 315             crm_trace("Inferring changes after %s op", op);
 316             xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
 317             xml_calculate_changes(current_cib, scratch);
 318         }
 319         CRM_CHECK(current_cib != scratch, return -EINVAL);
 320     }
 321 
 322     xml_acl_disable(scratch); /* Allow the system to make any additional changes */
 323 
 324     if (rc == pcmk_ok && scratch == NULL) {
 325         rc = -EINVAL;
 326         goto done;
 327 
 328     } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
 329         crm_trace("ACL rejected part or all of the proposed changes");
 330         rc = -EACCES;
 331         goto done;
 332 
 333     } else if (rc != pcmk_ok) {
 334         goto done;
 335     }
 336 
 337     if (scratch) {
 338         new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
 339 
 340         if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
 341             crm_err("Discarding update with feature set '%s' greater than our own '%s'",
 342                     new_version, CRM_FEATURE_SET);
 343             rc = -EPROTONOSUPPORT;
 344             goto done;
 345         }
 346     }
 347 
 348     if (current_cib) {
 349         int old = 0;
 350         int new = 0;
 351 
 352         crm_element_value_int(scratch, XML_ATTR_GENERATION_ADMIN, &new);
 353         crm_element_value_int(current_cib, XML_ATTR_GENERATION_ADMIN, &old);
 354 
 355         if (old > new) {
 356             crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
 357                     XML_ATTR_GENERATION_ADMIN, old, new, call_options);
 358             crm_log_xml_warn(req, "Bad Op");
 359             crm_log_xml_warn(input, "Bad Data");
 360             rc = -pcmk_err_old_data;
 361 
 362         } else if (old == new) {
 363             crm_element_value_int(scratch, XML_ATTR_GENERATION, &new);
 364             crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
 365             if (old > new) {
 366                 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
 367                         XML_ATTR_GENERATION, old, new, call_options);
 368                 crm_log_xml_warn(req, "Bad Op");
 369                 crm_log_xml_warn(input, "Bad Data");
 370                 rc = -pcmk_err_old_data;
 371             }
 372         }
 373     }
 374 
 375     crm_trace("Massaging CIB contents");
 376     pcmk__strip_xml_text(scratch);
 377     fix_plus_plus_recursive(scratch);
 378 
 379     if (pcmk_is_set(call_options, cib_zero_copy)) {
 380         /* At this point, current_cib is just the 'cib' tag and its properties,
 381          *
 382          * The v1 format would barf on this, but we know the v2 patch
 383          * format only needs it for the top-level version fields
 384          */
 385         local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters);
 386 
 387     } else {
 388         static time_t expires = 0;
 389         time_t tm_now = time(NULL);
 390 
 391         if (expires < tm_now) {
 392             expires = tm_now + 60;  /* Validate clients are correctly applying v2-style diffs at most once a minute */
 393             with_digest = TRUE;
 394         }
 395 
 396         local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters);
 397     }
 398 
 399     xml_log_changes(LOG_TRACE, __func__, scratch);
 400     xml_accept_changes(scratch);
 401 
 402     if (diff_cs == NULL) {
 403         diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__, "diff-validation", LOG_DEBUG, __LINE__, crm_trace_nonlog);
 404     }
 405 
 406     if(local_diff) {
 407         patchset_process_digest(local_diff, current_cib, scratch, with_digest);
 408 
 409         xml_log_patchset(LOG_INFO, __func__, local_diff);
 410         crm_log_xml_trace(local_diff, "raw patch");
 411     }
 412 
 413     if (!pcmk_is_set(call_options, cib_zero_copy) // Original to compare against doesn't exist
 414         && local_diff
 415         && crm_is_callsite_active(diff_cs, LOG_TRACE, 0)) {
 416 
 417         /* Validate the calculated patch set */
 418         int test_rc, format = 1;
 419         xmlNode * c = copy_xml(current_cib);
 420 
 421         crm_element_value_int(local_diff, "format", &format);
 422         test_rc = xml_apply_patchset(c, local_diff, manage_counters);
 423 
 424         if(test_rc != pcmk_ok) {
 425             save_xml_to_file(c,           "PatchApply:calculated", NULL);
 426             save_xml_to_file(current_cib, "PatchApply:input", NULL);
 427             save_xml_to_file(scratch,     "PatchApply:actual", NULL);
 428             save_xml_to_file(local_diff,  "PatchApply:diff", NULL);
 429             crm_err("v%d patchset error, patch failed to apply: %s (%d)", format, pcmk_strerror(test_rc), test_rc);
 430         }
 431         free_xml(c);
 432     }
 433 
 434     if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
 435         /* Throttle the amount of costly validation we perform due to status updates
 436          * a) we don't really care whats in the status section
 437          * b) we don't validate any of its contents at the moment anyway
 438          */
 439         check_schema = FALSE;
 440     }
 441 
 442     /* === scratch must not be modified after this point ===
 443      * Exceptions, anything in:
 444 
 445      static filter_t filter[] = {
 446      { 0, XML_ATTR_ORIGIN },
 447      { 0, XML_CIB_ATTR_WRITTEN },
 448      { 0, XML_ATTR_UPDATE_ORIG },
 449      { 0, XML_ATTR_UPDATE_CLIENT },
 450      { 0, XML_ATTR_UPDATE_USER },
 451      };
 452      */
 453 
 454     if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
 455         const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
 456 
 457         pcmk__xe_add_last_written(scratch);
 458         if (schema) {
 459             static int minimum_schema = 0;
 460             int current_schema = get_schema_version(schema);
 461 
 462             if (minimum_schema == 0) {
 463                 minimum_schema = get_schema_version("pacemaker-1.2");
 464             }
 465 
 466             /* Does the CIB support the "update-*" attributes... */
 467             if (current_schema >= minimum_schema) {
 468                 const char *origin = crm_element_value(req, F_ORIG);
 469 
 470                 CRM_LOG_ASSERT(origin != NULL);
 471                 crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
 472                 crm_xml_replace(scratch, XML_ATTR_UPDATE_CLIENT,
 473                                 crm_element_value(req, F_CIB_CLIENTNAME));
 474                 crm_xml_replace(scratch, XML_ATTR_UPDATE_USER, crm_element_value(req, F_CIB_USER));
 475             }
 476         }
 477     }
 478 
 479     crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
 480     if ((rc == pcmk_ok) && check_schema && !validate_xml(scratch, NULL, TRUE)) {
 481         const char *current_schema = crm_element_value(scratch,
 482                                                        XML_ATTR_VALIDATION);
 483 
 484         crm_warn("Updated CIB does not validate against %s schema",
 485                  crm_str(current_schema));
 486         rc = -pcmk_err_schema_validation;
 487     }
 488 
 489   done:
 490 
 491     *result_cib = scratch;
 492     if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
 493         if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
 494             if (*result_cib == NULL) {
 495                 crm_debug("Pre-filtered the entire cib result");
 496             }
 497             free_xml(scratch);
 498         }
 499     }
 500 
 501     if(diff) {
 502         *diff = local_diff;
 503     } else {
 504         free_xml(local_diff);
 505     }
 506 
 507     free_xml(top);
 508     crm_trace("Done");
 509     return rc;
 510 }
 511 
 512 xmlNode *
 513 cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 514               xmlNode * data, int call_options, const char *user_name)
 515 {
 516     xmlNode *op_msg = create_xml_node(NULL, "cib_command");
 517 
 518     CRM_CHECK(op_msg != NULL, return NULL);
 519     CRM_CHECK(token != NULL, return NULL);
 520 
 521     crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
 522 
 523     crm_xml_add(op_msg, F_TYPE, T_CIB);
 524     crm_xml_add(op_msg, F_CIB_CALLBACK_TOKEN, token);
 525     crm_xml_add(op_msg, F_CIB_OPERATION, op);
 526     crm_xml_add(op_msg, F_CIB_HOST, host);
 527     crm_xml_add(op_msg, F_CIB_SECTION, section);
 528     crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
 529     if (user_name) {
 530         crm_xml_add(op_msg, F_CIB_USER, user_name);
 531     }
 532     crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
 533     crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
 534 
 535     if (data != NULL) {
 536         add_message_xml(op_msg, F_CIB_CALLDATA, data);
 537     }
 538 
 539     if (call_options & cib_inhibit_bcast) {
 540         CRM_CHECK((call_options & cib_scope_local), return NULL);
 541     }
 542     return op_msg;
 543 }
 544 
 545 void
 546 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548     xmlNode *output = NULL;
 549     cib_callback_client_t *blob = NULL;
 550 
 551     if (msg != NULL) {
 552         crm_element_value_int(msg, F_CIB_RC, &rc);
 553         crm_element_value_int(msg, F_CIB_CALLID, &call_id);
 554         output = get_message_xml(msg, F_CIB_CALLDATA);
 555     }
 556 
 557     blob = cib__lookup_id(call_id);
 558 
 559     if (blob == NULL) {
 560         crm_trace("No callback found for call %d", call_id);
 561     }
 562 
 563     if (cib == NULL) {
 564         crm_debug("No cib object supplied");
 565     }
 566 
 567     if (rc == -pcmk_err_diff_resync) {
 568         /* This is an internal value that clients do not and should not care about */
 569         rc = pcmk_ok;
 570     }
 571 
 572     if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
 573         crm_trace("Invoking callback %s for call %d", crm_str(blob->id), call_id);
 574         blob->callback(msg, call_id, rc, output, blob->user_data);
 575 
 576     } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
 577         crm_warn("CIB command failed: %s", pcmk_strerror(rc));
 578         crm_log_xml_debug(msg, "Failed CIB Update");
 579     }
 580 
 581     /* This may free user_data, so do it after the callback */
 582     if (blob) {
 583         remove_cib_op_callback(call_id, FALSE);
 584     }
 585 
 586     if (cib && cib->op_callback != NULL) {
 587         crm_trace("Invoking global callback for call %d", call_id);
 588         cib->op_callback(msg, call_id, rc, output);
 589     }
 590     crm_trace("OP callback activated for %d", call_id);
 591 }
 592 
 593 void
 594 cib_native_notify(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 595 {
 596     xmlNode *msg = user_data;
 597     cib_notify_client_t *entry = data;
 598     const char *event = NULL;
 599 
 600     if (msg == NULL) {
 601         crm_warn("Skipping callback - NULL message");
 602         return;
 603     }
 604 
 605     event = crm_element_value(msg, F_SUBTYPE);
 606 
 607     if (entry == NULL) {
 608         crm_warn("Skipping callback - NULL callback client");
 609         return;
 610 
 611     } else if (entry->callback == NULL) {
 612         crm_warn("Skipping callback - NULL callback");
 613         return;
 614 
 615     } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
 616         crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
 617         return;
 618     }
 619 
 620     crm_trace("Invoking callback for %p/%s event...", entry, event);
 621     entry->callback(event, msg);
 622     crm_trace("Callback invoked...");
 623 }
 624 
 625 static pcmk__cluster_option_t cib_opts[] = {
 626     /* name, legacy name, type, allowed values,
 627      * default value, validator,
 628      * short description,
 629      * long description
 630      */
 631     {
 632         "enable-acl", NULL, "boolean", NULL,
 633         "false", pcmk__valid_boolean,
 634         "Enable Access Control Lists (ACLs) for the CIB",
 635         NULL
 636     },
 637     {
 638         "cluster-ipc-limit", NULL, "integer", NULL,
 639         "500", pcmk__valid_positive_number,
 640         "Maximum IPC message backlog before disconnecting a cluster daemon",
 641         "Raise this if log has \"Evicting client\" messages for cluster daemon"
 642             " PIDs (a good value is the number of resources in the cluster"
 643             " multiplied by the number of nodes)."
 644     },
 645 };
 646 
 647 void
 648 cib_metadata(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 649 {
 650     pcmk__print_option_metadata("pacemaker-based",
 651                                 "Cluster Information Base manager options",
 652                                 "Cluster options used by Pacemaker's "
 653                                     "Cluster Information Base manager",
 654                                 cib_opts, PCMK__NELEM(cib_opts));
 655 }
 656 
 657 void
 658 verify_cib_options(GHashTable * options)
     /* [previous][next][first][last][top][bottom][index][help] */
 659 {
 660     pcmk__validate_cluster_options(options, cib_opts, PCMK__NELEM(cib_opts));
 661 }
 662 
 663 const char *
 664 cib_pref(GHashTable * options, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 665 {
 666     return pcmk__cluster_option(options, cib_opts, PCMK__NELEM(cib_opts),
 667                                 name);
 668 }
 669 
 670 gboolean
 671 cib_read_config(GHashTable * options, xmlNode * current_cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 672 {
 673     xmlNode *config = NULL;
 674     crm_time_t *now = NULL;
 675 
 676     if (options == NULL || current_cib == NULL) {
 677         return FALSE;
 678     }
 679 
 680     now = crm_time_new(NULL);
 681 
 682     g_hash_table_remove_all(options);
 683 
 684     config = get_object_root(XML_CIB_TAG_CRMCONFIG, current_cib);
 685     if (config) {
 686         pe_unpack_nvpairs(current_cib, config, XML_CIB_TAG_PROPSET, NULL,
 687                           options, CIB_OPTIONS_FIRST, TRUE, now, NULL);
 688     }
 689 
 690     verify_cib_options(options);
 691 
 692     crm_time_free(now);
 693 
 694     return TRUE;
 695 }
 696 
 697 /* v2 and v2 patch formats */
 698 #define XPATH_CONFIG_CHANGE \
 699     "//" XML_CIB_TAG_CRMCONFIG " | " \
 700     "//" XML_DIFF_CHANGE "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
 701 
 702 gboolean
 703 cib_internal_config_changed(xmlNode *diff)
     /* [previous][next][first][last][top][bottom][index][help] */
 704 {
 705     gboolean changed = FALSE;
 706 
 707     if (diff) {
 708         xmlXPathObject *xpathObj = xpath_search(diff, XPATH_CONFIG_CHANGE);
 709 
 710         if (numXpathResults(xpathObj) > 0) {
 711             changed = TRUE;
 712         }
 713         freeXpathObject(xpathObj);
 714     }
 715     return changed;
 716 }
 717 
 718 int
 719 cib_internal_op(cib_t * cib, const char *op, const char *host,
     /* [previous][next][first][last][top][bottom][index][help] */
 720                 const char *section, xmlNode * data,
 721                 xmlNode ** output_data, int call_options, const char *user_name)
 722 {
 723     int (*delegate) (cib_t * cib, const char *op, const char *host,
 724                      const char *section, xmlNode * data,
 725                      xmlNode ** output_data, int call_options, const char *user_name) =
 726         cib->delegate_fn;
 727 
 728     if(user_name == NULL) {
 729         user_name = getenv("CIB_user");
 730     }
 731 
 732     return delegate(cib, op, host, section, data, output_data, call_options, user_name);
 733 }
 734 
 735 /*!
 736  * \brief Apply a CIB update patch to a given CIB
 737  *
 738  * \param[in]  event   CIB update patch
 739  * \param[in]  input   CIB to patch
 740  * \param[out] output  Resulting CIB after patch
 741  * \param[in]  level   Log the patch at this log level (unless LOG_CRIT)
 742  *
 743  * \return Legacy Pacemaker return code
 744  * \note sbd calls this function
 745  */
 746 int
 747 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
     /* [previous][next][first][last][top][bottom][index][help] */
 748                       int level)
 749 {
 750     int rc = pcmk_err_generic;
 751 
 752     xmlNode *diff = NULL;
 753 
 754     CRM_ASSERT(event);
 755     CRM_ASSERT(input);
 756     CRM_ASSERT(output);
 757 
 758     crm_element_value_int(event, F_CIB_RC, &rc);
 759     diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
 760 
 761     if (rc < pcmk_ok || diff == NULL) {
 762         return rc;
 763     }
 764 
 765     if (level > LOG_CRIT) {
 766         xml_log_patchset(level, "Config update", diff);
 767     }
 768 
 769     if (input != NULL) {
 770         rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
 771                               NULL);
 772 
 773         if (rc != pcmk_ok) {
 774             crm_debug("Update didn't apply: %s (%d) %p",
 775                       pcmk_strerror(rc), rc, *output);
 776 
 777             if (rc == -pcmk_err_old_data) {
 778                 crm_trace("Masking error, we already have the supplied update");
 779                 return pcmk_ok;
 780             }
 781             free_xml(*output);
 782             *output = NULL;
 783             return rc;
 784         }
 785     }
 786     return rc;
 787 }
 788 
 789 int
 790 cib__signon_query(cib_t **cib, xmlNode **cib_object)
     /* [previous][next][first][last][top][bottom][index][help] */
 791 {
 792     int rc = pcmk_rc_ok;
 793     cib_t *cib_conn = NULL;
 794 
 795     if (cib == NULL) {
 796         cib_conn = cib_new();
 797     } else {
 798         *cib = cib_new();
 799         cib_conn = *cib;
 800     }
 801 
 802     if (cib_conn == NULL) {
 803         return ENOMEM;
 804     }
 805 
 806     rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
 807     rc = pcmk_legacy2rc(rc);
 808 
 809     if (rc == pcmk_rc_ok) {
 810         rc = cib_conn->cmds->query(cib_conn, NULL, cib_object, cib_scope_local | cib_sync_call);
 811         rc = pcmk_legacy2rc(rc);
 812     }
 813 
 814     if (cib == NULL) {
 815         cib_conn->cmds->signoff(cib_conn);
 816         cib_delete(cib_conn);
 817         cib_conn = NULL;
 818     }
 819 
 820     if (cib_object == NULL) {
 821         return pcmk_rc_no_input;
 822     } else {
 823         return rc;
 824     }
 825 }

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