16 #include <sys/utsname.h>
28 struct config_root_s {
40 static struct config_root_s known_paths[] = {
41 { NULL, NULL,
"//cib" },
62 xmlNode *the_cib = NULL;
66 if (the_cib != NULL) {
94 int *_admin_epoch,
int *_epoch,
int *_updates)
96 int add[] = { 0, 0, 0 };
97 int del[] = { 0, 0, 0 };
101 *admin_epoch = add[0];
105 *_admin_epoch = del[0];
122 for (; lpc < max; lpc++) {
123 if ((object_type == NULL && known_paths[lpc].
name == NULL)
125 return known_paths[lpc].path;
137 for (; lpc < max; lpc++) {
139 return known_paths[lpc].parent;
168 xmlNode *cib_root = NULL, *config = NULL;
186 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
203 cib_acl_enabled(xmlNode *xml,
const char *user)
208 const char *value = NULL;
212 value =
cib_pref(options,
"enable-acl");
214 g_hash_table_destroy(options);
217 crm_trace(
"CIB ACL is %s", rc ?
"enabled" :
"disabled");
223 const char *section, xmlNode * req, xmlNode * input,
224 gboolean manage_counters, gboolean * config_changed,
225 xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
228 gboolean check_schema = TRUE;
230 xmlNode *scratch = NULL;
231 xmlNode *local_diff = NULL;
233 const char *new_version = NULL;
234 static struct qb_log_callsite *diff_cs = NULL;
236 bool with_digest = FALSE;
240 (is_query?
"read-only " :
""), op);
242 CRM_CHECK(output != NULL,
return -ENOMSG);
243 CRM_CHECK(result_cib != NULL,
return -ENOMSG);
244 CRM_CHECK(config_changed != NULL,
return -ENOMSG);
251 *config_changed = FALSE;
258 xmlNode *cib_ro = current_cib;
259 xmlNode *cib_filtered = NULL;
261 if(cib_acl_enabled(cib_ro, user)) {
263 if (cib_filtered == NULL) {
264 crm_debug(
"Pre-filtered the entire cib");
267 cib_ro = cib_filtered;
272 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
274 if(output == NULL || *output == NULL) {
277 }
else if(cib_filtered == *output) {
280 }
else if(*output == current_cib) {
283 }
else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
287 }
else if((*output)->doc == current_cib->doc) {
300 scratch = current_cib;
308 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
313 rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
316 crm_trace(
"Inferring changes after %s op", op);
317 xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
320 CRM_CHECK(current_cib != scratch,
return -EINVAL);
325 if (rc ==
pcmk_ok && scratch == NULL) {
330 crm_trace(
"ACL rejected part or all of the proposed changes");
342 crm_err(
"Discarding update with feature set '%s' greater than our own '%s'",
344 rc = -EPROTONOSUPPORT;
357 crm_err(
"%s went backwards: %d -> %d (Opts: 0x%x)",
363 }
else if (old ==
new) {
367 crm_err(
"%s went backwards: %d -> %d (Opts: 0x%x)",
386 local_diff =
xml_create_patchset(2, current_cib, scratch, (
bool*)config_changed, manage_counters);
389 static time_t expires = 0;
390 time_t tm_now = time(NULL);
392 if (expires < tm_now) {
393 expires = tm_now + 60;
397 local_diff =
xml_create_patchset(0, current_cib, scratch, (
bool*)config_changed, manage_counters);
403 if (diff_cs == NULL) {
404 diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__,
"diff-validation", LOG_DEBUG, __LINE__,
crm_trace_nonlog);
419 int test_rc, format = 1;
420 xmlNode * c =
copy_xml(current_cib);
430 crm_err(
"v%d patchset error, patch failed to apply: %s (%d)", format,
pcmk_strerror(test_rc), test_rc);
440 check_schema = FALSE;
460 static int minimum_schema = 0;
463 if (minimum_schema == 0) {
468 if (current_schema >= minimum_schema) {
480 crm_trace(
"Perform validation: %s", pcmk__btoa(check_schema));
485 crm_warn(
"Updated CIB does not validate against %s schema",
492 *result_cib = scratch;
493 if(rc !=
pcmk_ok && cib_acl_enabled(current_cib, user)) {
495 if (*result_cib == NULL) {
496 crm_debug(
"Pre-filtered the entire cib result");
514 cib_create_op(
int call_id,
const char *token,
const char *op,
const char *
host,
const char *section,
515 xmlNode *
data,
int call_options,
const char *user_name)
533 crm_trace(
"Sending call options: %.8lx, %d", (
long)call_options, call_options);
549 xmlNode *output = NULL;
560 crm_trace(
"No callback found for call %d", call_id);
587 crm_trace(
"Invoking global callback for call %d", call_id);
590 crm_trace(
"OP callback activated for %d", call_id);
596 xmlNode *msg = user_data;
598 const char *
event = NULL;
601 crm_warn(
"Skipping callback - NULL message");
608 crm_warn(
"Skipping callback - NULL callback client");
611 }
else if (entry->
callback == NULL) {
612 crm_warn(
"Skipping callback - NULL callback");
616 crm_trace(
"Skipping callback - event mismatch %p/%s vs. %s", entry, entry->
event, event);
620 crm_trace(
"Invoking callback for %p/%s event...", entry, event);
632 "enable-acl", NULL,
"boolean", NULL,
634 "Enable Access Control Lists (ACLs) for the CIB",
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)."
651 "Cluster Information Base manager options",
652 "Cluster options used by Pacemaker's "
653 "Cluster Information Base manager",
673 xmlNode *config = NULL;
676 if (options == NULL || current_cib == NULL) {
682 g_hash_table_remove_all(options);
698 #define XPATH_CONFIG_CHANGE \
699 "//" XML_CIB_TAG_CRMCONFIG " | " \
700 "//" XML_DIFF_CHANGE "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
705 gboolean changed = FALSE;
710 if (numXpathResults(xpathObj) > 0) {
720 const char *section, xmlNode *
data,
721 xmlNode ** output_data,
int call_options,
const char *user_name)
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) =
728 if(user_name == NULL) {
729 user_name = getenv(
"CIB_user");
732 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
752 xmlNode *diff = NULL;
761 if (rc <
pcmk_ok || diff == NULL) {
765 if (level > LOG_CRIT) {
774 crm_debug(
"Update didn't apply: %s (%d) %p",
778 crm_trace(
"Masking error, we already have the supplied update");
#define pcmk_err_old_data
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
#define CRM_CHECK(expr, failure_action)
#define XML_ATTR_UPDATE_ORIG
#define pcmk_err_schema_validation
xmlNode * get_message_xml(xmlNode *msg, const char *field)
#define XML_ATTR_UPDATE_CLIENT
const char * pcmk_strerror(int rc)
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
#define XML_CIB_TAG_SECTION_ALL
#define XML_ATTR_NUMUPDATES
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.
#define XPATH_CONFIG_CHANGE
const char * pcmk__xe_add_last_written(xmlNode *xe)
struct crm_time_s crm_time_t
#define XML_CIB_TAG_CONSTRAINTS
#define PCMK__RESOURCE_STICKINESS_DEFAULT
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
#define XML_ATTR_UPDATE_USER
const char * get_object_path(const char *object_type)
#define XML_TAG_FENCING_TOPOLOGY
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
void remove_cib_op_callback(int call_id, gboolean all_callbacks)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
#define F_CIB_CALLBACK_TOKEN
#define XML_NVPAIR_ATTR_NAME
int get_schema_version(const char *name)
#define CRM_LOG_ASSERT(expr)
#define XML_RSC_ATTR_STICKINESS
void copy_in_properties(xmlNode *target, xmlNode *src)
void xml_accept_changes(xmlNode *xml)
unsigned int crm_trace_nonlog
#define XML_CIB_TAG_NVPAIR
const char * get_object_parent(const char *object_type)
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
#define XML_CIB_TAG_NODES
void(* callback)(const char *event, xmlNode *msg)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
bool pcmk__valid_positive_number(const char *value)
#define XML_ATTR_GENERATION
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
#define XML_CIB_TAG_PROPSET
bool xml_tracking_changes(xmlNode *xml)
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)
void cib_native_notify(gpointer data, gpointer user_data)
xmlNode * copy_xml(xmlNode *src_node)
#define XML_CIB_TAG_RESOURCES
xmlNode * cib_get_generation(cib_t *cib)
void(* callback)(xmlNode *, int, int, xmlNode *, void *)
#define crm_warn(fmt, args...)
void pcmk__strip_xml_text(xmlNode *xml)
cib_api_operations_t * cmds
#define crm_debug(fmt, args...)
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
gboolean cib_internal_config_changed(xmlNode *diff)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Replace an XML attribute with specified name and (possibly NULL) value.
#define crm_trace(fmt, args...)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
#define crm_log_xml_debug(xml, text)
#define F_CIB_UPDATE_RESULT
#define XML_TAG_META_SETS
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
#define crm_log_xml_warn(xml, text)
#define XML_ATTR_VALIDATION
#define CIB_OPTIONS_FIRST
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
const char * pcmk__cluster_option(GHashTable *options, pcmk__cluster_option_t *option_list, int len, const char *name)
void free_xml(xmlNode *child)
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)
#define XML_CIB_TAG_GENERATION_TUPPLE
const char * xml_latest_schema(void)
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
GHashTable * cib_op_callback_table
void xml_log_changes(uint8_t level, const char *function, xmlNode *xml)
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
bool pcmk__valid_boolean(const char *value)
gboolean cib_read_config(GHashTable *options, xmlNode *current_cib)
#define pcmk_err_diff_resync
int cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output, int level)
Apply a CIB update patch to a given CIB.
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
#define crm_err(fmt, args...)
gboolean cib_diff_version_details(xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates)
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
crm_time_t * crm_time_new(const char *string)
#define XML_CIB_TAG_CRMCONFIG
#define XML_CIB_TAG_RSCCONFIG
void verify_cib_options(GHashTable *options)
bool xml_acl_denied(xmlNode *xml)
void xml_acl_disable(xmlNode *xml)
int compare_version(const char *version1, const char *version2)
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)
#define XML_ATTR_GENERATION_ADMIN
#define XML_NVPAIR_ATTR_VALUE
#define XML_ATTR_CRM_VERSION
const char * cib_pref(GHashTable *options, const char *name)
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
void cib_native_callback(cib_t *cib, xmlNode *msg, int call_id, int rc)
#define XML_CIB_TAG_STATUS
#define crm_log_xml_trace(xml, text)
void pcmk__validate_cluster_options(GHashTable *options, pcmk__cluster_option_t *option_list, int len)
gboolean crm_is_true(const char *s)
#define XML_CIB_TAG_ALERTS
#define XML_CIB_TAG_CONFIGURATION
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)
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
void fix_plus_plus_recursive(xmlNode *target)
void freeXpathObject(xmlXPathObjectPtr xpathObj)
#define XML_CIB_TAG_OPCONFIG
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version)
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
void crm_time_free(crm_time_t *dt)