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