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

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

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