Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842461
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c
index f0e33a9a8c..660a76c124 100644
--- a/lib/cib/cib_ops.c
+++ b/lib/cib/cib_ops.c
@@ -1,838 +1,838 @@
/*
- * Copyright 2004-2020 the Pacemaker project contributors
+ * Copyright 2004-2021 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <crm/crm.h>
#include <crm/cib/internal.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h>
int
cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
xmlNode *obj_root = NULL;
int result = pcmk_ok;
crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
if (options & cib_xpath) {
return cib_process_xpath(op, options, section, req, input,
existing_cib, result_cib, answer);
}
CRM_CHECK(*answer == NULL, free_xml(*answer));
*answer = NULL;
if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
section = NULL;
}
obj_root = get_object_root(section, existing_cib);
if (obj_root == NULL) {
result = -ENXIO;
} else if (options & cib_no_children) {
const char *tag = TYPE(obj_root);
xmlNode *shallow = create_xml_node(*answer, tag);
copy_in_properties(shallow, obj_root);
*answer = shallow;
} else {
*answer = obj_root;
}
if (result == pcmk_ok && *answer == NULL) {
crm_err("Error creating query response");
result = -ENOMSG;
}
return result;
}
int
cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
int result = pcmk_ok;
crm_trace("Processing \"%s\" event", op);
*answer = NULL;
free_xml(*result_cib);
*result_cib = createEmptyCib(0);
copy_in_properties(*result_cib, existing_cib);
cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
return result;
}
int
cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
xmlNode ** answer)
{
int rc = 0;
int new_version = 0;
int current_version = 0;
int max_version = 0;
const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
*answer = NULL;
crm_trace("Processing \"%s\" event with max=%s", op, max);
if (value != NULL) {
current_version = get_schema_version(value);
}
if (max) {
max_version = get_schema_version(max);
}
rc = update_validation(result_cib, &new_version, max_version, TRUE,
!(options & cib_verbose));
if (new_version > current_version) {
cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
return pcmk_ok;
}
return rc;
}
int
cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
int result = pcmk_ok;
crm_trace("Processing \"%s\" event for epoch=%s",
op, crm_str(crm_element_value(existing_cib, XML_ATTR_GENERATION)));
*answer = NULL;
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
return result;
}
int
cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
{
char *new_value = NULL;
char *old_value = NULL;
int int_value = -1;
if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
old_value = crm_element_value_copy(xml_obj, field);
}
if (old_value != NULL) {
int_value = atoi(old_value);
new_value = pcmk__itoa(++int_value);
} else {
new_value = strdup("1");
}
crm_trace("%s %d(%s)->%s", field, int_value, crm_str(old_value), crm_str(new_value));
crm_xml_add(xml_obj, field, new_value);
free(new_value);
free(old_value);
return pcmk_ok;
}
int
cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
xmlNode ** answer)
{
const char *tag = NULL;
int result = pcmk_ok;
crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
if (options & cib_xpath) {
return cib_process_xpath(op, options, section, req, input,
existing_cib, result_cib, answer);
}
*answer = NULL;
if (input == NULL) {
return -EINVAL;
}
tag = crm_element_name(input);
if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
section = NULL;
} else if (pcmk__str_eq(tag, section, pcmk__str_casei)) {
section = NULL;
}
if (pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
int updates = 0;
int epoch = 0;
int admin_epoch = 0;
int replace_updates = 0;
int replace_epoch = 0;
int replace_admin_epoch = 0;
const char *reason = NULL;
const char *peer = crm_element_value(req, F_ORIG);
const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
if (digest) {
const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
version ? version :
CRM_FEATURE_SET);
if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
digest_verify, digest);
reason = "digest mismatch";
} else {
crm_info("Digest matched on replace from %s: %s", peer, digest);
}
free(digest_verify);
} else {
crm_trace("No digest to verify");
}
cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
if (replace_admin_epoch < admin_epoch) {
reason = XML_ATTR_GENERATION_ADMIN;
} else if (replace_admin_epoch > admin_epoch) {
/* no more checks */
} else if (replace_epoch < epoch) {
reason = XML_ATTR_GENERATION;
} else if (replace_epoch > epoch) {
/* no more checks */
} else if (replace_updates < updates) {
reason = XML_ATTR_NUMUPDATES;
}
if (reason != NULL) {
crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
" current %s is greater than the replacement",
replace_admin_epoch, replace_epoch,
replace_updates, peer, admin_epoch, epoch, updates, reason);
result = -pcmk_err_old_data;
} else {
crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
admin_epoch, epoch, updates,
replace_admin_epoch, replace_epoch, replace_updates, peer);
}
free_xml(*result_cib);
*result_cib = copy_xml(input);
} else {
xmlNode *obj_root = NULL;
gboolean ok = TRUE;
obj_root = get_object_root(section, *result_cib);
ok = replace_xml_child(NULL, obj_root, input, FALSE);
if (ok == FALSE) {
crm_trace("No matching object to replace");
result = -ENXIO;
}
}
return result;
}
int
cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
xmlNode *obj_root = NULL;
crm_trace("Processing \"%s\" event", op);
if (options & cib_xpath) {
return cib_process_xpath(op, options, section, req, input,
existing_cib, result_cib, answer);
}
if (input == NULL) {
crm_err("Cannot perform modification with no data");
return -EINVAL;
}
obj_root = get_object_root(section, *result_cib);
if(pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
xmlNode *child = NULL;
for (child = pcmk__xml_first_child(input); child;
child = pcmk__xml_next(child)) {
if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
}
}
} else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
}
return pcmk_ok;
}
int
cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
xmlNode *obj_root = NULL;
crm_trace("Processing \"%s\" event", op);
if (options & cib_xpath) {
return cib_process_xpath(op, options, section, req, input,
existing_cib, result_cib, answer);
}
if (input == NULL) {
crm_err("Cannot perform modification with no data");
return -EINVAL;
}
obj_root = get_object_root(section, *result_cib);
if (obj_root == NULL) {
xmlNode *tmp_section = NULL;
- const char *path = get_object_parent(section);
+ const char *path = pcmk_cib_parent_name_for(section);
if (path == NULL) {
return -EINVAL;
}
tmp_section = create_xml_node(NULL, section);
cib_process_xpath(CIB_OP_CREATE, 0, path, NULL, tmp_section, NULL, result_cib, answer);
free_xml(tmp_section);
obj_root = get_object_root(section, *result_cib);
}
CRM_CHECK(obj_root != NULL, return -EINVAL);
if (update_xml_child(obj_root, input) == FALSE) {
if (options & cib_can_create) {
add_node_copy(obj_root, input);
} else {
return -ENXIO;
}
}
if(options & cib_mixed_update) {
int max = 0, lpc;
xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
if (xpathObj) {
max = numXpathResults(xpathObj);
crm_log_xml_trace(*result_cib, "Mixed result");
}
for (lpc = 0; lpc < max; lpc++) {
xmlNode *match = getXpathResult(xpathObj, lpc);
xmlChar *match_path = xmlGetNodePath(match);
crm_debug("Destroying %s", match_path);
free(match_path);
free_xml(match);
}
freeXpathObject(xpathObj);
}
return pcmk_ok;
}
static int
update_cib_object(xmlNode * parent, xmlNode * update)
{
int result = pcmk_ok;
xmlNode *target = NULL;
xmlNode *a_child = NULL;
const char *replace = NULL;
const char *object_id = NULL;
const char *object_name = NULL;
CRM_CHECK(update != NULL, return -EINVAL);
CRM_CHECK(parent != NULL, return -EINVAL);
object_name = crm_element_name(update);
CRM_CHECK(object_name != NULL, return -EINVAL);
object_id = ID(update);
crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
if (object_id == NULL) {
/* placeholder object */
target = find_xml_node(parent, object_name, FALSE);
} else {
target = pcmk__xe_match(parent, object_name, XML_ATTR_ID, object_id);
}
if (target == NULL) {
target = create_xml_node(parent, object_name);
}
crm_trace("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id));
replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
if (replace != NULL) {
xmlNode *remove = NULL;
int last = 0, lpc = 0, len = 0;
len = strlen(replace);
while (lpc <= len) {
if (replace[lpc] == ',' || replace[lpc] == 0) {
char *replace_item = NULL;
if (last == lpc) {
/* nothing to do */
last = lpc + 1;
goto incr;
}
replace_item = strndup(replace + last, lpc - last);
remove = find_xml_node(target, replace_item, FALSE);
if (remove != NULL) {
crm_trace("Replacing node <%s> in <%s>",
replace_item, crm_element_name(target));
free_xml(remove);
remove = NULL;
}
free(replace_item);
last = lpc + 1;
}
incr:
lpc++;
}
xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
}
copy_in_properties(target, update);
crm_trace("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id));
for (a_child = pcmk__xml_first_child(update); a_child != NULL;
a_child = pcmk__xml_next(a_child)) {
int tmp_result = 0;
crm_trace("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
tmp_result = update_cib_object(target, a_child);
/* only the first error is likely to be interesting */
if (tmp_result != pcmk_ok) {
crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
if (result == pcmk_ok) {
result = tmp_result;
}
}
}
crm_trace("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id));
return result;
}
static int
add_cib_object(xmlNode * parent, xmlNode * new_obj)
{
int result = pcmk_ok;
const char *object_name = NULL;
const char *object_id = NULL;
xmlNode *equiv_node = NULL;
if (new_obj != NULL) {
object_name = crm_element_name(new_obj);
}
object_id = crm_element_value(new_obj, XML_ATTR_ID);
crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
if (new_obj == NULL || object_name == NULL) {
result = -EINVAL;
} else if (parent == NULL) {
result = -EINVAL;
} else if (object_id == NULL) {
/* placeholder object */
equiv_node = find_xml_node(parent, object_name, FALSE);
} else {
equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
object_id);
}
if (result != pcmk_ok) {
; /* do nothing */
} else if (equiv_node != NULL) {
result = -EEXIST;
} else {
result = update_cib_object(parent, new_obj);
}
return result;
}
int
cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
xmlNode *failed = NULL;
int result = pcmk_ok;
xmlNode *update_section = NULL;
crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
section = NULL;
} else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
section = NULL;
} else if (pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
section = NULL;
}
CRM_CHECK(strcasecmp(CIB_OP_CREATE, op) == 0, return -EINVAL);
if (input == NULL) {
crm_err("Cannot perform modification with no data");
return -EINVAL;
}
if (section == NULL) {
return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
answer);
}
failed = create_xml_node(NULL, XML_TAG_FAILED);
update_section = get_object_root(section, *result_cib);
if (pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
xmlNode *a_child = NULL;
for (a_child = pcmk__xml_first_child(input); a_child != NULL;
a_child = pcmk__xml_next(a_child)) {
result = add_cib_object(update_section, a_child);
if (update_results(failed, a_child, op, result)) {
break;
}
}
} else {
result = add_cib_object(update_section, input);
update_results(failed, input, op, result);
}
if ((result == pcmk_ok) && xml_has_children(failed)) {
result = -EINVAL;
}
if (result != pcmk_ok) {
crm_log_xml_err(failed, "CIB Update failures");
*answer = failed;
} else {
free_xml(failed);
}
return result;
}
int
cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
const char *originator = NULL;
if (req != NULL) {
originator = crm_element_value(req, F_ORIG);
}
crm_trace("Processing \"%s\" event from %s%s",
op, originator,
(pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
free_xml(*result_cib);
*result_cib = copy_xml(existing_cib);
return xml_apply_patchset(*result_cib, input, TRUE);
}
gboolean
cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
{
int lpc = 0, max = 0;
gboolean config_changes = FALSE;
xmlXPathObject *xpathObj = NULL;
int format = 1;
CRM_ASSERT(diff != NULL);
if (*diff == NULL && last != NULL && next != NULL) {
*diff = diff_xml_object(last, next, FALSE);
}
if (*diff == NULL) {
goto done;
}
crm_element_value_int(*diff, "format", &format);
/* This function only applies to v1 diffs. */
CRM_LOG_ASSERT(format == 1);
xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
if (numXpathResults(xpathObj) > 0) {
config_changes = TRUE;
goto done;
}
freeXpathObject(xpathObj);
/*
* Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
* This always contains every field and would produce a false positive
* every time if the checked value existed
*/
xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
max = numXpathResults(xpathObj);
for (lpc = 0; lpc < max; lpc++) {
xmlNode *top = getXpathResult(xpathObj, lpc);
if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
config_changes = TRUE;
goto done;
}
if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
config_changes = TRUE;
goto done;
}
if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
config_changes = TRUE;
goto done;
}
if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
config_changes = TRUE;
goto done;
}
if (crm_element_value(top, "remote-clear-port") != NULL) {
config_changes = TRUE;
goto done;
}
if (crm_element_value(top, "remote-tls-port") != NULL) {
config_changes = TRUE;
goto done;
}
}
done:
freeXpathObject(xpathObj);
return config_changes;
}
int
cib_process_xpath(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
int lpc = 0;
int max = 0;
int rc = pcmk_ok;
gboolean is_query = pcmk__str_eq(op, CIB_OP_QUERY, pcmk__str_casei);
xmlXPathObjectPtr xpathObj = NULL;
crm_trace("Processing \"%s\" event", op);
if (is_query) {
xpathObj = xpath_search(existing_cib, section);
} else {
xpathObj = xpath_search(*result_cib, section);
}
max = numXpathResults(xpathObj);
if (max < 1 && pcmk__str_eq(op, CIB_OP_DELETE, pcmk__str_casei)) {
crm_debug("%s was already removed", section);
} else if (max < 1) {
crm_debug("%s: %s does not exist", op, section);
rc = -ENXIO;
} else if (is_query) {
if (max > 1) {
*answer = create_xml_node(NULL, "xpath-query");
}
}
if (pcmk__str_eq(op, CIB_OP_DELETE, pcmk__str_casei) && (options & cib_multiple)) {
dedupXpathResults(xpathObj);
}
for (lpc = 0; lpc < max; lpc++) {
xmlChar *path = NULL;
xmlNode *match = getXpathResult(xpathObj, lpc);
if (match == NULL) {
continue;
}
path = xmlGetNodePath(match);
crm_debug("Processing %s op for %s with %s", op, section, path);
free(path);
if (pcmk__str_eq(op, CIB_OP_DELETE, pcmk__str_casei)) {
if (match == *result_cib) {
/* Attempting to delete the whole "/cib" */
crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
rc = -EINVAL;
break;
}
free_xml(match);
if ((options & cib_multiple) == 0) {
break;
}
} else if (pcmk__str_eq(op, CIB_OP_MODIFY, pcmk__str_casei)) {
if (update_xml_child(match, input) == FALSE) {
rc = -ENXIO;
} else if ((options & cib_multiple) == 0) {
break;
}
} else if (pcmk__str_eq(op, CIB_OP_CREATE, pcmk__str_casei)) {
add_node_copy(match, input);
break;
} else if (pcmk__str_eq(op, CIB_OP_QUERY, pcmk__str_casei)) {
if (options & cib_no_children) {
const char *tag = TYPE(match);
xmlNode *shallow = create_xml_node(*answer, tag);
copy_in_properties(shallow, match);
if (*answer == NULL) {
*answer = shallow;
}
} else if (options & cib_xpath_address) {
char *path = NULL;
xmlNode *parent = match;
while (parent && parent->type == XML_ELEMENT_NODE) {
const char *id = crm_element_value(parent, XML_ATTR_ID);
char *new_path = NULL;
if (id) {
new_path = crm_strdup_printf("/%s[@id='%s']%s",
parent->name, id,
(path? path : ""));
} else {
new_path = crm_strdup_printf("/%s%s", parent->name,
(path? path : ""));
}
free(path);
path = new_path;
parent = parent->parent;
}
crm_trace("Got: %s", path);
if (*answer == NULL) {
*answer = create_xml_node(NULL, "xpath-query");
}
parent = create_xml_node(*answer, "xpath-query-path");
crm_xml_add(parent, XML_ATTR_ID, path);
free(path);
} else if (*answer) {
add_node_copy(*answer, match);
} else {
*answer = match;
}
} else if (pcmk__str_eq(op, CIB_OP_REPLACE, pcmk__str_casei)) {
xmlNode *parent = match->parent;
free_xml(match);
if (input != NULL) {
add_node_copy(parent, input);
}
if ((options & cib_multiple) == 0) {
break;
}
}
}
freeXpathObject(xpathObj);
return rc;
}
/* remove this function */
gboolean
update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
{
xmlNode *xml_node = NULL;
gboolean was_error = FALSE;
const char *error_msg = NULL;
if (return_code != pcmk_ok) {
error_msg = pcmk_strerror(return_code);
was_error = TRUE;
xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
add_node_copy(xml_node, target);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
}
return was_error;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:48 PM (17 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018965
Default Alt Text
(25 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment