Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1841544
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
41 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c
index 549507ee79..792dbf03ca 100644
--- a/lib/crm/cib/cib_client.c
+++ b/lib/crm/cib/cib_client.c
@@ -1,1602 +1,1607 @@
/*
* Copyright (c) 2004 International Business Machines
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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 library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <glib.h>
#include <heartbeat.h>
#include <clplumbing/ipc.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <cib_private.h>
/* short term hack to reduce callback messages */
typedef struct cib_native_opaque_s
{
IPC_Channel *command_channel;
IPC_Channel *callback_channel;
GCHSource *callback_source;
} cib_native_opaque_t;
GHashTable *cib_op_callback_table = NULL;
gboolean verify_cib_cmds(cib_t *cib);
int cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, crm_data_t *output));
int cib_client_noop(cib_t *cib, int call_options);
int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options);
int cib_client_query(cib_t *cib, const char *section,
crm_data_t **output_data, int call_options);
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
crm_data_t **output_data, int call_options);
int cib_client_sync(cib_t *cib, const char *section, int call_options);
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options);
int cib_client_is_master(cib_t *cib);
int cib_client_set_slave(cib_t *cib, int call_options);
int cib_client_set_slave_all(cib_t *cib, int call_options);
int cib_client_set_master(cib_t *cib, int call_options);
int cib_client_bump_epoch(cib_t *cib, int call_options);
int cib_client_create(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_update(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_delete_absolute(
cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_erase(
cib_t *cib, crm_data_t **output_data, int call_options);
int cib_client_quit(cib_t *cib, int call_options);
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b);
extern cib_t *cib_native_new(cib_t *cib);
extern void cib_native_delete(cib_t *cib);
static enum cib_variant configured_variant = cib_native;
/* define of the api functions*/
cib_t*
cib_new(void)
{
cib_t* new_cib = NULL;
if(configured_variant != cib_native) {
crm_err("Only the native CIB type is currently implemented");
return NULL;
}
if(cib_op_callback_table != NULL) {
g_hash_table_destroy(cib_op_callback_table);
cib_op_callback_table = NULL;
}
if(cib_op_callback_table == NULL) {
cib_op_callback_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal,
NULL, g_hash_destroy_str);
}
crm_malloc0(new_cib, sizeof(cib_t));
new_cib->call_id = 1;
new_cib->type = cib_none;
new_cib->state = cib_disconnected;
new_cib->op_callback = NULL;
new_cib->variant_opaque = NULL;
new_cib->notify_list = NULL;
/* the rest will get filled in by the variant constructor */
crm_malloc0(new_cib->cmds, sizeof(cib_api_operations_t));
new_cib->cmds->set_op_callback = cib_client_set_op_callback;
new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
new_cib->cmds->noop = cib_client_noop;
new_cib->cmds->ping = cib_client_ping;
new_cib->cmds->query = cib_client_query;
new_cib->cmds->sync = cib_client_sync;
new_cib->cmds->query_from = cib_client_query_from;
new_cib->cmds->sync_from = cib_client_sync_from;
new_cib->cmds->is_master = cib_client_is_master;
new_cib->cmds->set_master = cib_client_set_master;
new_cib->cmds->set_slave = cib_client_set_slave;
new_cib->cmds->set_slave_all = cib_client_set_slave_all;
new_cib->cmds->bump_epoch = cib_client_bump_epoch;
new_cib->cmds->create = cib_client_create;
new_cib->cmds->modify = cib_client_modify;
new_cib->cmds->update = cib_client_update;
new_cib->cmds->replace = cib_client_replace;
new_cib->cmds->delete = cib_client_delete;
new_cib->cmds->erase = cib_client_erase;
new_cib->cmds->quit = cib_client_quit;
new_cib->cmds->delete_absolute = cib_client_delete_absolute;
cib_native_new(new_cib);
if(verify_cib_cmds(new_cib) == FALSE) {
cib_delete(new_cib);
return NULL;
}
return new_cib;
}
void
cib_delete(cib_t *cib)
{
GList *list = cib->notify_list;
while(list != NULL) {
cib_notify_client_t *client = g_list_nth_data(list, 0);
list = g_list_remove(list, client);
crm_free(client);
}
cib_native_delete(cib);
g_hash_table_destroy(cib_op_callback_table);
crm_free(cib->cmds);
crm_free(cib);
}
int
cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, crm_data_t *output))
{
if(callback == NULL) {
crm_info("Un-Setting operation callback");
} else {
crm_debug_3("Setting operation callback");
}
cib->op_callback = callback;
return cib_ok;
}
int cib_client_noop(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options);
}
int cib_client_query(cib_t *cib, const char *section,
crm_data_t **output_data, int call_options)
{
return cib->cmds->query_from(
cib, NULL, section, output_data, call_options);
}
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_QUERY, host, section,
NULL, output_data, call_options);
}
int cib_client_is_master(cib_t *cib)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_ISMASTER, NULL, NULL,NULL,NULL,
cib_scope_local|cib_sync_call);
}
int cib_client_set_slave(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SLAVE, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_slave_all(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SLAVEALL, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_master(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
crm_debug_3("Adding cib_scope_local to options");
return cib->cmds->variant_op(
cib, CIB_OP_MASTER, NULL,NULL,NULL,NULL,
call_options|cib_scope_local);
}
int cib_client_bump_epoch(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_BUMP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_sync(cib_t *cib, const char *section, int call_options)
{
return cib->cmds->sync_from(cib, NULL, section, call_options);
}
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SYNC, host, section, NULL, NULL, call_options);
}
int cib_client_create(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_CREATE, NULL, section,
data, output_data, call_options);
}
int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_MODIFY, NULL, section,
data, output_data, call_options);
}
int cib_client_update(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_UPDATE, NULL, section,
data, output_data, call_options);
}
int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
} else if(data == NULL) {
return cib_missing_data;
}
return cib->cmds->variant_op(cib, CIB_OP_REPLACE, NULL, section,
data, output_data, call_options);
}
int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_DELETE, NULL, section,
data, output_data, call_options);
}
int cib_client_delete_absolute(
cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_DELETE_ALT, NULL, section,
data, output_data, call_options);
}
int cib_client_erase(
cib_t *cib, crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_ERASE, NULL, NULL, NULL,
output_data, call_options);
}
int cib_client_quit(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug_2("Adding callback for %s events (%d)",
event, g_list_length(cib->notify_list));
crm_malloc0(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
cib->notify_list, new_client, ciblib_GCompareFunc);
if(list_item != NULL) {
crm_warn("Callback already present");
crm_free(new_client);
} else {
cib->notify_list = g_list_append(
cib->notify_list, new_client);
cib->cmds->register_callback(cib, event, 1);
crm_debug_3("Callback added (%d)", g_list_length(cib->notify_list));
}
return cib_ok;
}
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug("Removing callback for %s events", event);
crm_malloc0(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
cib->notify_list, new_client, ciblib_GCompareFunc);
cib->cmds->register_callback(cib, event, 0);
if(list_item != NULL) {
cib_notify_client_t *list_client = list_item->data;
cib->notify_list =
g_list_remove(cib->notify_list, list_client);
crm_free(list_client);
crm_debug_3("Removed callback");
} else {
crm_debug_3("Callback not present");
}
crm_free(new_client);
return cib_ok;
}
gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const cib_notify_client_t *a_client = a;
const cib_notify_client_t *b_client = b;
if(a_client->callback == b_client->callback
&& safe_str_neq(a_client->event, b_client->event)) {
return 0;
} else if(((long)a_client->callback) < ((long)b_client->callback)) {
return -1;
}
return 1;
}
gboolean
add_cib_op_callback(
int call_id, gboolean only_success, void *user_data,
void (*callback)(const HA_Message*, int, int, crm_data_t*,void*))
{
cib_callback_client_t *blob = NULL;
if(call_id < 0) {
crm_warn("CIB call failed: %s", cib_error2string(call_id));
if(only_success == FALSE) {
callback(NULL, call_id, call_id, NULL, user_data);
}
return FALSE;
}
crm_malloc0(blob, sizeof(cib_callback_client_t));
blob->only_success = only_success;
blob->user_data = user_data;
blob->callback = callback;
g_hash_table_insert(
cib_op_callback_table, GINT_TO_POINTER(call_id), blob);
return TRUE;
}
void
remove_cib_op_callback(int call_id, gboolean all_callbacks)
{
if(all_callbacks) {
if(cib_op_callback_table != NULL) {
g_hash_table_destroy(cib_op_callback_table);
}
cib_op_callback_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal,
NULL, g_hash_destroy_str);
} else {
g_hash_table_remove(
cib_op_callback_table,
GINT_TO_POINTER(call_id));
}
}
int
num_cib_op_callbacks(void)
{
if(cib_op_callback_table == NULL) {
return 0;
}
return g_hash_table_size(cib_op_callback_table);
}
char *
cib_pluralSection(const char *a_section)
{
char *a_section_parent = NULL;
if (a_section == NULL) {
a_section_parent = crm_strdup("all");
} else if(strcasecmp(a_section, XML_TAG_CIB) == 0) {
a_section_parent = crm_strdup("all");
} else if(strcasecmp(a_section, XML_CIB_TAG_NODE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_NODES);
} else if(strcasecmp(a_section, XML_CIB_TAG_STATE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_STATUS);
} else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_LOCATION) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_DEPEND) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_ORDER) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, "resource") == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_GROUP) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_INCARNATION) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_NVPAIR) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG);
} else if(strcasecmp(a_section, XML_TAG_ATTR_SETS) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG);
} else {
crm_err("Unknown section %s", a_section);
a_section_parent = crm_strdup("all");
}
crm_debug_2("Plural of %s is %s", crm_str(a_section), a_section_parent);
return a_section_parent;
}
const char *
cib_error2string(enum cib_errors return_code)
{
const char *error_msg = NULL;
switch(return_code) {
case cib_bad_permissions:
error_msg = "bad permissions for the on-disk configuration. shutdown heartbeat and repair.";
break;
case cib_bad_digest:
error_msg = "the on-disk configuration was manually altered. shutdown heartbeat and repair.";
break;
case cib_bad_config:
error_msg = "the on-disk configuration is not valid";
break;
case cib_msg_field_add:
error_msg = "failed adding field to cib message";
break;
case cib_id_check:
error_msg = "missing id or id-collision detected";
break;
case cib_operation:
error_msg = "invalid operation";
break;
case cib_create_msg:
error_msg = "couldnt create cib message";
break;
case cib_client_gone:
error_msg = "client left before we could send reply";
break;
case cib_not_connected:
error_msg = "not connected";
break;
case cib_not_authorized:
error_msg = "not authorized";
break;
case cib_send_failed:
error_msg = "send failed";
break;
case cib_reply_failed:
error_msg = "reply failed";
break;
case cib_return_code:
error_msg = "no return code";
break;
case cib_output_ptr:
error_msg = "nowhere to store output";
break;
case cib_output_data:
error_msg = "corrupt output data";
break;
case cib_connection:
error_msg = "connection failed";
break;
case cib_callback_register:
error_msg = "couldnt register callback channel";
break;
case cib_authentication:
error_msg = "";
break;
case cib_registration_msg:
error_msg = "invalid registration msg";
break;
case cib_callback_token:
error_msg = "callback token not found";
break;
case cib_missing:
error_msg = "cib object missing";
break;
case cib_variant:
error_msg = "unknown/corrupt cib variant";
break;
case CIBRES_MISSING_ID:
error_msg = "The id field is missing";
break;
case CIBRES_MISSING_TYPE:
error_msg = "The type field is missing";
break;
case CIBRES_MISSING_FIELD:
error_msg = "A required field is missing";
break;
case CIBRES_OBJTYPE_MISMATCH:
error_msg = "CIBRES_OBJTYPE_MISMATCH";
break;
case cib_EXISTS:
error_msg = "The object already exists";
break;
case cib_NOTEXISTS:
error_msg = "The object/attribute does not exist";
break;
case CIBRES_CORRUPT:
error_msg = "The CIB is corrupt";
break;
case cib_NOOBJECT:
error_msg = "The update was empty";
break;
case cib_NOPARENT:
error_msg = "The parent object does not exist";
break;
case cib_NODECOPY:
error_msg = "Failed while copying update";
break;
case CIBRES_OTHER:
error_msg = "CIBRES_OTHER";
break;
case cib_ok:
error_msg = "ok";
break;
case cib_unknown:
error_msg = "Unknown error";
break;
case cib_STALE:
error_msg = "Discarded old update";
break;
case cib_ACTIVATION:
error_msg = "Activation Failed";
break;
case cib_NOSECTION:
error_msg = "Required section was missing";
break;
case cib_NOTSUPPORTED:
error_msg = "Supplied information is not supported";
break;
case cib_not_master:
error_msg = "Local service is not the master instance";
break;
case cib_client_corrupt:
error_msg = "Service client not valid";
break;
case cib_remote_timeout:
error_msg = "Remote node did not respond";
break;
case cib_master_timeout:
error_msg = "No master service is currently active";
break;
case cib_revision_unsupported:
error_msg = "The required CIB revision number is not supported";
break;
case cib_revision_unknown:
error_msg = "The CIB revision number could not be determined";
break;
case cib_missing_data:
error_msg = "Required data for this CIB API call not found";
break;
case cib_no_quorum:
error_msg = "Write requires quorum";
break;
case cib_diff_failed:
error_msg = "Application of an update diff failed";
break;
case cib_diff_resync:
error_msg = "Application of an update diff failed, requesting a full refresh";
break;
case cib_bad_section:
error_msg = "Invalid CIB section specified";
break;
case cib_old_data:
error_msg = "Update was older than existing configuration";
break;
case cib_dtd_validation:
error_msg = "Update does not conform to the DTD in "DTD_DIRECTORY"/crm.dtd";
break;
case cib_invalid_argument:
error_msg = "Invalid argument";
break;
}
if(error_msg == NULL) {
crm_err("Unknown CIB Error Code: %d", return_code);
error_msg = "<unknown error>";
}
return error_msg;
}
const char *
cib_op2string(enum cib_update_op operation)
{
const char *operation_msg = NULL;
switch(operation) {
case 0:
operation_msg = "none";
break;
case 1:
operation_msg = "add";
break;
case 2:
operation_msg = "modify";
break;
case 3:
operation_msg = "delete";
break;
case CIB_UPDATE_OP_MAX:
operation_msg = "invalid operation";
break;
}
if(operation_msg == NULL) {
crm_err("Unknown CIB operation %d", operation);
operation_msg = "<unknown operation>";
}
return operation_msg;
}
int
cib_section2enum(const char *a_section)
{
if(a_section == NULL || strcasecmp(a_section, "all") == 0) {
return cib_section_all;
} else if(strcasecmp(a_section, XML_CIB_TAG_NODES) == 0) {
return cib_section_nodes;
} else if(strcasecmp(a_section, XML_CIB_TAG_STATUS) == 0) {
return cib_section_status;
} else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) {
return cib_section_constraints;
} else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCES) == 0) {
return cib_section_resources;
} else if(strcasecmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) {
return cib_section_crmconfig;
}
crm_err("Unknown CIB section: %s", a_section);
return cib_section_none;
}
int
cib_compare_generation(crm_data_t *left, crm_data_t *right)
{
int lpc = 0;
const char *attributes[] = {
XML_ATTR_GENERATION_ADMIN,
XML_ATTR_GENERATION,
XML_ATTR_NUMUPDATES,
XML_ATTR_NUMPEERS
};
crm_log_xml_debug_3(left, "left");
crm_log_xml_debug_3(right, "right");
for(lpc = 0; lpc < DIMOF(attributes); lpc++) {
int int_elem_l = -1;
int int_elem_r = -1;
const char *elem_r = NULL;
const char *elem_l = crm_element_value(left, attributes[lpc]);
if(right != NULL) {
elem_r = crm_element_value(right, attributes[lpc]);
}
if(elem_l != NULL) { int_elem_l = crm_parse_int(elem_l, NULL); }
if(elem_r != NULL) { int_elem_r = crm_parse_int(elem_r, NULL); }
if(int_elem_l < int_elem_r) {
crm_debug_2("%s (%s < %s)", attributes[lpc],
crm_str(elem_l), crm_str(elem_r));
return -1;
} else if(int_elem_l > int_elem_r) {
crm_debug_2("%s (%s > %s)", attributes[lpc],
crm_str(elem_l), crm_str(elem_r));
return 1;
}
}
return 0;
}
crm_data_t*
get_cib_copy(cib_t *cib)
{
crm_data_t *xml_cib;
#if CRM_DEPRECATED_SINCE_2_0_4
crm_data_t *xml_cib_copy;
#endif
int options = cib_scope_local|cib_sync_call;
if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) {
crm_err("Couldnt retrieve the CIB");
return NULL;
} else if(xml_cib == NULL) {
crm_err("The CIB result was empty");
return NULL;
}
if(safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) {
return xml_cib;
#if CRM_DEPRECATED_SINCE_2_0_4
} else {
xml_cib_copy = copy_xml(
find_xml_node(xml_cib, XML_TAG_CIB, TRUE));
free_xml(xml_cib);
return xml_cib_copy;
#endif
}
free_xml(xml_cib);
return NULL;
}
crm_data_t*
cib_get_generation(cib_t *cib)
{
crm_data_t *the_cib = get_cib_copy(cib);
crm_data_t *generation = create_xml_node(
NULL, XML_CIB_TAG_GENERATION_TUPPLE);
if(the_cib != NULL) {
copy_in_properties(generation, the_cib);
free_xml(the_cib);
}
return generation;
}
gboolean
apply_cib_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **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) {
int len = 0;
crm_data_t *tmp = NULL;
crm_data_t *diff_copy = copy_xml(diff);
tmp = find_xml_node(diff_copy, "diff-removed", TRUE);
if(tmp != NULL) {
len = tmp->nfields;
cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN);
cl_msg_remove(tmp, XML_ATTR_GENERATION);
cl_msg_remove(tmp, XML_ATTR_NUMUPDATES);
}
tmp = find_xml_node(diff_copy, "diff-added", TRUE);
if(tmp != NULL) {
len = tmp->nfields;
cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN);
cl_msg_remove(tmp, XML_ATTR_GENERATION);
cl_msg_remove(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 xml_has_child(crm_data_t *data, const char *name);
gboolean
xml_has_child(crm_data_t *data, const char *name)
{
xml_child_iter_filter(data, child, name,
return TRUE;
);
return FALSE;
}
gboolean
cib_config_changed(crm_data_t *old_cib, crm_data_t *new_cib, crm_data_t **result)
{
gboolean config_changes = FALSE;
const char *tag = NULL;
crm_data_t *diff = NULL;
crm_data_t *dest = NULL;
if(result) {
*result = NULL;
}
diff = diff_xml_object(old_cib, new_cib, FALSE);
if(diff == NULL) {
return FALSE;
}
tag = "diff-removed";
dest = find_xml_node(diff, tag, FALSE);
if(dest) {
dest = find_xml_node(dest, "cib", FALSE);
}
if(dest) {
if(xml_has_child(dest, "status")) {
cl_msg_remove(dest, "status");
}
if(xml_has_children(dest)) {
config_changes = TRUE;
}
}
tag = "diff-added";
dest = find_xml_node(diff, tag, FALSE);
if(dest) {
dest = find_xml_node(dest, "cib", FALSE);
}
if(dest) {
if(xml_has_child(dest, "status")) {
cl_msg_remove(dest, "status");
}
- xml_prop_iter(dest, name, value, config_changes = TRUE);
+ xml_prop_iter(dest, name, value,
+ if(safe_str_neq(name, XML_ATTR_NUMUPDATES)) {
+ config_changes = TRUE;
+ break;
+ }
+ );
if(xml_has_children(dest)) {
config_changes = TRUE;
}
}
if(result) {
*result = diff;
} else {
free_xml(diff);
}
return config_changes;
}
crm_data_t *
diff_cib_object(crm_data_t *old_cib, crm_data_t *new_cib, gboolean suppress)
{
crm_data_t *dest = NULL;
crm_data_t *src = NULL;
const char *name = NULL;
const char *value = NULL;
crm_data_t *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;
}
void
log_cib_diff(int log_level, crm_data_t *diff, const char *function)
{
int add_updates = 0;
int add_epoch = 0;
int add_admin_epoch = 0;
int del_updates = 0;
int del_epoch = 0;
int del_admin_epoch = 0;
if(diff == NULL) {
return;
}
cib_diff_version_details(
diff, &add_admin_epoch, &add_epoch, &add_updates,
&del_admin_epoch, &del_epoch, &del_updates);
if(add_updates != del_updates) {
do_crm_log(log_level, "%s: Diff: --- %d.%d.%d", function,
del_admin_epoch, del_epoch, del_updates);
do_crm_log(log_level, "%s: Diff: +++ %d.%d.%d", function,
add_admin_epoch, add_epoch, add_updates);
} else if(diff != NULL) {
do_crm_log(log_level,
"%s: Local-only Change: %d.%d.%d", function,
add_admin_epoch, add_epoch, add_updates);
}
log_xml_diff(log_level, diff, function);
}
gboolean
cib_version_details(
crm_data_t *cib, int *admin_epoch, int *epoch, int *updates)
{
const char *value = NULL;
if(cib == NULL) {
*admin_epoch = -1;
*epoch = -1;
*updates = -1;
return FALSE;
} else {
value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN);
*admin_epoch = crm_parse_int(value, "-1");
value = crm_element_value(cib, XML_ATTR_GENERATION);
*epoch = crm_parse_int(value, "-1");
value = crm_element_value(cib, XML_ATTR_NUMUPDATES);
*updates = crm_parse_int(value, "-1");
}
return TRUE;
}
gboolean
cib_diff_version_details(
crm_data_t *diff, int *admin_epoch, int *epoch, int *updates,
int *_admin_epoch, int *_epoch, int *_updates)
{
crm_data_t *tmp = NULL;
tmp = find_xml_node(diff, "diff-added", FALSE);
cib_version_details(tmp, admin_epoch, epoch, updates);
tmp = find_xml_node(diff, "diff-removed", FALSE);
cib_version_details(tmp, _admin_epoch, _epoch, _updates);
return TRUE;
}
/*
* The caller should never free the return value
*/
crm_data_t*
get_object_root(const char *object_type, crm_data_t *the_root)
{
const char *node_stack[2];
crm_data_t *tmp_node = NULL;
if(the_root == NULL) {
crm_err("CIB root object was NULL");
return NULL;
}
node_stack[0] = XML_CIB_TAG_CONFIGURATION;
node_stack[1] = object_type;
if(object_type == NULL
|| strlen(object_type) == 0
|| safe_str_eq(XML_CIB_TAG_SECTION_ALL, object_type)
|| safe_str_eq(XML_TAG_CIB, object_type)) {
/* get the whole cib */
return the_root;
} else if(strcasecmp(object_type, XML_CIB_TAG_STATUS) == 0) {
/* these live in a different place */
tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, FALSE);
node_stack[0] = object_type;
node_stack[1] = NULL;
} else {
tmp_node = find_xml_node_nested(the_root, node_stack, 2);
}
if (tmp_node == NULL) {
crm_debug_2("Section [%s [%s]] not present in %s",
node_stack[0],
node_stack[1]?node_stack[1]:"",
crm_element_name(the_root));
}
return tmp_node;
}
const char *
get_crm_option(crm_data_t *cib, const char *name, gboolean do_warn)
{
const char * value = NULL;
crm_data_t * a_default = NULL;
crm_data_t * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib);
if(config != NULL) {
a_default = find_entity(config, XML_CIB_TAG_NVPAIR, name);
}
if(a_default == NULL) {
if(do_warn) {
crm_warn("Option %s not set", name);
}
return NULL;
}
value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE);
if(safe_str_eq(value, "")) {
value = NULL;
}
return value;
}
crm_data_t*
create_cib_fragment_adv(
crm_data_t *update, const char *update_section, const char *source)
{
crm_data_t *cib = NULL;
gboolean whole_cib = FALSE;
crm_data_t *object_root = NULL;
const char *update_name = NULL;
char *local_section = NULL;
/* crm_debug("Creating a blank fragment: %s", update_section); */
if(update == NULL && update_section == NULL) {
crm_debug_3("Creating a blank fragment");
update = createEmptyCib();
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
return update;
} else if(update == NULL) {
crm_err("No update to create a fragment for");
return NULL;
} else if(update_section == NULL) {
local_section = cib_pluralSection(update_name);
update_section = local_section;
}
if(safe_str_eq(crm_element_name(update), XML_TAG_CIB)) {
whole_cib = TRUE;
}
if(whole_cib == FALSE) {
cib = createEmptyCib();
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
object_root = get_object_root(update_section, cib);
add_node_copy(object_root, update);
} else {
cib = copy_xml(update);
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
}
crm_free(local_section);
crm_debug_3("Verifying created fragment");
if(verifyCibXml(cib) == FALSE) {
crm_err("Fragment creation failed");
crm_log_xml_err(cib, "[src]");
free_xml(cib);
cib = NULL;
}
return cib;
}
/*
* It is the callers responsibility to free both the new CIB (output)
* and the new CIB (input)
*/
crm_data_t*
createEmptyCib(void)
{
crm_data_t *cib_root = NULL, *config = NULL, *status = NULL;
cib_root = create_xml_node(NULL, XML_TAG_CIB);
config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
status = create_xml_node(cib_root, XML_CIB_TAG_STATUS);
/* crm_xml_add(cib_root, "version", "1"); */
crm_xml_add(cib_root, "generated", XML_BOOLEAN_TRUE);
create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
create_xml_node(config, XML_CIB_TAG_NODES);
create_xml_node(config, XML_CIB_TAG_RESOURCES);
create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
if (verifyCibXml(cib_root)) {
return cib_root;
}
free_xml(cib_root);
crm_crit("The generated CIB did not pass integrity testing!!"
" All hope is lost.");
return NULL;
}
gboolean
verifyCibXml(crm_data_t *cib)
{
int lpc = 0;
gboolean is_valid = TRUE;
crm_data_t *tmp_node = NULL;
const char *sections[] = {
XML_CIB_TAG_NODES,
XML_CIB_TAG_RESOURCES,
XML_CIB_TAG_CONSTRAINTS,
XML_CIB_TAG_STATUS,
XML_CIB_TAG_CRMCONFIG
};
if (cib == NULL) {
crm_warn("CIB was empty.");
return FALSE;
}
/* basic tests... are the standard section all there */
for(lpc = 0; lpc < DIMOF(sections); lpc++) {
tmp_node = get_object_root(sections[lpc], cib);
if (tmp_node == NULL) {
crm_warn("Section %s is not present in the CIB",
sections[lpc]);
is_valid = FALSE;
}
}
/* more integrity tests */
return is_valid;
}
gboolean verify_cib_cmds(cib_t *cib)
{
gboolean valid = TRUE;
if(cib->cmds->variant_op == NULL) {
crm_err("Operation variant_op not set");
valid = FALSE;
}
if(cib->cmds->signon == NULL) {
crm_err("Operation signon not set");
valid = FALSE;
}
if(cib->cmds->signoff == NULL) {
crm_err("Operation signoff not set");
valid = FALSE;
}
if(cib->cmds->free == NULL) {
crm_err("Operation free not set");
valid = FALSE;
}
if(cib->cmds->set_op_callback == NULL) {
crm_err("Operation set_op_callback not set");
valid = FALSE;
}
if(cib->cmds->add_notify_callback == NULL) {
crm_err("Operation add_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->del_notify_callback == NULL) {
crm_err("Operation del_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->set_connection_dnotify == NULL) {
crm_err("Operation set_connection_dnotify not set");
valid = FALSE;
}
if(cib->cmds->channel == NULL) {
crm_err("Operation channel not set");
valid = FALSE;
}
if(cib->cmds->inputfd == NULL) {
crm_err("Operation inputfd not set");
valid = FALSE;
}
if(cib->cmds->noop == NULL) {
crm_err("Operation noop not set");
valid = FALSE;
}
if(cib->cmds->ping == NULL) {
crm_err("Operation ping not set");
valid = FALSE;
}
if(cib->cmds->query == NULL) {
crm_err("Operation query not set");
valid = FALSE;
}
if(cib->cmds->query_from == NULL) {
crm_err("Operation query_from not set");
valid = FALSE;
}
if(cib->cmds->is_master == NULL) {
crm_err("Operation is_master not set");
valid = FALSE;
}
if(cib->cmds->set_master == NULL) {
crm_err("Operation set_master not set");
valid = FALSE;
}
if(cib->cmds->set_slave == NULL) {
crm_err("Operation set_slave not set");
valid = FALSE;
}
if(cib->cmds->set_slave_all == NULL) {
crm_err("Operation set_slave_all not set");
valid = FALSE;
}
if(cib->cmds->sync == NULL) {
crm_err("Operation sync not set");
valid = FALSE;
} if(cib->cmds->sync_from == NULL) {
crm_err("Operation sync_from not set");
valid = FALSE;
}
if(cib->cmds->bump_epoch == NULL) {
crm_err("Operation bump_epoch not set");
valid = FALSE;
}
if(cib->cmds->create == NULL) {
crm_err("Operation create not set");
valid = FALSE;
}
if(cib->cmds->modify == NULL) {
crm_err("Operation modify not set");
valid = FALSE;
}
if(cib->cmds->replace == NULL) {
crm_err("Operation replace not set");
valid = FALSE;
}
if(cib->cmds->delete == NULL) {
crm_err("Operation delete not set");
valid = FALSE;
}
if(cib->cmds->erase == NULL) {
crm_err("Operation erase not set");
valid = FALSE;
}
if(cib->cmds->quit == NULL) {
crm_err("Operation quit not set");
valid = FALSE;
}
if(cib->cmds->msgready == NULL) {
crm_err("Operation msgready not set");
valid = FALSE;
}
if(cib->cmds->rcvmsg == NULL) {
crm_err("Operation rcvmsg not set");
valid = FALSE;
}
if(cib->cmds->dispatch == NULL) {
crm_err("Operation dispatch not set");
valid = FALSE;
}
return valid;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:29 AM (5 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018258
Default Alt Text
(41 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment