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