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