pacemaker  2.1.6-802a72226b
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-2023 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>
25 #include <crm/pengine/rules.h>
26 
27 xmlNode *
29 {
30  xmlNode *the_cib = NULL;
31  xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
32 
33  cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
34  if (the_cib != NULL) {
35  copy_in_properties(generation, the_cib);
36  free_xml(the_cib);
37  }
38 
39  return generation;
40 }
41 
42 gboolean
43 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
44 {
45  *epoch = -1;
46  *updates = -1;
47  *admin_epoch = -1;
48 
49  if (cib == NULL) {
50  return FALSE;
51 
52  } else {
56  }
57  return TRUE;
58 }
59 
60 gboolean
61 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
62  int *_admin_epoch, int *_epoch, int *_updates)
63 {
64  int add[] = { 0, 0, 0 };
65  int del[] = { 0, 0, 0 };
66 
67  xml_patch_versions(diff, add, del);
68 
69  *admin_epoch = add[0];
70  *epoch = add[1];
71  *updates = add[2];
72 
73  *_admin_epoch = del[0];
74  *_epoch = del[1];
75  *_updates = del[2];
76 
77  return TRUE;
78 }
79 
88 xmlNode *
89 createEmptyCib(int cib_epoch)
90 {
91  xmlNode *cib_root = NULL, *config = NULL;
92 
93  cib_root = create_xml_node(NULL, XML_TAG_CIB);
96 
97  crm_xml_add_int(cib_root, XML_ATTR_GENERATION, cib_epoch);
100 
101  config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
103 
108 
109 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
110  {
111  xmlNode *rsc_defaults = create_xml_node(config, XML_CIB_TAG_RSCCONFIG);
112  xmlNode *meta = create_xml_node(rsc_defaults, XML_TAG_META_SETS);
113  xmlNode *nvpair = create_xml_node(meta, XML_CIB_TAG_NVPAIR);
114 
115  crm_xml_add(meta, XML_ATTR_ID, "build-resource-defaults");
120  }
121 #endif
122  return cib_root;
123 }
124 
125 static bool
126 cib_acl_enabled(xmlNode *xml, const char *user)
127 {
128  bool rc = FALSE;
129 
130  if(pcmk_acl_required(user)) {
131  const char *value = NULL;
132  GHashTable *options = pcmk__strkey_table(free, free);
133 
134  cib_read_config(options, xml);
135  value = cib_pref(options, "enable-acl");
136  rc = crm_is_true(value);
137  g_hash_table_destroy(options);
138  }
139 
140  crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
141  return rc;
142 }
143 
144 int
145 cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
146  const char *section, xmlNode * req, xmlNode * input,
147  gboolean manage_counters, gboolean * config_changed,
148  xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
149 {
150  int rc = pcmk_ok;
151  gboolean check_schema = TRUE;
152  xmlNode *top = NULL;
153  xmlNode *scratch = NULL;
154  xmlNode *local_diff = NULL;
155 
156  const char *new_version = NULL;
157  const char *user = crm_element_value(req, F_CIB_USER);
158  bool with_digest = FALSE;
159 
160  pcmk__output_t *out = NULL;
161  int out_rc = pcmk_rc_no_output;
162 
163  crm_trace("Begin %s%s%s op",
164  (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
165  (is_query? "read-only " : ""), op);
166 
167  CRM_CHECK(output != NULL, return -ENOMSG);
168  CRM_CHECK(result_cib != NULL, return -ENOMSG);
169  CRM_CHECK(config_changed != NULL, return -ENOMSG);
170 
171  if(output) {
172  *output = NULL;
173  }
174 
175  *result_cib = NULL;
176  *config_changed = FALSE;
177 
178  if (fn == NULL) {
179  return -EINVAL;
180  }
181 
182  if (is_query) {
183  xmlNode *cib_ro = current_cib;
184  xmlNode *cib_filtered = NULL;
185 
186  if(cib_acl_enabled(cib_ro, user)) {
187  if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
188  if (cib_filtered == NULL) {
189  crm_debug("Pre-filtered the entire cib");
190  return -EACCES;
191  }
192  cib_ro = cib_filtered;
193  crm_log_xml_trace(cib_ro, "filtered");
194  }
195  }
196 
197  rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
198 
199  if(output == NULL || *output == NULL) {
200  /* nothing */
201 
202  } else if(cib_filtered == *output) {
203  cib_filtered = NULL; /* Let them have this copy */
204 
205  } else if(*output == current_cib) {
206  /* They already know not to free it */
207 
208  } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
209  /* We're about to free the document of which *output is a part */
210  *output = copy_xml(*output);
211 
212  } else if((*output)->doc == current_cib->doc) {
213  /* Give them a copy they can free */
214  *output = copy_xml(*output);
215  }
216 
217  free_xml(cib_filtered);
218  return rc;
219  }
220 
221 
222  if (pcmk_is_set(call_options, cib_zero_copy)) {
223  /* Conditional on v2 patch style */
224 
225  scratch = current_cib;
226 
227  /* Create a shallow copy of current_cib for the version details */
228  current_cib = create_xml_node(NULL, (const char *)scratch->name);
229  copy_in_properties(current_cib, scratch);
230  top = current_cib;
231 
232  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
233  rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
234 
235  } else {
236  scratch = copy_xml(current_cib);
237  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
238  rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
239 
240  if(scratch && xml_tracking_changes(scratch) == FALSE) {
241  crm_trace("Inferring changes after %s op", op);
242  xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
243  xml_calculate_changes(current_cib, scratch);
244  }
245  CRM_CHECK(current_cib != scratch, return -EINVAL);
246  }
247 
248  xml_acl_disable(scratch); /* Allow the system to make any additional changes */
249 
250  if (rc == pcmk_ok && scratch == NULL) {
251  rc = -EINVAL;
252  goto done;
253 
254  } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
255  crm_trace("ACL rejected part or all of the proposed changes");
256  rc = -EACCES;
257  goto done;
258 
259  } else if (rc != pcmk_ok) {
260  goto done;
261  }
262 
263  if (scratch) {
264  new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
265 
266  if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
267  crm_err("Discarding update with feature set '%s' greater than our own '%s'",
268  new_version, CRM_FEATURE_SET);
269  rc = -EPROTONOSUPPORT;
270  goto done;
271  }
272  }
273 
274  if (current_cib) {
275  int old = 0;
276  int new = 0;
277 
280 
281  if (old > new) {
282  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
283  XML_ATTR_GENERATION_ADMIN, old, new, call_options);
284  crm_log_xml_warn(req, "Bad Op");
285  crm_log_xml_warn(input, "Bad Data");
286  rc = -pcmk_err_old_data;
287 
288  } else if (old == new) {
290  crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
291  if (old > new) {
292  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
293  XML_ATTR_GENERATION, old, new, call_options);
294  crm_log_xml_warn(req, "Bad Op");
295  crm_log_xml_warn(input, "Bad Data");
296  rc = -pcmk_err_old_data;
297  }
298  }
299  }
300 
301  crm_trace("Massaging CIB contents");
302  pcmk__strip_xml_text(scratch);
303  fix_plus_plus_recursive(scratch);
304 
305  if (pcmk_is_set(call_options, cib_zero_copy)) {
306  /* At this point, current_cib is just the 'cib' tag and its properties,
307  *
308  * The v1 format would barf on this, but we know the v2 patch
309  * format only needs it for the top-level version fields
310  */
311  local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters);
312 
313  } else {
314  static time_t expires = 0;
315  time_t tm_now = time(NULL);
316 
317  if (expires < tm_now) {
318  expires = tm_now + 60; /* Validate clients are correctly applying v2-style diffs at most once a minute */
319  with_digest = TRUE;
320  }
321 
322  local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters);
323  }
324 
325  // Create a log output object only if we're going to use it
327  {
329  CRM_CHECK(rc == pcmk_ok, goto done);
330 
332  out_rc = pcmk__xml_show_changes(out, scratch);
333  },
334  {}
335  );
336  xml_accept_changes(scratch);
337 
338  if(local_diff) {
339  int temp_rc = pcmk_rc_no_output;
340 
341  patchset_process_digest(local_diff, current_cib, scratch, with_digest);
342 
343  if (out == NULL) {
345  CRM_CHECK(rc == pcmk_ok, goto done);
346  }
347  pcmk__output_set_log_level(out, LOG_INFO);
348  temp_rc = out->message(out, "xml-patchset", local_diff);
349  out_rc = pcmk__output_select_rc(rc, temp_rc);
350 
351  crm_log_xml_trace(local_diff, "raw patch");
352  }
353 
354  if (out != NULL) {
355  out->finish(out, pcmk_rc2exitc(out_rc), true, NULL);
356  pcmk__output_free(out);
357  out = NULL;
358  }
359 
360  if (!pcmk_is_set(call_options, cib_zero_copy) && (local_diff != NULL)) {
361  // Original to compare against doesn't exist
363  {
364  // Validate the calculated patch set
365  int test_rc = pcmk_ok;
366  int format = 1;
367  xmlNode *cib_copy = copy_xml(current_cib);
368 
369  crm_element_value_int(local_diff, "format", &format);
370  test_rc = xml_apply_patchset(cib_copy, local_diff,
371  manage_counters);
372 
373  if (test_rc != pcmk_ok) {
374  save_xml_to_file(cib_copy, "PatchApply:calculated", NULL);
375  save_xml_to_file(current_cib, "PatchApply:input", NULL);
376  save_xml_to_file(scratch, "PatchApply:actual", NULL);
377  save_xml_to_file(local_diff, "PatchApply:diff", NULL);
378  crm_err("v%d patchset error, patch failed to apply: %s "
379  "(%d)",
380  format, pcmk_rc_str(pcmk_legacy2rc(test_rc)),
381  test_rc);
382  }
383  free_xml(cib_copy);
384  },
385  {}
386  );
387  }
388 
389  if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
390  /* Throttle the amount of costly validation we perform due to status updates
391  * a) we don't really care whats in the status section
392  * b) we don't validate any of its contents at the moment anyway
393  */
394  check_schema = FALSE;
395  }
396 
397  /* === scratch must not be modified after this point ===
398  * Exceptions, anything in:
399 
400  static filter_t filter[] = {
401  { 0, XML_ATTR_ORIGIN },
402  { 0, XML_CIB_ATTR_WRITTEN },
403  { 0, XML_ATTR_UPDATE_ORIG },
404  { 0, XML_ATTR_UPDATE_CLIENT },
405  { 0, XML_ATTR_UPDATE_USER },
406  };
407  */
408 
409  if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
410  const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
411 
412  pcmk__xe_add_last_written(scratch);
413  if (schema) {
414  static int minimum_schema = 0;
415  int current_schema = get_schema_version(schema);
416 
417  if (minimum_schema == 0) {
418  minimum_schema = get_schema_version("pacemaker-1.2");
419  }
420 
421  /* Does the CIB support the "update-*" attributes... */
422  if (current_schema >= minimum_schema) {
423  const char *origin = crm_element_value(req, F_ORIG);
424 
425  CRM_LOG_ASSERT(origin != NULL);
426  crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
430  }
431  }
432  }
433 
434  crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
435  if ((rc == pcmk_ok) && check_schema && !validate_xml(scratch, NULL, TRUE)) {
436  const char *current_schema = crm_element_value(scratch,
438 
439  crm_warn("Updated CIB does not validate against %s schema",
440  pcmk__s(current_schema, "unspecified"));
442  }
443 
444  done:
445 
446  *result_cib = scratch;
447  if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
448  if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
449  if (*result_cib == NULL) {
450  crm_debug("Pre-filtered the entire cib result");
451  }
452  free_xml(scratch);
453  }
454  }
455 
456  if(diff) {
457  *diff = local_diff;
458  } else {
459  free_xml(local_diff);
460  }
461 
462  free_xml(top);
463  crm_trace("Done");
464  return rc;
465 }
466 
467 xmlNode *
468 cib_create_op(int call_id, const char *op, const char *host,
469  const char *section, xmlNode *data, int call_options,
470  const char *user_name)
471 {
472  xmlNode *op_msg = create_xml_node(NULL, "cib_command");
473 
474  CRM_CHECK(op_msg != NULL, return NULL);
475 
476  crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
477 
478  crm_xml_add(op_msg, F_TYPE, T_CIB);
479  crm_xml_add(op_msg, F_CIB_OPERATION, op);
480  crm_xml_add(op_msg, F_CIB_HOST, host);
481  crm_xml_add(op_msg, F_CIB_SECTION, section);
482  crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
483  if (user_name) {
484  crm_xml_add(op_msg, F_CIB_USER, user_name);
485  }
486  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
487  crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
488 
489  if (data != NULL) {
491  }
492 
493  if (call_options & cib_inhibit_bcast) {
494  CRM_CHECK((call_options & cib_scope_local), return NULL);
495  }
496  return op_msg;
497 }
498 
499 void
500 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
501 {
502  xmlNode *output = NULL;
503  cib_callback_client_t *blob = NULL;
504 
505  if (msg != NULL) {
506  crm_element_value_int(msg, F_CIB_RC, &rc);
507  crm_element_value_int(msg, F_CIB_CALLID, &call_id);
508  output = get_message_xml(msg, F_CIB_CALLDATA);
509  }
510 
511  blob = cib__lookup_id(call_id);
512 
513  if (blob == NULL) {
514  crm_trace("No callback found for call %d", call_id);
515  }
516 
517  if (cib == NULL) {
518  crm_debug("No cib object supplied");
519  }
520 
521  if (rc == -pcmk_err_diff_resync) {
522  /* This is an internal value that clients do not and should not care about */
523  rc = pcmk_ok;
524  }
525 
526  if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
527  crm_trace("Invoking callback %s for call %d",
528  pcmk__s(blob->id, "without ID"), call_id);
529  blob->callback(msg, call_id, rc, output, blob->user_data);
530 
531  } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
532  crm_warn("CIB command failed: %s", pcmk_strerror(rc));
533  crm_log_xml_debug(msg, "Failed CIB Update");
534  }
535 
536  /* This may free user_data, so do it after the callback */
537  if (blob) {
538  remove_cib_op_callback(call_id, FALSE);
539  }
540 
541  if (cib && cib->op_callback != NULL) {
542  crm_trace("Invoking global callback for call %d", call_id);
543  cib->op_callback(msg, call_id, rc, output);
544  }
545  crm_trace("OP callback activated for %d", call_id);
546 }
547 
548 void
549 cib_native_notify(gpointer data, gpointer user_data)
550 {
551  xmlNode *msg = user_data;
552  cib_notify_client_t *entry = data;
553  const char *event = NULL;
554 
555  if (msg == NULL) {
556  crm_warn("Skipping callback - NULL message");
557  return;
558  }
559 
560  event = crm_element_value(msg, F_SUBTYPE);
561 
562  if (entry == NULL) {
563  crm_warn("Skipping callback - NULL callback client");
564  return;
565 
566  } else if (entry->callback == NULL) {
567  crm_warn("Skipping callback - NULL callback");
568  return;
569 
570  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
571  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
572  return;
573  }
574 
575  crm_trace("Invoking callback for %p/%s event...", entry, event);
576  entry->callback(event, msg);
577  crm_trace("Callback invoked...");
578 }
579 
580 static pcmk__cluster_option_t cib_opts[] = {
581  /* name, legacy name, type, allowed values,
582  * default value, validator,
583  * short description,
584  * long description
585  */
586  {
587  "enable-acl", NULL, "boolean", NULL,
588  "false", pcmk__valid_boolean,
589  N_("Enable Access Control Lists (ACLs) for the CIB"),
590  NULL
591  },
592  {
593  "cluster-ipc-limit", NULL, "integer", NULL,
595  N_("Maximum IPC message backlog before disconnecting a cluster daemon"),
596  N_("Raise this if log has \"Evicting client\" messages for cluster daemon"
597  " PIDs (a good value is the number of resources in the cluster"
598  " multiplied by the number of nodes).")
599  },
600 };
601 
602 void
604 {
605  const char *desc_short = "Cluster Information Base manager options";
606  const char *desc_long = "Cluster options used by Pacemaker's Cluster "
607  "Information Base manager";
608 
609  gchar *s = pcmk__format_option_metadata("pacemaker-based", desc_short,
610  desc_long, cib_opts,
611  PCMK__NELEM(cib_opts));
612  printf("%s", s);
613  g_free(s);
614 }
615 
616 static void
617 verify_cib_options(GHashTable *options)
618 {
619  pcmk__validate_cluster_options(options, cib_opts, PCMK__NELEM(cib_opts));
620 }
621 
622 const char *
623 cib_pref(GHashTable * options, const char *name)
624 {
625  return pcmk__cluster_option(options, cib_opts, PCMK__NELEM(cib_opts),
626  name);
627 }
628 
629 gboolean
630 cib_read_config(GHashTable * options, xmlNode * current_cib)
631 {
632  xmlNode *config = NULL;
633  crm_time_t *now = NULL;
634 
635  if (options == NULL || current_cib == NULL) {
636  return FALSE;
637  }
638 
639  now = crm_time_new(NULL);
640 
641  g_hash_table_remove_all(options);
642 
643  config = pcmk_find_cib_element(current_cib, XML_CIB_TAG_CRMCONFIG);
644  if (config) {
645  pe_unpack_nvpairs(current_cib, config, XML_CIB_TAG_PROPSET, NULL,
646  options, CIB_OPTIONS_FIRST, TRUE, now, NULL);
647  }
648 
649  verify_cib_options(options);
650 
651  crm_time_free(now);
652 
653  return TRUE;
654 }
655 
656 int
657 cib_internal_op(cib_t * cib, const char *op, const char *host,
658  const char *section, xmlNode * data,
659  xmlNode ** output_data, int call_options, const char *user_name)
660 {
661  int (*delegate) (cib_t * cib, const char *op, const char *host,
662  const char *section, xmlNode * data,
663  xmlNode ** output_data, int call_options, const char *user_name) =
664  cib->delegate_fn;
665 
666  if(user_name == NULL) {
667  user_name = getenv("CIB_user");
668  }
669 
670  return delegate(cib, op, host, section, data, output_data, call_options, user_name);
671 }
672 
684 int
685 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
686  int level)
687 {
688  int rc = pcmk_err_generic;
689 
690  xmlNode *diff = NULL;
691 
692  CRM_ASSERT(event);
693  CRM_ASSERT(input);
694  CRM_ASSERT(output);
695 
696  crm_element_value_int(event, F_CIB_RC, &rc);
697  diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
698 
699  if (rc < pcmk_ok || diff == NULL) {
700  return rc;
701  }
702 
703  if (level > LOG_CRIT) {
704  pcmk__output_t *out = NULL;
705 
707  CRM_CHECK(rc == pcmk_ok, return rc);
708 
709  pcmk__output_set_log_level(out, level);
710  rc = out->message(out, "xml-patchset", diff);
711  out->finish(out, pcmk_rc2exitc(rc), true, NULL);
712  pcmk__output_free(out);
713  rc = pcmk_ok;
714  }
715 
716  if (input != NULL) {
717  rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
718  NULL);
719 
720  if (rc != pcmk_ok) {
721  crm_debug("Update didn't apply: %s (%d) %p",
722  pcmk_strerror(rc), rc, *output);
723 
724  if (rc == -pcmk_err_old_data) {
725  crm_trace("Masking error, we already have the supplied update");
726  return pcmk_ok;
727  }
728  free_xml(*output);
729  *output = NULL;
730  return rc;
731  }
732  }
733  return rc;
734 }
735 
736 #define log_signon_query_err(out, fmt, args...) do { \
737  if (out != NULL) { \
738  out->err(out, fmt, ##args); \
739  } else { \
740  crm_err(fmt, ##args); \
741  } \
742  } while (0)
743 
744 int
745 cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
746 {
747  int rc = pcmk_rc_ok;
748  cib_t *cib_conn = NULL;
749 
750  CRM_ASSERT(cib_object != NULL);
751 
752  if (cib == NULL) {
753  cib_conn = cib_new();
754  } else {
755  if (*cib == NULL) {
756  *cib = cib_new();
757  }
758  cib_conn = *cib;
759  }
760 
761  if (cib_conn == NULL) {
762  return ENOMEM;
763  }
764 
765  if (cib_conn->state == cib_disconnected) {
766  rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
767  rc = pcmk_legacy2rc(rc);
768  }
769 
770  if (rc != pcmk_rc_ok) {
771  log_signon_query_err(out, "Could not connect to the CIB: %s",
772  pcmk_rc_str(rc));
773  goto done;
774  }
775 
776  if (out != NULL) {
777  out->transient(out, "Querying CIB...");
778  }
779  rc = cib_conn->cmds->query(cib_conn, NULL, cib_object,
781  rc = pcmk_legacy2rc(rc);
782 
783  if (rc != pcmk_rc_ok) {
784  log_signon_query_err(out, "CIB query failed: %s", pcmk_rc_str(rc));
785  }
786 
787 done:
788  if (cib == NULL) {
789  cib__clean_up_connection(&cib_conn);
790  }
791 
792  if ((rc == pcmk_rc_ok) && (*cib_object == NULL)) {
793  return pcmk_rc_no_input;
794  }
795  return rc;
796 }
797 
798 int
800 {
801  int rc;
802 
803  if (*cib == NULL) {
804  return pcmk_rc_ok;
805  }
806 
807  rc = (*cib)->cmds->signoff(*cib);
808  cib_delete(*cib);
809  *cib = NULL;
810  return pcmk_legacy2rc(rc);
811 }
812 
813 // Deprecated functions kept only for backward API compatibility
814 // LCOV_EXCL_START
815 
816 #include <crm/cib/util_compat.h>
817 
818 const char *
819 get_object_path(const char *object_type)
820 {
821  return pcmk_cib_xpath_for(object_type);
822 }
823 
824 const char *
825 get_object_parent(const char *object_type)
826 {
827  return pcmk_cib_parent_name_for(object_type);
828 }
829 
830 xmlNode *
831 get_object_root(const char *object_type, xmlNode *the_root)
832 {
833  return pcmk_find_cib_element(the_root, object_type);
834 }
835 
836 // LCOV_EXCL_STOP
837 // End deprecated API
#define pcmk_err_old_data
Definition: results.h:75
#define LOG_TRACE
Definition: logging.h:37
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
#define XML_ATTR_UPDATE_ORIG
Definition: msg_xml.h:155
#define pcmk_err_schema_validation
Definition: results.h:73
const char * get_object_parent(const char *object_type)
Definition: cib_utils.c:825
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:82
#define XML_ATTR_UPDATE_CLIENT
Definition: msg_xml.h:156
const char * pcmk_strerror(int rc)
Definition: results.c:148
char data[0]
Definition: cpg.c:55
#define pcmk__if_tracing(if_action, else_action)
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:140
int pcmk_rc2legacy(int rc)
Definition: results.c:533
cib_t * cib_new(void)
Create a new CIB connection object.
Definition: cib_client.c:535
const char * name
Definition: cib.c:24
int(* message)(pcmk__output_t *out, const char *message_id,...)
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1077
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define XML_CIB_TAG_CONSTRAINTS
Definition: msg_xml.h:202
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:43
#define PCMK__RESOURCE_STICKINESS_DEFAULT
Definition: config.h:553
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:438
#define F_SUBTYPE
Definition: msg_xml.h:78
void(* callback)(const char *event, xmlNode *msg)
Definition: internal.h:95
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:398
#define CRM_FEATURE_SET
Definition: crm.h:69
void copy_in_properties(xmlNode *target, const xmlNode *src)
Definition: xml.c:481
#define XML_ATTR_UPDATE_USER
Definition: msg_xml.h:157
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:689
xmlNode * cib_get_generation(cib_t *cib)
Definition: cib_utils.c:28
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
Definition: xml.c:270
void remove_cib_op_callback(int call_id, gboolean all_callbacks)
Definition: cib_client.c:709
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:302
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:831
#define pcmk_err_generic
Definition: results.h:71
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:403
int get_schema_version(const char *name)
Definition: schemas.c:1033
char * crm_system_name
Definition: utils.c:51
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:685
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
#define XML_RSC_ATTR_STICKINESS
Definition: msg_xml.h:252
Deprecated Pacemaker configuration utilities.
void xml_accept_changes(xmlNode *xml)
Definition: xml.c:379
gboolean only_success
Definition: internal.h:103
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:219
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:488
void pcmk__output_set_log_level(pcmk__output_t *out, uint8_t log_level)
Definition: output_log.c:345
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:532
#define XML_CIB_TAG_NODES
Definition: msg_xml.h:200
#define F_CIB_SECTION
Definition: internal.h:42
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:799
bool pcmk__valid_positive_number(const char *value)
Definition: options.c:196
void cib_delete(cib_t *cib)
Free all memory used by CIB connection.
Definition: cib_client.c:700
#define XML_ATTR_GENERATION
Definition: msg_xml.h:138
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:707
cib_callback_client_t * cib__lookup_id(int call_id)
Definition: cib_client.c:747
#define XML_CIB_TAG_PROPSET
Definition: msg_xml.h:221
bool xml_tracking_changes(xmlNode *xml)
Definition: xml.c:285
gboolean cib_read_config(GHashTable *options, xmlNode *current_cib)
Definition: cib_utils.c:630
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:819
const char * get_object_path(const char *object_type)
Definition: cib_utils.c:819
void cib_metadata(void)
Definition: cib_utils.c:603
#define XML_CIB_TAG_RESOURCES
Definition: msg_xml.h:199
#define crm_warn(fmt, args...)
Definition: logging.h:378
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition: cib_utils.c:745
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:979
cib_api_operations_t * cmds
Definition: cib_types.h:216
#define crm_debug(fmt, args...)
Definition: logging.h:382
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:636
void cib_native_callback(cib_t *cib, xmlNode *msg, int call_id, int rc)
Definition: cib_utils.c:500
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: patchset.c:1096
#define F_CIB_RC
Definition: internal.h:44
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:84
xmlNode * cib_create_op(int call_id, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
Definition: cib_utils.c:468
#define XML_ATTR_ID
Definition: msg_xml.h:147
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
#define F_CIB_OPERATION
Definition: internal.h:40
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
#define F_CIB_CLIENTNAME
Definition: internal.h:55
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Replace an XML attribute with specified name and (possibly NULL) value.
Definition: nvpair.c:347
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:127
void(* callback)(xmlNode *, int, int, xmlNode *, void *)
Definition: internal.h:100
#define crm_trace(fmt, args...)
Definition: logging.h:383
gchar * pcmk__format_option_metadata(const char *name, const char *desc_short, const char *desc_long, pcmk__cluster_option_t *option_list, int len)
Definition: options.c:413
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
#define F_CIB_USER
Definition: internal.h:59
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:214
#define crm_log_xml_debug(xml, text)
Definition: logging.h:390
const char * pcmk__cluster_option(GHashTable *options, const pcmk__cluster_option_t *option_list, int len, const char *name)
Definition: options.c:337
#define F_CIB_UPDATE_RESULT
Definition: internal.h:54
#define F_CIB_HOST
Definition: internal.h:43
#define XML_TAG_META_SETS
Definition: msg_xml.h:223
Wrappers for and extensions to libxml2.
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:677
#define crm_log_xml_warn(xml, text)
Definition: logging.h:387
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:532
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:103
#define PCMK__NELEM(a)
Definition: internal.h:44
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:133
const char * event
Definition: internal.h:92
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:131
int(*) int(* transient)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:546
#define CIB_OPTIONS_FIRST
Definition: msg_xml.h:101
#define F_ORIG
Definition: msg_xml.h:70
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition: cib_utils.c:89
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:160
void free_xml(xmlNode *child)
Definition: xml.c:813
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:61
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
#define XML_CIB_TAG_GENERATION_TUPPLE
Definition: msg_xml.h:422
#define T_CIB
Definition: internal.h:65
const char * xml_latest_schema(void)
Definition: schemas.c:113
void pcmk__output_free(pcmk__output_t *out)
Definition: output.c:28
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
Definition: patchset.c:376
const char * pcmk_cib_xpath_for(const char *element_name)
Get the XPath needed to find a specified CIB element name.
Definition: cib.c:110
#define XML_TAG_CIB
Definition: msg_xml.h:128
bool pcmk__valid_boolean(const char *value)
Definition: options.c:174
#define N_(String)
Definition: crm_internal.h:48
#define pcmk_err_diff_resync
Definition: results.h:77
#define F_CIB_CALLOPTS
Definition: internal.h:37
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
#define F_CIB_CALLDATA
Definition: internal.h:39
#define crm_err(fmt, args...)
Definition: logging.h:377
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlNode * input
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
#define XML_CIB_TAG_CRMCONFIG
Definition: msg_xml.h:203
#define XML_CIB_TAG_RSCCONFIG
Definition: msg_xml.h:205
const char * id
Definition: internal.h:101
int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
Definition: xml_display.c:370
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:619
This structure contains everything that makes up a single output formatter.
int compare_version(const char *version1, const char *version2)
Definition: utils.c:189
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:139
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:404
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:131
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
Definition: xml.c:1753
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:608
#define pcmk_ok
Definition: results.h:68
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:198
#define crm_log_xml_trace(xml, text)
Definition: logging.h:391
void pcmk__validate_cluster_options(GHashTable *options, pcmk__cluster_option_t *option_list, int len)
Definition: options.c:488
#define F_CIB_CALLID
Definition: internal.h:38
gboolean crm_is_true(const char *s)
Definition: strings.c:416
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
Definition: patchset.c:572
const char * cib_pref(GHashTable *options, const char *name)
Definition: cib_utils.c:623
#define XML_CIB_TAG_CONFIGURATION
Definition: msg_xml.h:197
#define F_XML_TAGNAME
Definition: msg_xml.h:90
void fix_plus_plus_recursive(xmlNode *target)
Parse integer assignment statements on this node and all its child nodes.
Definition: xml.c:514
enum cib_state state
Definition: cib_types.h:204
int cib_perform_op(const char *op, int call_options, cib_op_t *fn, gboolean is_query, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, xmlNode *current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
Definition: cib_utils.c:145
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version)
Definition: patchset.c:319
void cib_native_notify(gpointer data, gpointer user_data)
Definition: cib_utils.c:549
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
Definition: xml.c:2103
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition: acl.c:746
#define log_signon_query_err(out, fmt, args...)
Definition: cib_utils.c:736
int pcmk__log_output_new(pcmk__output_t **out)
Definition: output.c:272
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:657
void * delegate_fn
Definition: cib_types.h:211
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150