Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639716
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
38 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/cib/messages.c b/cib/messages.c
index 203c580731..9c998768d9 100644
--- a/cib/messages.c
+++ b/cib/messages.c
@@ -1,462 +1,462 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <crm/common/cluster.h>
#include <cibio.h>
#include <cibmessages.h>
#include <callbacks.h>
#define MAX_DIFF_RETRY 5
#ifdef CIBPIPE
gboolean cib_is_master = TRUE;
#else
gboolean cib_is_master = FALSE;
#endif
xmlNode *the_cib = NULL;
gboolean syncd_once = FALSE;
extern const char *cib_our_uname;
enum cib_errors revision_check(xmlNode *cib_update, xmlNode *cib_copy, int flags);
int get_revision(xmlNode *xml_obj, int cur_revision);
enum cib_errors updateList(
xmlNode *local_cib, xmlNode *update_command, xmlNode *failed,
int operation, const char *section);
gboolean check_generation(xmlNode *newCib, xmlNode *oldCib);
gboolean update_results(
xmlNode *failed, xmlNode *target, const char *operation, int return_code);
enum cib_errors cib_update_counter(
xmlNode *xml_obj, const char *field, gboolean reset);
enum cib_errors sync_our_cib(xmlNode *request, gboolean all);
extern xmlNode *cib_msg_copy(const xmlNode *msg, gboolean with_data);
extern gboolean cib_shutdown_flag;
extern void terminate_cib(const char *caller);
enum cib_errors
cib_process_shutdown_req(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
#ifdef CIBPIPE
return cib_invalid_argument;
#else
enum cib_errors result = cib_ok;
const char *host = crm_element_value(req, F_ORIG);
*answer = NULL;
if(crm_element_value(req, F_CIB_ISREPLY) == NULL) {
crm_info("Shutdown REQ from %s", host);
return cib_ok;
} else if(cib_shutdown_flag) {
crm_info("Shutdown ACK from %s", host);
terminate_cib(__FUNCTION__);
return cib_ok;
} else {
crm_err("Shutdown ACK from %s - not shutting down",host);
result = cib_unknown;
}
return result;
#endif
}
enum cib_errors
cib_process_default(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = NULL;
if(op == NULL) {
result = cib_operation;
crm_err("No operation specified");
} else if(strcasecmp(CRM_OP_NOOP, op) == 0) {
;
} else {
result = cib_NOTSUPPORTED;
crm_err("Action [%s] is not supported by the CIB", op);
}
return result;
}
enum cib_errors
cib_process_quit(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
crm_warn("The CRMd has asked us to exit... complying");
exit(0);
return result;
}
enum cib_errors
cib_process_readwrite(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
#ifdef CIBPIPE
return cib_invalid_argument;
#else
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(safe_str_eq(op, CIB_OP_ISMASTER)) {
if(cib_is_master == TRUE) {
result = cib_ok;
} else {
result = cib_not_master;
}
return result;
}
if(safe_str_eq(op, CIB_OP_MASTER)) {
if(cib_is_master == FALSE) {
crm_info("We are now in R/W mode");
cib_is_master = TRUE;
syncd_once = TRUE;
} else {
crm_debug("We are still in R/W mode");
}
} else if(cib_is_master) {
crm_info("We are now in R/O mode");
cib_is_master = FALSE;
}
return result;
#endif
}
enum cib_errors
cib_process_ping(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
#ifdef CIBPIPE
return cib_invalid_argument;
#else
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok");
return result;
#endif
}
enum cib_errors
cib_process_sync(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
#ifdef CIBPIPE
return cib_invalid_argument;
#else
return sync_our_cib(req, TRUE);
#endif
}
enum cib_errors
cib_process_sync_one(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
#ifdef CIBPIPE
return cib_invalid_argument;
#else
return sync_our_cib(req, FALSE);
#endif
}
int sync_in_progress = 0;
enum cib_errors
cib_server_process_diff(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
int rc = cib_ok;
if(cib_is_master) {
/* the master is never waiting for a resync */
sync_in_progress = 0;
}
if(sync_in_progress > MAX_DIFF_RETRY) {
/* request another full-sync,
* the last request may have been lost
*/
sync_in_progress = 0;
}
if(sync_in_progress) {
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
cib_diff_version_details(
input,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
sync_in_progress++;
crm_warn("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
return cib_diff_resync;
}
rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
if(rc == cib_diff_resync && cib_is_master == FALSE) {
xmlNode *sync_me = create_xml_node(NULL, "sync-me");
free_xml(*result_cib);
*result_cib = NULL;
crm_info("Requesting re-sync from peer");
sync_in_progress++;
crm_xml_add(sync_me, F_TYPE, "cib");
crm_xml_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
crm_xml_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
if(send_cluster_message(NULL, crm_msg_cib, sync_me, FALSE) == FALSE) {
rc = cib_not_connected;
}
free_xml(sync_me);
} else if(rc == cib_diff_resync) {
rc = cib_diff_failed;
if(options & cib_force_diff) {
crm_warn("Not requesting full refresh in slave mode.");
}
}
return rc;
}
enum cib_errors
cib_process_replace_svr(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
const char *tag = crm_element_name(input);
enum cib_errors rc = cib_process_replace(
op, options, section, req, input, existing_cib, result_cib, answer);
if(rc == cib_ok && safe_str_eq(tag, XML_TAG_CIB)) {
sync_in_progress = 0;
}
return rc;
}
static int
delete_cib_object(xmlNode *parent, xmlNode *delete_spec)
{
const char *object_name = NULL;
const char *object_id = NULL;
xmlNode *equiv_node = NULL;
int result = cib_ok;
if(delete_spec != NULL) {
object_name = crm_element_name(delete_spec);
}
object_id = crm_element_value(delete_spec, XML_ATTR_ID);
crm_debug_3("Processing: <%s id=%s>",
crm_str(object_name), crm_str(object_id));
if(delete_spec == NULL) {
result = cib_NOOBJECT;
} else if(parent == NULL) {
result = cib_NOPARENT;
} else if(object_id == NULL) {
/* placeholder object */
equiv_node = find_xml_node(parent, object_name, FALSE);
} else {
equiv_node = find_entity(parent, object_name, object_id);
}
if(result != cib_ok) {
; /* nothing */
} else if(equiv_node == NULL) {
result = cib_ok;
} else if(xml_has_children(delete_spec) == FALSE) {
/* only leaves are deleted */
crm_debug("Removing leaf: <%s id=%s>",
crm_str(object_name), crm_str(object_id));
zap_xml_from_parent(parent, equiv_node);
} else {
xml_child_iter(
delete_spec, child,
int tmp_result = delete_cib_object(equiv_node, child);
/* only the first error is likely to be interesting */
if(tmp_result != cib_ok && result == cib_ok) {
result = tmp_result;
}
);
}
return result;
}
enum cib_errors
cib_process_delete_absolute(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
xmlNode *failed = NULL;
enum cib_errors result = cib_ok;
xmlNode *update_section = NULL;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
} else if(safe_str_eq(XML_TAG_CIB, section)) {
section = NULL;
} else if(safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
section = NULL;
}
CRM_CHECK(strcasecmp(CIB_OP_DELETE, op) == 0, return cib_operation);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
failed = create_xml_node(NULL, XML_TAG_FAILED);
update_section = get_object_root(section, *result_cib);
result = delete_cib_object(update_section, input);
update_results(failed, input, op, result);
if(xml_has_children(failed)) {
CRM_CHECK(result != cib_ok, result = cib_unknown);
}
if (result != cib_ok) {
crm_log_xml_err(failed, "CIB Update failures");
*answer = failed;
} else {
free_xml(failed);
}
return result;
}
gboolean
check_generation(xmlNode *newCib, xmlNode *oldCib)
{
if(cib_compare_generation(newCib, oldCib) >= 0) {
return TRUE;
}
crm_warn("Generation from update is older than the existing one");
return FALSE;
}
#ifndef CIBPIPE
enum cib_errors
sync_our_cib(xmlNode *request, gboolean all)
{
enum cib_errors result = cib_ok;
const char *host = crm_element_value(request, F_ORIG);
const char *op = crm_element_value(request, F_CIB_OPERATION);
xmlNode *replace_request = cib_msg_copy(request, FALSE);
CRM_CHECK(the_cib != NULL, ;);
CRM_CHECK(replace_request != NULL, ;);
- crm_info("Syncing CIB to %s", all?"all peers":host);
+ crm_debug("Syncing CIB to %s", all?"all peers":host);
if(all == FALSE && host == NULL) {
crm_log_xml(LOG_ERR, "bad sync", request);
}
/* remove the "all == FALSE" condition
*
* sync_from was failing, the local client wasnt being notified
* because it didnt know it was a reply
* setting this does not prevent the other nodes from applying it
* if all == TRUE
*/
if(host != NULL) {
crm_xml_add(replace_request, F_CIB_ISREPLY, host);
}
crm_xml_add(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
crm_xml_add(replace_request, "original_"F_CIB_OPERATION, op);
crm_xml_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
if(send_cluster_message(all?NULL:host, crm_msg_cib, replace_request, FALSE) == FALSE) {
result = cib_not_connected;
}
free_xml(replace_request);
return result;
}
#endif
diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c
index a8e12e89a4..1eb744f0e3 100644
--- a/lib/cib/cib_ops.c
+++ b/lib/cib/cib_ops.c
@@ -1,996 +1,994 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
enum cib_errors
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;
enum cib_errors result = cib_ok;
crm_debug_2("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 (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
obj_root = get_object_root(section, existing_cib);
if(obj_root == NULL) {
result = cib_NOTEXISTS;
} else {
*answer = obj_root;
}
if(result == cib_ok && *answer == NULL) {
crm_err("Error creating query response");
result = cib_output_data;
}
return result;
}
enum cib_errors
cib_process_erase(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = NULL;
free_xml(*result_cib);
*result_cib = createEmptyCib();
copy_in_properties(*result_cib, existing_cib);
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
return result;
}
enum cib_errors
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;
const char *value = NULL;
*answer = NULL;
crm_debug_2("Processing \"%s\" event", op);
value = crm_element_value_copy(existing_cib, XML_ATTR_VALIDATION);
if(value != NULL) {
current_version = get_schema_version(value);
}
rc = update_validation(result_cib, &new_version, TRUE, TRUE);
if(new_version > current_version) {
return cib_ok;
}
return rc;
}
enum cib_errors
cib_process_bump(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("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;
}
enum cib_errors
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) {
crm_malloc0(new_value, 128);
int_value = atoi(old_value);
sprintf(new_value, "%d", ++int_value);
} else {
new_value = crm_strdup("1");
}
crm_debug_4("%s %d(%s)->%s",
field, int_value, crm_str(old_value), crm_str(new_value));
crm_xml_add(xml_obj, field, new_value);
crm_free(new_value);
crm_free(old_value);
return cib_ok;
}
enum cib_errors
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;
gboolean verbose = FALSE;
enum cib_errors result = cib_ok;
crm_debug_2("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 cib_NOOBJECT;
}
tag = crm_element_name(input);
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
} else if(safe_str_eq(tag, section)) {
section = NULL;
}
if(safe_str_eq(tag, XML_TAG_CIB)) {
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;
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_warn("Replacement %d.%d.%d not applied to %d.%d.%d:"
" current %s is greater than the replacement",
replace_admin_epoch, replace_epoch,
replace_updates, admin_epoch, epoch, updates,
reason);
result = cib_old_data;
}
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_debug_2("No matching object to replace");
result = cib_NOTEXISTS;
}
}
return result;
}
enum cib_errors
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_debug_2("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 cib_NOOBJECT;
}
obj_root = get_object_root(section, *result_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
crm_debug_2("No matching object to delete");
}
return cib_ok;
}
enum cib_errors
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_debug_2("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 cib_NOOBJECT;
}
obj_root = get_object_root(section, *result_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(obj_root == NULL) {
xmlNode *tmp_section = NULL;
const char *path = get_object_parent(section);
if(path == NULL) {
return cib_bad_section;
}
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 cib_unknown);
if(update_xml_child(obj_root, input) == FALSE) {
if(options & cib_can_create) {
add_node_copy(obj_root, input);
} else {
return cib_NOTEXISTS;
}
}
return cib_ok;
}
static int
update_cib_object(xmlNode *parent, xmlNode *update)
{
const char *replace = NULL;
const char *object_name = NULL;
const char *object_id = NULL;
xmlNode *target = NULL;
int result = cib_ok;
CRM_CHECK(update != NULL, return cib_NOOBJECT);
CRM_CHECK(parent != NULL, return cib_NOPARENT);
object_name = crm_element_name(update);
CRM_CHECK(object_name != NULL, return cib_NOOBJECT);
object_id = ID(update);
crm_debug_3("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 = find_entity(parent, object_name, object_id);
}
if(target == NULL) {
target = create_xml_node(parent, object_name);
}
crm_debug_2("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;
}
crm_malloc0(replace_item, lpc - last + 1);
strncpy(replace_item, replace+last, lpc-last);
remove = find_xml_node(target, replace_item, FALSE);
if(remove != NULL) {
crm_debug_3("Replacing node <%s> in <%s>",
replace_item, crm_element_name(target));
zap_xml_from_parent(target, remove);
}
crm_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_debug_3("Processing children of <%s id=%s>",
crm_str(object_name), crm_str(object_id));
xml_child_iter(
update, a_child,
int tmp_result = 0;
crm_debug_3("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 != cib_ok) {
crm_err("Error updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
if(result == cib_ok) {
result = tmp_result;
}
}
);
crm_debug_3("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)
{
enum cib_errors result = cib_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_debug_3("Processing: <%s id=%s>",
crm_str(object_name), crm_str(object_id));
if(new_obj == NULL || object_name == NULL) {
result = cib_NOOBJECT;
} else if(parent == NULL) {
result = cib_NOPARENT;
} else if(object_id == NULL) {
/* placeholder object */
equiv_node = find_xml_node(parent, object_name, FALSE);
} else {
equiv_node = find_entity(parent, object_name, object_id);
}
if(result != cib_ok) {
; /* do nothing */
} else if(equiv_node != NULL) {
result = cib_EXISTS;
} else {
result = update_cib_object(parent, new_obj);
}
return result;
}
enum cib_errors
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;
enum cib_errors result = cib_ok;
xmlNode *update_section = NULL;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
} else if(safe_str_eq(XML_TAG_CIB, section)) {
section = NULL;
} else if(safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
section = NULL;
}
CRM_CHECK(strcasecmp(CIB_OP_CREATE, op) == 0, return cib_operation);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
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(safe_str_eq(crm_element_name(input), section)) {
xml_child_iter(input, 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(xml_has_children(failed)) {
CRM_CHECK(result != cib_ok, result = cib_unknown);
}
if (result != cib_ok) {
crm_log_xml_err(failed, "CIB Update failures");
*answer = failed;
} else {
free_xml(failed);
}
return result;
}
enum cib_errors
cib_process_diff(
const char *op, int options, const char *section, xmlNode *req, xmlNode *input,
xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
{
unsigned int log_level = LOG_DEBUG;
const char *reason = NULL;
gboolean apply_diff = TRUE;
enum cib_errors result = cib_ok;
int this_updates = 0;
int this_epoch = 0;
int this_admin_epoch = 0;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
crm_debug_2("Processing \"%s\" event", op);
cib_diff_version_details(
input,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
crm_element_value_int(existing_cib, XML_ATTR_GENERATION, &this_epoch);
crm_element_value_int(existing_cib, XML_ATTR_NUMUPDATES, &this_updates);
crm_element_value_int(existing_cib, XML_ATTR_GENERATION_ADMIN, &this_admin_epoch);
if(this_epoch < 0) { this_epoch = 0; }
if(this_updates < 0) { this_updates = 0; }
if(this_admin_epoch < 0) { this_admin_epoch = 0; }
if(diff_del_admin_epoch == diff_add_admin_epoch
&& diff_del_epoch == diff_add_epoch
&& diff_del_updates == diff_add_updates) {
if(options & cib_force_diff) {
apply_diff = FALSE;
log_level = LOG_ERR;
reason = "+ and - versions in the diff did not change in global update";
crm_log_xml_warn(input, "Bad global update");
} else if(diff_add_admin_epoch == -1 && diff_add_epoch == -1 && diff_add_updates == -1) {
crm_err("Massaging diff versions");
diff_add_epoch = this_epoch;
diff_add_updates = this_updates + 1;
diff_add_admin_epoch = this_admin_epoch;
diff_del_epoch = this_epoch;
diff_del_updates = this_updates;
diff_del_admin_epoch = this_admin_epoch;
crm_log_xml_err(input, __FUNCTION__);
} else {
apply_diff = FALSE;
log_level = LOG_ERR;
reason = "+ and - versions in the diff did not change";
log_cib_diff(LOG_ERR, input, __FUNCTION__);
}
}
if(apply_diff && diff_del_admin_epoch > this_admin_epoch) {
result = cib_diff_resync;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
} else if(apply_diff && diff_del_admin_epoch < this_admin_epoch) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
} else if(apply_diff && diff_del_epoch > this_epoch) {
result = cib_diff_resync;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION"\" is less than required";
} else if(apply_diff && diff_del_epoch < this_epoch) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
} else if(apply_diff && diff_del_updates > this_updates) {
result = cib_diff_resync;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
} else if(apply_diff && diff_del_updates < this_updates) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
}
if(apply_diff) {
free_xml(*result_cib);
*result_cib = NULL;
if(apply_xml_diff(existing_cib, input, result_cib) == FALSE) {
log_level = LOG_NOTICE;
reason = "Failed application of an update diff";
if(options & cib_force_diff) {
result = cib_diff_resync;
}
}
}
if(reason != NULL) {
do_crm_log(
log_level,
"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
this_admin_epoch,this_epoch,this_updates, reason);
if(result == cib_ok) {
result = cib_diff_failed;
}
} else if(apply_diff) {
crm_debug_2("Diff %d.%d.%d -> %d.%d.%d was applied to %d.%d.%d",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
this_admin_epoch,this_epoch,this_updates);
}
return result;
}
gboolean
apply_cib_diff(xmlNode *old, xmlNode *diff, xmlNode **new)
{
gboolean result = TRUE;
const char *value = NULL;
int this_updates = 0;
int this_epoch = 0;
int this_admin_epoch = 0;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
CRM_CHECK(diff != NULL, return FALSE);
CRM_CHECK(old != NULL, return FALSE);
value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN);
this_admin_epoch = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN,
this_admin_epoch, value);
value = crm_element_value(old, XML_ATTR_GENERATION);
this_epoch = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoch, value);
value = crm_element_value(old, XML_ATTR_NUMUPDATES);
this_updates = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_NUMUPDATES, this_updates, value);
cib_diff_version_details(
diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
value = NULL;
if(result && diff_del_admin_epoch != this_admin_epoch) {
value = XML_ATTR_GENERATION_ADMIN;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_admin_epoch);
} else if(result && diff_del_epoch != this_epoch) {
value = XML_ATTR_GENERATION;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_epoch);
} else if(result && diff_del_updates != this_updates) {
value = XML_ATTR_NUMUPDATES;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_updates);
}
if(result) {
xmlNode *tmp = NULL;
xmlNode *diff_copy = copy_xml(diff);
tmp = find_xml_node(diff_copy, "diff-removed", TRUE);
if(tmp != NULL) {
xml_remove_prop(tmp, XML_ATTR_GENERATION_ADMIN);
xml_remove_prop(tmp, XML_ATTR_GENERATION);
xml_remove_prop(tmp, XML_ATTR_NUMUPDATES);
}
tmp = find_xml_node(diff_copy, "diff-added", TRUE);
if(tmp != NULL) {
xml_remove_prop(tmp, XML_ATTR_GENERATION_ADMIN);
xml_remove_prop(tmp, XML_ATTR_GENERATION);
xml_remove_prop(tmp, XML_ATTR_NUMUPDATES);
}
result = apply_xml_diff(old, diff_copy, new);
free_xml(diff_copy);
} else {
crm_err("target and diff %s values didnt match", value);
}
return result;
}
gboolean
cib_config_changed(xmlNode *diff)
{
gboolean config_changes = FALSE;
xmlXPathObject *xpathObj = NULL;
if(diff == NULL) {
goto done;
}
xpathObj = xpath_search(diff, "//"XML_CIB_TAG_CONFIGURATION);
if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
config_changes = TRUE;
goto done;
} else if(xpathObj) {
xmlXPathFreeObject(xpathObj);
}
xpathObj = xpath_search(diff, "//"XML_TAG_CIB);
if(xpathObj) {
int lpc = 0, max = xpathObj->nodesetval->nodeNr;
for(lpc = 0; lpc < max; lpc++) {
xmlNode *top = getXpathResult(xpathObj, lpc);
xml_prop_iter(top, name, value,
if(crm_str_eq(XML_ATTR_NUMUPDATES, name, TRUE) == FALSE) {
config_changes = TRUE;
goto done;
}
);
}
}
done:
if(xpathObj) {
xmlXPathFreeObject(xpathObj);
}
return config_changes;
}
xmlNode *
diff_cib_object(xmlNode *old_cib, xmlNode *new_cib, gboolean suppress)
{
xmlNode *dest = NULL;
xmlNode *src = NULL;
const char *name = NULL;
const char *value = NULL;
xmlNode *diff = diff_xml_object(old_cib, new_cib, suppress);
/* add complete version information */
src = old_cib;
dest = find_xml_node(diff, "diff-removed", FALSE);
if(src != NULL && dest != NULL) {
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_GENERATION;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
}
src = new_cib;
dest = find_xml_node(diff, "diff-added", FALSE);
if(src != NULL && dest != NULL) {
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_GENERATION;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
}
return diff;
}
enum cib_errors
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 = cib_ok;
gboolean is_query = safe_str_eq(op, CIB_OP_QUERY);
xmlXPathObjectPtr xpathObj = NULL;
crm_debug_2("Processing \"%s\" event", op);
if(is_query) {
xpathObj = xpath_search(existing_cib, section);
} else {
xpathObj = xpath_search(*result_cib, section);
}
if(xpathObj != NULL && xpathObj->nodesetval != NULL) {
max = xpathObj->nodesetval->nodeNr;
}
if(max < 1 && safe_str_eq(op, CIB_OP_DELETE)) {
crm_debug("%s was already removed", section);
} else if(max < 1) {
crm_debug("%s: %s does not exist", op, section);
rc = cib_NOTEXISTS;
} else if(is_query) {
if(max > 1) {
*answer = create_xml_node(NULL, "xpath-query");
}
}
for(lpc = 0; lpc < max; lpc++) {
xmlChar *path = NULL;
xmlNode *match = getXpathResult(xpathObj, lpc);
CRM_CHECK(match != NULL, goto out);
path = xmlGetNodePath(match);
- if(is_query == FALSE) {
- crm_info("Processing %s op for %s (%s)", op, section, path);
- }
+ crm_debug("Processing %s op for %s (%s)", op, section, path);
free(path);
if(safe_str_eq(op, CIB_OP_DELETE)) {
free_xml_from_parent(NULL, match);
break;
} else if(safe_str_eq(op, CIB_OP_MODIFY)) {
if(update_xml_child(match, input) == FALSE) {
rc = cib_NOTEXISTS;
} else {
rc = cib_ok;
if((options & cib_multiple) == 0) {
break;
}
}
} else if(safe_str_eq(op, CIB_OP_CREATE)) {
add_node_copy(match, input);
break;
} else if(safe_str_eq(op, CIB_OP_QUERY)) {
if(options & cib_no_children) {
const char *tag = TYPE(match);
*answer = create_xml_node(NULL, tag);
copy_in_properties(*answer, match);
break;
} else if(*answer) {
add_node_copy(*answer, match);
} else {
*answer = match;
}
} else if(safe_str_eq(op, CIB_OP_REPLACE)) {
xmlNode *parent = match->parent;
free_xml_from_parent(NULL, match);
if(input != NULL) {
add_node_copy(parent, input);
}
if((options & cib_multiple) == 0) {
break;
}
}
}
out:
if(xpathObj) {
xmlXPathFreeObject(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 != cib_ok) {
error_msg = cib_error2string(return_code);
xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
was_error = TRUE;
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
Thu, Jul 10, 3:21 AM (17 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009906
Default Alt Text
(38 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment