pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
cib_utils.c
Go to the documentation of this file.
1 /*
2  * Original copyright 2004 International Business Machines
3  * Later changes copyright 2008-2024 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>
23 #include <crm/common/xml.h>
25 #include <crm/pengine/rules.h>
26 
27 gboolean
28 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
29 {
30  *epoch = -1;
31  *updates = -1;
32  *admin_epoch = -1;
33 
34  if (cib == NULL) {
35  return FALSE;
36 
37  } else {
40  crm_element_value_int(cib, PCMK_XA_ADMIN_EPOCH, admin_epoch);
41  }
42  return TRUE;
43 }
44 
45 gboolean
46 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
47  int *_admin_epoch, int *_epoch, int *_updates)
48 {
49  int add[] = { 0, 0, 0 };
50  int del[] = { 0, 0, 0 };
51 
52  xml_patch_versions(diff, add, del);
53 
54  *admin_epoch = add[0];
55  *epoch = add[1];
56  *updates = add[2];
57 
58  *_admin_epoch = del[0];
59  *_epoch = del[1];
60  *_updates = del[2];
61 
62  return TRUE;
63 }
64 
74 int
75 cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset)
76 {
77  int rc = pcmk_err_generic;
78  xmlNode *wrapper = NULL;
79 
80  pcmk__assert(patchset != NULL);
81  *patchset = NULL;
82 
83  if (msg == NULL) {
84  crm_err("CIB diff notification received with no XML");
85  return ENOMSG;
86  }
87 
88  if ((crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc) != 0)
89  || (rc != pcmk_ok)) {
90 
91  crm_warn("Ignore failed CIB update: %s " CRM_XS " rc=%d",
92  pcmk_strerror(rc), rc);
93  crm_log_xml_debug(msg, "failed");
94  return pcmk_legacy2rc(rc);
95  }
96 
97  wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT, NULL, NULL);
98  *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
99 
100  if (*patchset == NULL) {
101  crm_err("CIB diff notification received with no patchset");
102  return ENOMSG;
103  }
104  return pcmk_rc_ok;
105 }
106 
107 #define XPATH_DIFF_V1 "//" PCMK__XE_CIB_UPDATE_RESULT "//" PCMK__XE_DIFF_ADDED
108 
119 static bool
120 element_in_patchset_v1(const xmlNode *patchset, const char *element)
121 {
122  char *xpath = crm_strdup_printf(XPATH_DIFF_V1 "//%s",
123  pcmk__s(element, PCMK_XE_CIB));
124  xmlXPathObject *xpath_obj = xpath_search(patchset, xpath);
125 
126  free(xpath);
127 
128  if (xpath_obj == NULL) {
129  return false;
130  }
131  freeXpathObject(xpath_obj);
132  return true;
133 }
134 
146 static bool
147 element_in_patchset_v2(const xmlNode *patchset, const char *element)
148 {
149  const char *element_xpath = pcmk__cib_abs_xpath_for(element);
150  const char *parent_xpath = pcmk_cib_parent_name_for(element);
151  char *element_regex = NULL;
152  bool rc = false;
153 
154  CRM_CHECK(element_xpath != NULL, return false); // Unsupported element
155 
156  // Matches if and only if element_xpath is part of a changed path
157  element_regex = crm_strdup_printf("^%s(/|$)", element_xpath);
158 
159  for (const xmlNode *change = pcmk__xe_first_child(patchset, PCMK_XE_CHANGE,
160  NULL, NULL);
161  change != NULL; change = pcmk__xe_next_same(change)) {
162 
163  const char *op = crm_element_value(change, PCMK_XA_OPERATION);
164  const char *diff_xpath = crm_element_value(change, PCMK_XA_PATH);
165 
166  if (pcmk__str_eq(diff_xpath, element_regex, pcmk__str_regex)) {
167  // Change to an existing element
168  rc = true;
169  break;
170  }
171 
172  if (pcmk__str_eq(op, PCMK_VALUE_CREATE, pcmk__str_none)
173  && pcmk__str_eq(diff_xpath, parent_xpath, pcmk__str_none)
174  && pcmk__xe_is(pcmk__xe_first_child(change, NULL, NULL, NULL),
175  element)) {
176 
177  // Newly added element
178  rc = true;
179  break;
180  }
181  }
182 
183  free(element_regex);
184  return rc;
185 }
186 
198 bool
199 cib__element_in_patchset(const xmlNode *patchset, const char *element)
200 {
201  int format = 1;
202 
203  pcmk__assert(patchset != NULL);
204 
205  crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
206  switch (format) {
207  case 1:
208  return element_in_patchset_v1(patchset, element);
209 
210  case 2:
211  return element_in_patchset_v2(patchset, element);
212 
213  default:
214  crm_warn("Unknown patch format: %d", format);
215  return false;
216  }
217 }
218 
227 xmlNode *
228 createEmptyCib(int cib_epoch)
229 {
230  xmlNode *cib_root = NULL, *config = NULL;
231 
232  cib_root = pcmk__xe_create(NULL, PCMK_XE_CIB);
235 
236  crm_xml_add_int(cib_root, PCMK_XA_EPOCH, cib_epoch);
237  crm_xml_add_int(cib_root, PCMK_XA_NUM_UPDATES, 0);
238  crm_xml_add_int(cib_root, PCMK_XA_ADMIN_EPOCH, 0);
239 
240  config = pcmk__xe_create(cib_root, PCMK_XE_CONFIGURATION);
241  pcmk__xe_create(cib_root, PCMK_XE_STATUS);
242 
247 
248 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
249  {
250  xmlNode *rsc_defaults = pcmk__xe_create(config, PCMK_XE_RSC_DEFAULTS);
251  xmlNode *meta = pcmk__xe_create(rsc_defaults, PCMK_XE_META_ATTRIBUTES);
252  xmlNode *nvpair = pcmk__xe_create(meta, PCMK_XE_NVPAIR);
253 
254  crm_xml_add(meta, PCMK_XA_ID, "build-resource-defaults");
259  }
260 #endif
261  return cib_root;
262 }
263 
264 static bool
265 cib_acl_enabled(xmlNode *xml, const char *user)
266 {
267  bool rc = FALSE;
268 
269  if(pcmk_acl_required(user)) {
270  const char *value = NULL;
271  GHashTable *options = pcmk__strkey_table(free, free);
272 
273  cib_read_config(options, xml);
274  value = pcmk__cluster_option(options, PCMK_OPT_ENABLE_ACL);
275  rc = crm_is_true(value);
276  g_hash_table_destroy(options);
277  }
278 
279  crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
280  return rc;
281 }
282 
293 static bool
294 should_copy_cib(const char *op, const char *section, int call_options)
295 {
296  if (pcmk_is_set(call_options, cib_dryrun)) {
297  // cib_dryrun implies a scratch copy by definition; no side effects
298  return true;
299  }
300 
301  if (pcmk__str_eq(op, PCMK__CIB_REQUEST_COMMIT_TRANSACT, pcmk__str_none)) {
302  /* Commit-transaction must make a copy for atomicity. We must revert to
303  * the original CIB if the entire transaction cannot be applied
304  * successfully.
305  */
306  return true;
307  }
308 
309  if (pcmk_is_set(call_options, cib_transaction)) {
310  /* If cib_transaction is set, then we're in the process of committing a
311  * transaction. The commit-transaction request already made a scratch
312  * copy, and we're accumulating changes in that copy.
313  */
314  return false;
315  }
316 
317  if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_none)) {
318  /* Copying large CIBs accounts for a huge percentage of our CIB usage,
319  * and this avoids some of it.
320  *
321  * @TODO: Is this safe? See discussion at
322  * https://github.com/ClusterLabs/pacemaker/pull/3094#discussion_r1211400690.
323  */
324  return false;
325  }
326 
327  // Default behavior is to operate on a scratch copy
328  return true;
329 }
330 
331 int
332 cib_perform_op(cib_t *cib, const char *op, uint32_t call_options,
333  cib__op_fn_t fn, bool is_query, const char *section,
334  xmlNode *req, xmlNode *input, bool manage_counters,
335  bool *config_changed, xmlNode **current_cib,
336  xmlNode **result_cib, xmlNode **diff, xmlNode **output)
337 {
338  int rc = pcmk_ok;
339  bool check_schema = true;
340  bool make_copy = true;
341  xmlNode *top = NULL;
342  xmlNode *scratch = NULL;
343  xmlNode *patchset_cib = NULL;
344  xmlNode *local_diff = NULL;
345 
346  const char *user = crm_element_value(req, PCMK__XA_CIB_USER);
347  bool with_digest = false;
348 
349  crm_trace("Begin %s%s%s op",
350  (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
351  (is_query? "read-only " : ""), op);
352 
353  CRM_CHECK(output != NULL, return -ENOMSG);
354  CRM_CHECK(current_cib != NULL, return -ENOMSG);
355  CRM_CHECK(result_cib != NULL, return -ENOMSG);
356  CRM_CHECK(config_changed != NULL, return -ENOMSG);
357 
358  if(output) {
359  *output = NULL;
360  }
361 
362  *result_cib = NULL;
363  *config_changed = false;
364 
365  if (fn == NULL) {
366  return -EINVAL;
367  }
368 
369  if (is_query) {
370  xmlNode *cib_ro = *current_cib;
371  xmlNode *cib_filtered = NULL;
372 
373  if (cib_acl_enabled(cib_ro, user)
374  && xml_acl_filtered_copy(user, *current_cib, *current_cib,
375  &cib_filtered)) {
376 
377  if (cib_filtered == NULL) {
378  crm_debug("Pre-filtered the entire cib");
379  return -EACCES;
380  }
381  cib_ro = cib_filtered;
382  crm_log_xml_trace(cib_ro, "filtered");
383  }
384 
385  rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
386 
387  if(output == NULL || *output == NULL) {
388  /* nothing */
389 
390  } else if(cib_filtered == *output) {
391  cib_filtered = NULL; /* Let them have this copy */
392 
393  } else if (*output == *current_cib) {
394  /* They already know not to free it */
395 
396  } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
397  /* We're about to free the document of which *output is a part */
398  *output = pcmk__xml_copy(NULL, *output);
399 
400  } else if ((*output)->doc == (*current_cib)->doc) {
401  /* Give them a copy they can free */
402  *output = pcmk__xml_copy(NULL, *output);
403  }
404 
405  free_xml(cib_filtered);
406  return rc;
407  }
408 
409  make_copy = should_copy_cib(op, section, call_options);
410 
411  if (!make_copy) {
412  /* Conditional on v2 patch style */
413 
414  scratch = *current_cib;
415 
416  // Make a copy of the top-level element to store version details
417  top = pcmk__xe_create(NULL, (const char *) scratch->name);
418  pcmk__xe_copy_attrs(top, scratch, pcmk__xaf_none);
419  patchset_cib = top;
420 
421  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
422  rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
423 
424  /* If scratch points to a new object now (for example, after an erase
425  * operation), then *current_cib should point to the same object.
426  */
427  *current_cib = scratch;
428 
429  } else {
430  scratch = pcmk__xml_copy(NULL, *current_cib);
431  patchset_cib = *current_cib;
432 
433  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
434  rc = (*fn) (op, call_options, section, req, input, *current_cib,
435  &scratch, output);
436 
437  if ((scratch != NULL) && !xml_tracking_changes(scratch)) {
438  crm_trace("Inferring changes after %s op", op);
439  xml_track_changes(scratch, user, *current_cib,
440  cib_acl_enabled(*current_cib, user));
441  xml_calculate_changes(*current_cib, scratch);
442  }
443  CRM_CHECK(*current_cib != scratch, return -EINVAL);
444  }
445 
446  xml_acl_disable(scratch); /* Allow the system to make any additional changes */
447 
448  if (rc == pcmk_ok && scratch == NULL) {
449  rc = -EINVAL;
450  goto done;
451 
452  } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
453  crm_trace("ACL rejected part or all of the proposed changes");
454  rc = -EACCES;
455  goto done;
456 
457  } else if (rc != pcmk_ok) {
458  goto done;
459  }
460 
461  /* If the CIB is from a file, we don't need to check that the feature set is
462  * supported. All we care about in that case is the schema version, which
463  * is checked elsewhere.
464  */
465  if (scratch && (cib == NULL || cib->variant != cib_file)) {
466  const char *new_version = crm_element_value(scratch, PCMK_XA_CRM_FEATURE_SET);
467 
468  rc = pcmk__check_feature_set(new_version);
469  if (rc != pcmk_rc_ok) {
470  pcmk__config_err("Discarding update with feature set '%s' greater than our own '%s'",
471  new_version, CRM_FEATURE_SET);
472  rc = pcmk_rc2legacy(rc);
473  goto done;
474  }
475  }
476 
477  if (patchset_cib != NULL) {
478  int old = 0;
479  int new = 0;
480 
482  crm_element_value_int(patchset_cib, PCMK_XA_ADMIN_EPOCH, &old);
483 
484  if (old > new) {
485  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
486  PCMK_XA_ADMIN_EPOCH, old, new, call_options);
487  crm_log_xml_warn(req, "Bad Op");
488  crm_log_xml_warn(input, "Bad Data");
489  rc = -pcmk_err_old_data;
490 
491  } else if (old == new) {
492  crm_element_value_int(scratch, PCMK_XA_EPOCH, &new);
493  crm_element_value_int(patchset_cib, PCMK_XA_EPOCH, &old);
494  if (old > new) {
495  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
496  PCMK_XA_EPOCH, old, new, call_options);
497  crm_log_xml_warn(req, "Bad Op");
498  crm_log_xml_warn(input, "Bad Data");
499  rc = -pcmk_err_old_data;
500  }
501  }
502  }
503 
504  crm_trace("Massaging CIB contents");
505  pcmk__strip_xml_text(scratch);
506 
507  if (!make_copy) {
508  /* At this point, patchset_cib is just the PCMK_XE_CIB tag and its
509  * properties.
510  *
511  * The v1 format would barf on this, but we know the v2 patch
512  * format only needs it for the top-level version fields
513  */
514  local_diff = xml_create_patchset(2, patchset_cib, scratch,
515  config_changed, manage_counters);
516 
517  } else {
518  static time_t expires = 0;
519  time_t tm_now = time(NULL);
520 
521  if (expires < tm_now) {
522  expires = tm_now + 60; /* Validate clients are correctly applying v2-style diffs at most once a minute */
523  with_digest = true;
524  }
525 
526  local_diff = xml_create_patchset(0, patchset_cib, scratch,
527  config_changed, manage_counters);
528  }
529 
531  xml_accept_changes(scratch);
532 
533  if(local_diff) {
534  patchset_process_digest(local_diff, patchset_cib, scratch, with_digest);
535  pcmk__log_xml_patchset(LOG_INFO, local_diff);
536  crm_log_xml_trace(local_diff, "raw patch");
537  }
538 
539  if (make_copy && (local_diff != NULL)) {
540  // Original to compare against doesn't exist
542  {
543  // Validate the calculated patch set
544  int test_rc = pcmk_ok;
545  int format = 1;
546  xmlNode *cib_copy = pcmk__xml_copy(NULL, patchset_cib);
547 
548  crm_element_value_int(local_diff, PCMK_XA_FORMAT, &format);
549  test_rc = xml_apply_patchset(cib_copy, local_diff,
550  manage_counters);
551 
552  if (test_rc != pcmk_ok) {
553  save_xml_to_file(cib_copy, "PatchApply:calculated", NULL);
554  save_xml_to_file(patchset_cib, "PatchApply:input", NULL);
555  save_xml_to_file(scratch, "PatchApply:actual", NULL);
556  save_xml_to_file(local_diff, "PatchApply:diff", NULL);
557  crm_err("v%d patchset error, patch failed to apply: %s "
558  "(%d)",
559  format, pcmk_rc_str(pcmk_legacy2rc(test_rc)),
560  test_rc);
561  }
562  free_xml(cib_copy);
563  },
564  {}
565  );
566  }
567 
568  if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei)) {
569  /* Throttle the amount of costly validation we perform due to status updates
570  * a) we don't really care whats in the status section
571  * b) we don't validate any of its contents at the moment anyway
572  */
573  check_schema = false;
574  }
575 
576  /* === scratch must not be modified after this point ===
577  * Exceptions, anything in:
578 
579  static filter_t filter[] = {
580  { 0, PCMK_XA_CRM_DEBUG_ORIGIN },
581  { 0, PCMK_XA_CIB_LAST_WRITTEN },
582  { 0, PCMK_XA_UPDATE_ORIGIN },
583  { 0, PCMK_XA_UPDATE_CLIENT },
584  { 0, PCMK_XA_UPDATE_USER },
585  };
586  */
587 
588  if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
589  const char *schema = crm_element_value(scratch, PCMK_XA_VALIDATE_WITH);
590 
591  pcmk__xe_add_last_written(scratch);
593 
594  /* Make values of origin, client, and user in scratch match
595  * the ones in req (if the schema allows the attributes)
596  */
597  if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") >= 0) {
598  const char *origin = crm_element_value(req, PCMK__XA_SRC);
599  const char *client = crm_element_value(req,
601 
602  if (origin != NULL) {
603  crm_xml_add(scratch, PCMK_XA_UPDATE_ORIGIN, origin);
604  } else {
606  }
607 
608  if (client != NULL) {
609  crm_xml_add(scratch, PCMK_XA_UPDATE_CLIENT, user);
610  } else {
612  }
613 
614  if (user != NULL) {
615  crm_xml_add(scratch, PCMK_XA_UPDATE_USER, user);
616  } else {
618  }
619  }
620  }
621 
622  crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
623  if ((rc == pcmk_ok) && check_schema
624  && !pcmk__configured_schema_validates(scratch)) {
625  const char *current_schema = crm_element_value(scratch,
627 
628  crm_warn("Updated CIB does not validate against %s schema",
629  pcmk__s(current_schema, "unspecified"));
631  }
632 
633  done:
634 
635  *result_cib = scratch;
636 
637  /* @TODO: This may not work correctly with !make_copy, since we don't
638  * keep the original CIB.
639  */
640  if ((rc != pcmk_ok) && cib_acl_enabled(patchset_cib, user)
641  && xml_acl_filtered_copy(user, patchset_cib, scratch, result_cib)) {
642 
643  if (*result_cib == NULL) {
644  crm_debug("Pre-filtered the entire cib result");
645  }
646  free_xml(scratch);
647  }
648 
649  if(diff) {
650  *diff = local_diff;
651  } else {
652  free_xml(local_diff);
653  }
654 
655  free_xml(top);
656  crm_trace("Done");
657  return rc;
658 }
659 
660 int
661 cib__create_op(cib_t *cib, const char *op, const char *host,
662  const char *section, xmlNode *data, int call_options,
663  const char *user_name, const char *client_name,
664  xmlNode **op_msg)
665 {
666  CRM_CHECK((cib != NULL) && (op_msg != NULL), return -EPROTO);
667 
668  *op_msg = pcmk__xe_create(NULL, PCMK__XE_CIB_COMMAND);
669 
670  cib->call_id++;
671  if (cib->call_id < 1) {
672  cib->call_id = 1;
673  }
674 
676  crm_xml_add(*op_msg, PCMK__XA_CIB_OP, op);
678  crm_xml_add(*op_msg, PCMK__XA_CIB_SECTION, section);
679  crm_xml_add(*op_msg, PCMK__XA_CIB_USER, user_name);
680  crm_xml_add(*op_msg, PCMK__XA_CIB_CLIENTNAME, client_name);
682 
683  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
684  crm_xml_add_int(*op_msg, PCMK__XA_CIB_CALLOPT, call_options);
685 
686  if (data != NULL) {
687  xmlNode *wrapper = pcmk__xe_create(*op_msg, PCMK__XE_CIB_CALLDATA);
688 
689  pcmk__xml_copy(wrapper, data);
690  }
691 
692  if (pcmk_is_set(call_options, cib_inhibit_bcast)) {
693  CRM_CHECK(pcmk_is_set(call_options, cib_scope_local),
694  free_xml(*op_msg); return -EPROTO);
695  }
696  return pcmk_ok;
697 }
698 
707 static int
708 validate_transaction_request(const xmlNode *request)
709 {
710  const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
711  const char *host = crm_element_value(request, PCMK__XA_CIB_HOST);
712  const cib__operation_t *operation = NULL;
713  int rc = cib__get_operation(op, &operation);
714 
715  if (rc != pcmk_rc_ok) {
716  // cib__get_operation() logs error
717  return rc;
718  }
719 
720  if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)) {
721  crm_err("Operation %s is not supported in CIB transactions", op);
722  return EOPNOTSUPP;
723  }
724 
725  if (host != NULL) {
726  crm_err("Operation targeting a specific node (%s) is not supported in "
727  "a CIB transaction",
728  host);
729  return EOPNOTSUPP;
730  }
731  return pcmk_rc_ok;
732 }
733 
743 int
744 cib__extend_transaction(cib_t *cib, xmlNode *request)
745 {
746  int rc = pcmk_rc_ok;
747 
748  pcmk__assert((cib != NULL) && (request != NULL));
749 
750  rc = validate_transaction_request(request);
751 
752  if ((rc == pcmk_rc_ok) && (cib->transaction == NULL)) {
754  }
755 
756  if (rc == pcmk_rc_ok) {
757  pcmk__xml_copy(cib->transaction, request);
758 
759  } else {
760  const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
761  const char *client_id = NULL;
762 
763  cib->cmds->client_id(cib, NULL, &client_id);
764  crm_err("Failed to add '%s' operation to transaction for client %s: %s",
765  op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc));
766  crm_log_xml_info(request, "failed");
767  }
768  return pcmk_rc2legacy(rc);
769 }
770 
771 void
772 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
773 {
774  xmlNode *output = NULL;
775  cib_callback_client_t *blob = NULL;
776 
777  if (msg != NULL) {
778  xmlNode *wrapper = NULL;
779 
782  wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_CALLDATA, NULL, NULL);
783  output = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
784  }
785 
786  blob = cib__lookup_id(call_id);
787 
788  if (blob == NULL) {
789  crm_trace("No callback found for call %d", call_id);
790  }
791 
792  if (cib == NULL) {
793  crm_debug("No cib object supplied");
794  }
795 
796  if (rc == -pcmk_err_diff_resync) {
797  /* This is an internal value that clients do not and should not care about */
798  rc = pcmk_ok;
799  }
800 
801  if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
802  crm_trace("Invoking callback %s for call %d",
803  pcmk__s(blob->id, "without ID"), call_id);
804  blob->callback(msg, call_id, rc, output, blob->user_data);
805 
806  } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
807  crm_warn("CIB command failed: %s", pcmk_strerror(rc));
808  crm_log_xml_debug(msg, "Failed CIB Update");
809  }
810 
811  /* This may free user_data, so do it after the callback */
812  if (blob) {
813  remove_cib_op_callback(call_id, FALSE);
814  }
815 
816  if (cib && cib->op_callback != NULL) {
817  crm_trace("Invoking global callback for call %d", call_id);
818  cib->op_callback(msg, call_id, rc, output);
819  }
820  crm_trace("OP callback activated for %d", call_id);
821 }
822 
823 void
824 cib_native_notify(gpointer data, gpointer user_data)
825 {
826  xmlNode *msg = user_data;
827  cib_notify_client_t *entry = data;
828  const char *event = NULL;
829 
830  if (msg == NULL) {
831  crm_warn("Skipping callback - NULL message");
832  return;
833  }
834 
835  event = crm_element_value(msg, PCMK__XA_SUBT);
836 
837  if (entry == NULL) {
838  crm_warn("Skipping callback - NULL callback client");
839  return;
840 
841  } else if (entry->callback == NULL) {
842  crm_warn("Skipping callback - NULL callback");
843  return;
844 
845  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
846  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
847  return;
848  }
849 
850  crm_trace("Invoking callback for %p/%s event...", entry, event);
851  entry->callback(event, msg);
852  crm_trace("Callback invoked...");
853 }
854 
855 gboolean
856 cib_read_config(GHashTable * options, xmlNode * current_cib)
857 {
858  xmlNode *config = NULL;
859  crm_time_t *now = NULL;
860 
861  if (options == NULL || current_cib == NULL) {
862  return FALSE;
863  }
864 
865  now = crm_time_new(NULL);
866 
867  g_hash_table_remove_all(options);
868 
869  config = pcmk_find_cib_element(current_cib, PCMK_XE_CRM_CONFIG);
870  if (config) {
871  pe_unpack_nvpairs(current_cib, config, PCMK_XE_CLUSTER_PROPERTY_SET,
872  NULL, options, PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, TRUE,
873  now, NULL);
874  }
875 
877 
878  crm_time_free(now);
879 
880  return TRUE;
881 }
882 
883 int
884 cib_internal_op(cib_t * cib, const char *op, const char *host,
885  const char *section, xmlNode * data,
886  xmlNode ** output_data, int call_options, const char *user_name)
887 {
888  int (*delegate)(cib_t *cib, const char *op, const char *host,
889  const char *section, xmlNode *data, xmlNode **output_data,
890  int call_options, const char *user_name) = NULL;
891 
892  if (cib == NULL) {
893  return -EINVAL;
894  }
895 
896  delegate = cib->delegate_fn;
897  if (delegate == NULL) {
898  return -EPROTONOSUPPORT;
899  }
900  if (user_name == NULL) {
901  user_name = getenv("CIB_user");
902  }
903  return delegate(cib, op, host, section, data, output_data, call_options, user_name);
904 }
905 
917 int
918 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
919  int level)
920 {
921  int rc = pcmk_err_generic;
922 
923  xmlNode *wrapper = NULL;
924  xmlNode *diff = NULL;
925 
926  pcmk__assert((event != NULL) && (input != NULL) && (output != NULL));
927 
929  wrapper = pcmk__xe_first_child(event, PCMK__XE_CIB_UPDATE_RESULT, NULL,
930  NULL);
931  diff = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
932 
933  if (rc < pcmk_ok || diff == NULL) {
934  return rc;
935  }
936 
937  if (level > LOG_CRIT) {
938  pcmk__log_xml_patchset(level, diff);
939  }
940 
941  if (input != NULL) {
942  rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
943  NULL);
944 
945  if (rc != pcmk_ok) {
946  crm_debug("Update didn't apply: %s (%d) %p",
947  pcmk_strerror(rc), rc, *output);
948 
949  if (rc == -pcmk_err_old_data) {
950  crm_trace("Masking error, we already have the supplied update");
951  return pcmk_ok;
952  }
953  free_xml(*output);
954  *output = NULL;
955  return rc;
956  }
957  }
958  return rc;
959 }
960 
961 #define log_signon_query_err(out, fmt, args...) do { \
962  if (out != NULL) { \
963  out->err(out, fmt, ##args); \
964  } else { \
965  crm_err(fmt, ##args); \
966  } \
967  } while (0)
968 
969 int
970 cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
971 {
972  int rc = pcmk_rc_ok;
973  cib_t *cib_conn = NULL;
974 
975  pcmk__assert(cib_object != NULL);
976 
977  if (cib == NULL) {
978  cib_conn = cib_new();
979  } else {
980  if (*cib == NULL) {
981  *cib = cib_new();
982  }
983  cib_conn = *cib;
984  }
985 
986  if (cib_conn == NULL) {
987  return ENOMEM;
988  }
989 
990  if (cib_conn->state == cib_disconnected) {
991  rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
992  rc = pcmk_legacy2rc(rc);
993  }
994 
995  if (rc != pcmk_rc_ok) {
996  log_signon_query_err(out, "Could not connect to the CIB: %s",
997  pcmk_rc_str(rc));
998  goto done;
999  }
1000 
1001  if (out != NULL) {
1002  out->transient(out, "Querying CIB...");
1003  }
1004  rc = cib_conn->cmds->query(cib_conn, NULL, cib_object,
1006  rc = pcmk_legacy2rc(rc);
1007 
1008  if (rc != pcmk_rc_ok) {
1009  log_signon_query_err(out, "CIB query failed: %s", pcmk_rc_str(rc));
1010  }
1011 
1012 done:
1013  if (cib == NULL) {
1014  cib__clean_up_connection(&cib_conn);
1015  }
1016 
1017  if ((rc == pcmk_rc_ok) && (*cib_object == NULL)) {
1018  return pcmk_rc_no_input;
1019  }
1020  return rc;
1021 }
1022 
1023 int
1025  int attempts)
1026 {
1027  int rc = pcmk_rc_ok;
1028 
1029  crm_trace("Attempting connection to CIB manager (up to %d time%s)",
1030  attempts, pcmk__plural_s(attempts));
1031 
1032  for (int remaining = attempts - 1; remaining >= 0; --remaining) {
1033  rc = cib->cmds->signon(cib, name, type);
1034 
1035  if ((rc == pcmk_rc_ok)
1036  || (remaining == 0)
1037  || ((errno != EAGAIN) && (errno != EALREADY))) {
1038  break;
1039  }
1040 
1041  // Retry after soft error (interrupted by signal, etc.)
1042  pcmk__sleep_ms((attempts - remaining) * 500);
1043  crm_debug("Re-attempting connection to CIB manager (%d attempt%s remaining)",
1044  remaining, pcmk__plural_s(remaining));
1045  }
1046 
1047  return rc;
1048 }
1049 
1050 int
1052 {
1053  int rc;
1054 
1055  if (*cib == NULL) {
1056  return pcmk_rc_ok;
1057  }
1058 
1059  rc = (*cib)->cmds->signoff(*cib);
1060  cib_delete(*cib);
1061  *cib = NULL;
1062  return pcmk_legacy2rc(rc);
1063 }
1064 
1065 // Deprecated functions kept only for backward API compatibility
1066 // LCOV_EXCL_START
1067 
1068 #include <crm/cib/util_compat.h>
1069 
1070 xmlNode *
1072 {
1073  xmlNode *the_cib = NULL;
1074  xmlNode *generation = pcmk__xe_create(NULL, PCMK__XE_GENERATION_TUPLE);
1075 
1076  cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
1077  if (the_cib != NULL) {
1078  pcmk__xe_copy_attrs(generation, the_cib, pcmk__xaf_none);
1079  free_xml(the_cib);
1080  }
1081 
1082  return generation;
1083 }
1084 
1085 const char *
1086 get_object_path(const char *object_type)
1087 {
1088  return pcmk_cib_xpath_for(object_type);
1089 }
1090 
1091 const char *
1092 get_object_parent(const char *object_type)
1093 {
1094  return pcmk_cib_parent_name_for(object_type);
1095 }
1096 
1097 xmlNode *
1098 get_object_root(const char *object_type, xmlNode *the_root)
1099 {
1100  return pcmk_find_cib_element(the_root, object_type);
1101 }
1102 
1103 const char *
1104 cib_pref(GHashTable * options, const char *name)
1105 {
1106  return pcmk__cluster_option(options, name);
1107 }
1108 
1109 void
1111 {
1112  pcmk__output_t *out = NULL;
1113  int rc = pcmk__output_new(&out, "text", NULL, NULL);
1114 
1115  if (rc != pcmk_rc_ok) {
1116  crm_err("Unable to output metadata: %s", pcmk_rc_str(rc));
1117  return;
1118  }
1119 
1120  pcmk__daemon_metadata(out, "pacemaker-based",
1121  "Cluster Information Base manager options",
1122  "Cluster options used by Pacemaker's Cluster "
1123  "Information Base manager",
1124  pcmk__opt_based);
1125 
1126  out->finish(out, CRM_EX_OK, true, NULL);
1127  pcmk__output_free(out);
1128 }
1129 
1130 // LCOV_EXCL_STOP
1131 // End deprecated API
#define pcmk_err_old_data
Definition: results.h:73
#define LOG_TRACE
Definition: logging.h:38
pcmk__cpg_host_t host
Definition: cpg.c:52
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
#define pcmk_err_schema_validation
Definition: results.h:71
const char * get_object_parent(const char *object_type)
Definition: cib_utils.c:1092
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:974
A dumping ground.
#define PCMK_XE_NVPAIR
Definition: xml_names.h:144
const char * pcmk_strerror(int rc)
Definition: results.c:151
#define PCMK_XA_NAME
Definition: xml_names.h:330
char data[0]
Definition: cpg.c:58
int pcmk__cmp_schemas_by_name(const char *schema1_name, const char *schema2_name)
Definition: schemas.c:691
#define pcmk__if_tracing(if_action, else_action)
int pcmk_rc2legacy(int rc)
Definition: results.c:548
int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags)
Definition: xml.c:669
#define PCMK_XA_PATH
Definition: xml_names.h:355
#define PCMK_XE_CIB
Definition: xml_names.h:79
#define PCMK_XE_STATUS
Definition: xml_names.h:204
cib_t * cib_new(void)
Create a new CIB connection object.
Definition: cib_client.c:598
#define PCMK_XA_UPDATE_ORIGIN
Definition: xml_names.h:437
int pcmk__daemon_metadata(pcmk__output_t *out, const char *name, const char *short_desc, const char *long_desc, enum pcmk__opt_flags filter)
Definition: options.c:1524
const char * name
Definition: cib.c:26
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
Definition: xml_io.c:736
#define PCMK__XE_GENERATION_TUPLE
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1048
struct crm_time_s crm_time_t
Definition: iso8601.h:32
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:28
#define PCMK__RESOURCE_STICKINESS_DEFAULT
Definition: config.h:577
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
Copy ACL-allowed portions of specified XML.
Definition: acl.c:445
#define PCMK_XE_CONSTRAINTS
Definition: xml_names.h:89
#define PCMK__XE_CIB_COMMAND
void pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:282
#define PCMK_VALUE_CREATE
Definition: options.h:139
void(* callback)(const char *event, xmlNode *msg)
Definition: internal.h:98
int cib__signon_attempts(cib_t *cib, const char *name, enum cib_conn_type type, int attempts)
Definition: cib_utils.c:1024
#define PCMK_XE_RSC_DEFAULTS
Definition: xml_names.h:186
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:360
#define CRM_FEATURE_SET
Definition: crm.h:72
#define pcmk__config_err(fmt...)
#define PCMK_XA_NUM_UPDATES
Definition: xml_names.h:341
xmlNode * cib_get_generation(cib_t *cib)
Definition: cib_utils.c:1071
#define PCMK__CIB_REQUEST_COMMIT_TRANSACT
Definition: internal.h:34
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
Definition: xml.c:344
In CIB manager metadata.
void remove_cib_op_callback(int call_id, gboolean all_callbacks)
Definition: cib_client.c:780
int cib__extend_transaction(cib_t *cib, xmlNode *request)
Definition: cib_utils.c:744
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:313
#define PCMK_OPT_ENABLE_ACL
Definition: options.h:37
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:1098
#define PCMK_XA_FORMAT
Definition: xml_names.h:291
#define pcmk_err_generic
Definition: results.h:69
#define XPATH_DIFF_V1
Definition: cib_utils.c:107
char * crm_system_name
Definition: utils.c:48
int cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output, int level)
Apply a CIB update patch to a given CIB.
Definition: cib_utils.c:918
#define PCMK__XA_SUBT
enum crm_ais_msg_types type
Definition: cpg.c:51
Supported in a transaction.
Definition: internal.h:49
Deprecated Pacemaker configuration utilities.
void xml_accept_changes(xmlNode *xml)
Definition: xml.c:443
#define PCMK__XA_CIB_SECTION
gboolean only_success
Definition: internal.h:106
void pcmk__validate_cluster_options(GHashTable *options)
Definition: options.c:1565
const char * pcmk__cluster_option(GHashTable *options, const char *name)
Definition: options.c:1419
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:503
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:494
#define PCMK_XA_OPERATION
Definition: xml_names.h:349
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:1051
void cib_delete(cib_t *cib)
Free all memory used by CIB connection.
Definition: cib_client.c:771
cib_callback_client_t * cib__lookup_id(int call_id)
Definition: cib_client.c:818
bool cib__element_in_patchset(const xmlNode *patchset, const char *element)
Definition: cib_utils.c:199
bool xml_tracking_changes(xmlNode *xml)
Definition: xml.c:359
gboolean cib_read_config(GHashTable *options, xmlNode *current_cib)
Definition: cib_utils.c:856
int cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset)
Definition: cib_utils.c:75
const char * get_object_path(const char *object_type)
Definition: cib_utils.c:1086
void cib_metadata(void)
Definition: cib_utils.c:1110
#define crm_warn(fmt, args...)
Definition: logging.h:394
#define PCMK__XA_CIB_HOST
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition: cib_utils.c:970
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:1012
void pcmk__sleep_ms(unsigned int ms)
Definition: utils.c:359
cib_api_operations_t * cmds
Definition: cib_types.h:399
#define crm_debug(fmt, args...)
Definition: logging.h:402
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:669
void cib_native_callback(cib_t *cib, xmlNode *msg, int call_id, int rc)
Definition: cib_utils.c:772
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: patchset.c:1318
cib_conn_type
Definition: cib_types.h:50
#define PCMK__XA_CIB_CALLOPT
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:159
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:172
#define PCMK_XE_CHANGE
Definition: xml_names.h:74
void(* callback)(xmlNode *, int, int, xmlNode *, void *)
Definition: internal.h:103
#define crm_trace(fmt, args...)
Definition: logging.h:404
#define PCMK_XA_UPDATE_USER
Definition: xml_names.h:438
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:94
#define PCMK__XE_CIB_CALLDATA
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:395
#define crm_log_xml_debug(xml, text)
Definition: logging.h:411
#define PCMK_XE_CLUSTER_PROPERTY_SET
Definition: xml_names.h:84
#define PCMK__VALUE_CIB
#define PCMK_META_RESOURCE_STICKINESS
Definition: options.h:111
#define PCMK_XA_EPOCH
Definition: xml_names.h:268
Wrappers for and extensions to libxml2.
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
Definition: xml.c:702
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
#define crm_log_xml_warn(xml, text)
Definition: logging.h:408
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:198
const char * event
Definition: internal.h:95
Flag has no effect.
Definition: xml_internal.h:440
const char * pcmk_cib_parent_name_for(const char *element_name)
Get the parent element name of a given CIB element name.
Definition: cib.c:150
xmlNode * transaction
Definition: cib_types.h:401
#define PCMK_XA_ID
Definition: xml_names.h:301
Success.
Definition: results.h:251
int(*) int(* transient)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:561
#define PCMK_XA_VALUE
Definition: xml_names.h:442
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition: cib_utils.c:228
void free_xml(xmlNode *child)
Definition: xml.c:958
#define PCMK_XE_CONFIGURATION
Definition: xml_names.h:87
gboolean cib_diff_version_details(xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates)
Definition: cib_utils.c:46
#define PCMK_XA_VALIDATE_WITH
Definition: xml_names.h:441
const char * pcmk__cib_abs_xpath_for(const char *element)
Definition: cib.c:133
#define PCMK_XE_META_ATTRIBUTES
Definition: xml_names.h:130
void pcmk__output_free(pcmk__output_t *out)
Definition: output.c:30
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
Definition: patchset.c:386
const char * pcmk_cib_xpath_for(const char *element_name)
Get the relative XPath needed to find a specified CIB element name.
Definition: cib.c:112
#define pcmk__assert(expr)
#define PCMK_XA_CRM_FEATURE_SET
Definition: xml_names.h:254
int(* cib__op_fn_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:85
#define CRM_XS
Definition: logging.h:56
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
#define pcmk_err_diff_resync
Definition: results.h:79
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:695
#define PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS
Definition: options.h:137
int cib__create_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name, const char *client_name, xmlNode **op_msg)
Definition: cib_utils.c:661
#define crm_err(fmt, args...)
Definition: logging.h:391
xmlNode * input
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:112
const char * id
Definition: internal.h:104
#define PCMK__XA_CIB_RC
#define PCMK__XA_CIB_OP
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:627
This structure contains everything that makes up a single output formatter.
#define crm_log_xml_info(xml, text)
Definition: logging.h:410
uint32_t flags
Group of enum cib__op_attr flags.
Definition: internal.h:91
enum cib_variant variant
Definition: cib_types.h:385
#define pcmk__plural_s(i)
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:616
#define pcmk_ok
Definition: results.h:65
#define pcmk__log_xml_patchset(level, patchset)
int call_id
Definition: cib_types.h:387
#define PCMK_XE_NODES
Definition: xml_names.h:142
int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv)
Definition: output.c:113
#define crm_log_xml_trace(xml, text)
Definition: logging.h:412
gboolean crm_is_true(const char *s)
Definition: strings.c:500
#define pcmk__log_xml_changes(level, xml)
#define PCMK__XA_CIB_USER
#define PCMK__XA_T
bool pcmk__configured_schema_validates(xmlNode *xml)
Definition: schemas.c:809
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
Definition: patchset.c:787
void pcmk__warn_if_schema_deprecated(const char *schema)
Definition: schemas.c:1595
int cib__get_operation(const char *op, const cib__operation_t **operation)
Definition: cib_ops.c:144
const char * cib_pref(GHashTable *options, const char *name)
Definition: cib_utils.c:1104
#define PCMK__XE_CIB_UPDATE_RESULT
const char * pcmk__highest_schema_name(void)
Definition: schemas.c:97
#define PCMK_XA_ADMIN_EPOCH
Definition: xml_names.h:232
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
#define PCMK__XA_CIB_CLIENTNAME
enum cib_state state
Definition: cib_types.h:382
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition: xml.c:2130
int(* client_id)(const cib_t *cib, const char **async_id, const char **sync_id)
Get the given CIB connection&#39;s unique client identifier(s)
Definition: cib_types.h:299
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version)
Definition: patchset.c:328
void cib_native_notify(gpointer data, gpointer user_data)
Definition: cib_utils.c:824
#define PCMK_XA_UPDATE_CLIENT
Definition: xml_names.h:436
#define PCMK__XA_CIB_CALLID
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
Definition: xml.c:1642
Process request when the client commits the active transaction.
Definition: cib_types.h:108
#define PCMK_XE_RESOURCES
Definition: xml_names.h:179
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition: acl.c:753
#define PCMK__XA_SRC
#define log_signon_query_err(out, fmt, args...)
Definition: cib_utils.c:961
int cib_internal_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options, const char *user_name)
Definition: cib_utils.c:884
#define PCMK_XE_CRM_CONFIG
Definition: xml_names.h:91
void * delegate_fn
Definition: cib_types.h:390
int pcmk__check_feature_set(const char *cib_version)
Definition: cib.c:184
int cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, cib__op_fn_t fn, bool is_query, const char *section, xmlNode *req, xmlNode *input, bool manage_counters, bool *config_changed, xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
Definition: cib_utils.c:332
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150