diff --git a/lib/crm/Makefile.am b/lib/crm/Makefile.am new file mode 100644 index 0000000000..dc59cdeae1 --- /dev/null +++ b/lib/crm/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright (C) 2004 Andrew Beekhof +# +# 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 +# of the License, or (at your option) any later version. +# +# This program 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 program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +MAINTAINERCLEANFILES = Makefile.in + +## Subdirectories... +SUBDIRS = cib +DIST_SUBDIRS = cib diff --git a/lib/crm/cib/Makefile.am b/lib/crm/cib/Makefile.am new file mode 100644 index 0000000000..e950a2b2a7 --- /dev/null +++ b/lib/crm/cib/Makefile.am @@ -0,0 +1,55 @@ +# +# Copyright (C) 2004 Andrew Beekhof +# +# 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 +# of the License, or (at your option) any later version. +# +# This program 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 program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \ + -I$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \ + -I$(top_builddir) -I$(top_srcdir) + +hadir = $(sysconfdir)/ha.d +halibdir = $(libdir)/@HB_PKG@ +commmoddir = $(halibdir)/modules/comm +havarlibdir = $(localstatedir)/lib/@HB_PKG@ +crmdir = $(havarlibdir)/crm +XML_FLAGS = `xml2-config --cflags` +XML_LIBS = `xml2-config --libs` + +# sockets with path +apigid = @HA_APIGID@ +crmuid = @HA_CCMUID@ + +LIBRT = @LIBRT@ +AM_CFLAGS = @CFLAGS@ -DPIDFILE='"$(PIDFILE)"' $(CRM_DEBUG_FLAGS) + +## libraries +lib_LTLIBRARIES = libcib.la + +## SOURCES +noinst_HEADERS = +libcib_la_SOURCES = cib_client.c cib_native.c + +libcib_la_LDFLAGS = -version-info 0:0:0 +libcib_la_CFLAGS = -I$(top_builddir) + +clean-generic: + rm -f *.log *.debug *.xml *~ + +install-exec-local: + +uninstall-local: diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c new file mode 100755 index 0000000000..c2c98e851d --- /dev/null +++ b/lib/crm/cib/cib_client.c @@ -0,0 +1,835 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +int cib_client_set_op_callback( + cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, + int rc, xmlNodePtr output)); +int cib_client_noop(cib_t *cib, int call_options); +int cib_client_ping(cib_t *cib, xmlNodePtr *output_data, int call_options); + +int cib_client_query(cib_t *cib, const char *section, + xmlNodePtr *output_data, int call_options); +int cib_client_query_from(cib_t *cib, const char *host, const char *section, + xmlNodePtr *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); + +gboolean cib_client_is_master(cib_t *cib); +int cib_client_set_slave(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, xmlNodePtr data, + xmlNodePtr *output_data, int call_options) ; +int cib_client_modify(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *output_data, int call_options) ; +int cib_client_replace(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *output_data, int call_options) ; +int cib_client_delete(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *output_data, int call_options) ; +int cib_client_erase( + cib_t *cib, xmlNodePtr *output_data, int call_options); +int cib_client_quit(cib_t *cib, int call_options); + +extern cib_t *cib_native_new(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; + } + + crm_malloc(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_callback_list = NULL; + + /* the rest will get filled in by the variant constructor */ + crm_malloc(new_cib->cmds, sizeof(cib_api_operations_t)); + memset(new_cib->cmds, 0, sizeof(cib_api_operations_t)); + + new_cib->cmds->set_op_callback = cib_client_set_op_callback; + + new_cib->cmds->sync = cib_client_sync; + new_cib->cmds->noop = cib_client_noop; + new_cib->cmds->ping = cib_client_ping; + new_cib->cmds->query = cib_client_query; + 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_slave = cib_client_set_slave; + new_cib->cmds->set_master = cib_client_set_master; + 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->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; + + cib_native_new(new_cib); + + return new_cib; +} + +int +cib_client_set_op_callback( + cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, + int rc, xmlNodePtr output)) +{ + if(callback == NULL) { + crm_info("Un-Setting operation callback"); + + } else { + crm_debug("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, call_options); +} + +int cib_client_ping(cib_t *cib, xmlNodePtr *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, output_data, call_options); +} + + +int cib_client_query(cib_t *cib, const char *section, + xmlNodePtr *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, + xmlNodePtr *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_CIB_QUERY, section, NULL, output_data, call_options); +} + + +gboolean 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, CRM_OP_CIB_ISMASTER, 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, CRM_OP_CIB_SLAVE, 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; + } + + return cib->cmds->variant_op( + cib, CRM_OP_CIB_MASTER, NULL,NULL,NULL, call_options); +} + + + +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, CRM_OP_CIB_BUMP, 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) +{ + enum cib_errors rc = cib_ok; + xmlNodePtr stored_cib = NULL; + xmlNodePtr current_cib = NULL; + + 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("Retrieving current CIB from %s", host); + rc = cib->cmds->query_from( + cib, host, section, ¤t_cib, call_options|cib_sync_call); + + if(rc == cib_ok) { + if(call_options & cib_scope_local) { + /* having scope == local makes no sense from here on */ + call_options ^= cib_scope_local; + } + + crm_debug("Storing current CIB (should trigger a store everywhere)"); + crm_xml_debug(current_cib, "XML to store"); + rc = cib->cmds->replace( + cib, section, current_cib, &stored_cib, call_options); + } + free_xml(current_cib); + free_xml(stored_cib); + + return rc; + +} + + +int cib_client_create(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *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_CIB_CREATE, section, data, output_data, call_options); +} + + +int cib_client_modify(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *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_CIB_UPDATE, section, data, output_data, call_options); +} + + +int cib_client_replace(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *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_CIB_REPLACE, NULL,NULL,NULL, call_options); +} + + +int cib_client_delete(cib_t *cib, const char *section, xmlNodePtr data, + xmlNodePtr *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_CIB_DELETE, section, data, output_data, call_options); +} + + +int cib_client_erase( + cib_t *cib, xmlNodePtr *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_CIB_ERASE, 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, call_options); +} + + +char * +cib_pluralSection(const char *a_section) +{ + char *a_section_parent = NULL; + if (a_section == NULL) { + a_section_parent = crm_strdup("all"); + + } else if(strcmp(a_section, XML_TAG_CIB) == 0) { + a_section_parent = crm_strdup("all"); + + } else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_NODES); + + } else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); + + } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); + + } else if(strcmp(a_section, "rsc_location") == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); + + } else if(strcmp(a_section, "rsc_dependancy") == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); + + } else if(strcmp(a_section, "rsc_order") == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); + + } else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); + + } else if(strcmp(a_section, XML_CIB_TAG_NVPAIR) == 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_verbose("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_msg_field_add: + error_msg = "failed adding field to cib message"; + 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 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; + } + + if(error_msg == NULL) { + crm_err("Unknown CIB Error Code: %d", return_code); + error_msg = ""; + } + + return error_msg; +} + +const char * +cib_op2string(enum cib_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_OP_MAX: + operation_msg = "invalid operation"; + break; + + } + + if(operation_msg == NULL) { + crm_err("Unknown CIB operation %d", operation); + operation_msg = ""; + } + + return operation_msg; +} + + + + +int +cib_section2enum(const char *a_section) +{ + if(a_section == NULL || strcmp(a_section, "all") == 0) { + return cib_section_all; + + } else if(strcmp(a_section, XML_CIB_TAG_NODES) == 0) { + return cib_section_nodes; + + } else if(strcmp(a_section, XML_CIB_TAG_STATUS) == 0) { + return cib_section_status; + + } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) { + return cib_section_constraints; + + } else if(strcmp(a_section, XML_CIB_TAG_RESOURCES) == 0) { + return cib_section_resources; + + } else if(strcmp(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(xmlNodePtr left, xmlNodePtr right) +{ + int int_gen_l = -1; + int int_gen_r = -1; + const char *gen_l = xmlGetProp(left, XML_ATTR_GENERATION); + const char *gen_r = xmlGetProp(right, XML_ATTR_GENERATION); + + if(gen_l != NULL) int_gen_l = atoi(gen_l); + if(gen_r != NULL) int_gen_r = atoi(gen_r); + + if(int_gen_l < int_gen_r) { + return -1; + + } else if(int_gen_l > int_gen_r) { + return 1; + } + + return 0; +} + + +xmlNodePtr +get_cib_copy(cib_t *cib) +{ + xmlNodePtr xml_cib; + 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; + } + return xml_cib; +} + +xmlNodePtr +cib_get_generation(cib_t *cib) +{ + xmlNodePtr the_cib = get_cib_copy(cib); + xmlNodePtr generation = create_xml_node(NULL, "generation_tuple"); + + copy_in_properties(generation, the_cib); + free_xml(the_cib); + + return generation; +} + +/* + * The caller should never free the return value + */ +xmlNodePtr +get_object_root(const char *object_type, xmlNodePtr the_root) +{ + const char *node_stack[2]; + xmlNodePtr tmp_node = NULL; + + if(the_root == NULL) { + crm_err("CIB root object was NULL"); + return NULL; + + } else if(object_type == NULL) { + crm_debug("Returning the whole CIB"); + return the_root; + } + + node_stack[0] = XML_CIB_TAG_CONFIGURATION; + node_stack[1] = object_type; + + if(object_type == NULL + || strlen(object_type) == 0 + || safe_str_eq("all", object_type)) { + return the_root; + /* get the whole cib */ + + } else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) { + /* these live in a different place */ + tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS); + + node_stack[0] = XML_CIB_TAG_STATUS; + node_stack[1] = NULL; + +/* } else if(strcmp(object_type, XML_CIB_TAG_CRMCONFIG) == 0) { */ +/* /\* these live in a different place too *\/ */ +/* tmp_node = find_xml_node(the_root, XML_CIB_TAG_CRMCONFIG); */ + +/* node_stack[0] = XML_CIB_TAG_CRMCONFIG; */ +/* node_stack[1] = NULL; */ + + } else { + tmp_node = find_xml_node_nested(the_root, node_stack, 2); + } + + if (tmp_node == NULL) { + crm_err("[cib] Section %s [%s [%s]] not present", + the_root->name, + node_stack[0], + node_stack[1]?node_stack[1]:""); + } + return tmp_node; +} + + +xmlNodePtr +create_cib_fragment_adv( + xmlNodePtr update, const char *section, const char *source) +{ + gboolean whole_cib = FALSE; + xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); + xmlNodePtr cib = NULL; + xmlNodePtr object_root = NULL; + char *auto_section = cib_pluralSection(update?update->name:NULL); + + if(update == NULL) { + crm_err("No update to create a fragment for"); + crm_free(auto_section); + return NULL; + + } else if(section == NULL) { + section = auto_section; + + } else if(strcmp(auto_section, section) != 0) { + crm_err("Values for update (tag=%s) and section (%s)" + " were not consistent", update->name, section); + crm_free(auto_section); + return NULL; + + } + + if(strcmp(section, "all")==0 && strcmp(update->name, XML_TAG_CIB)==0) { + whole_cib = TRUE; + } + + set_xml_property_copy(fragment, XML_ATTR_SECTION, section); + + if(whole_cib == FALSE) { + cib = createEmptyCib(); + object_root = get_object_root(section, cib); + xmlAddChildList(object_root, xmlCopyNodeList(update)); + + } else { + cib = xmlCopyNodeList(update); + } + + xmlAddChild(fragment, cib); + set_xml_property_copy(cib, "debug_source", source); + + crm_free(auto_section); + + crm_debug("Verifying created fragment"); + if(verifyCibXml(cib) == FALSE) { + crm_err("Fragment creation failed"); + crm_err("[src] %s", dump_xml_formatted(update)); + crm_err("[created] %s", dump_xml_formatted(fragment)); + free_xml(fragment); + fragment = NULL; + } + + return fragment; +} + +/* + * It is the callers responsibility to free both the new CIB (output) + * and the new CIB (input) + */ +xmlNodePtr +createEmptyCib(void) +{ + xmlNodePtr 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); + + set_node_tstamp(cib_root); + set_node_tstamp(config); + set_node_tstamp(status); + + set_xml_property_copy(cib_root, "version", "1"); + set_xml_property_copy(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; + } + crm_crit("The generated CIB did not pass integrity testing!!" + " All hope is lost."); + return NULL; +} + + +gboolean +verifyCibXml(xmlNodePtr cib) +{ + gboolean is_valid = TRUE; + xmlNodePtr tmp_node = NULL; + + if (cib == NULL) { + crm_warn("XML Buffer was empty."); + return FALSE; + } + + tmp_node = get_object_root(XML_CIB_TAG_NODES, cib); + if (tmp_node == NULL) is_valid = FALSE; + + tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, cib); + if (tmp_node == NULL) is_valid = FALSE; + + tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + if (tmp_node == NULL) is_valid = FALSE; + + tmp_node = get_object_root(XML_CIB_TAG_STATUS, cib); + if (tmp_node == NULL) is_valid = FALSE; + + tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); + if (tmp_node == NULL) is_valid = FALSE; + + /* more integrity tests */ + + return is_valid; +} + diff --git a/lib/crm/cib/cib_native.c b/lib/crm/cib/cib_native.c new file mode 100755 index 0000000000..c3b3c0bee8 --- /dev/null +++ b/lib/crm/cib/cib_native.c @@ -0,0 +1,528 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct cib_native_opaque_s +{ + IPC_Channel *command_channel; + IPC_Channel *callback_channel; +/* GCHSource *callback_source; */ + +} cib_native_opaque_t; + +int cib_native_perform_op( + cib_t *cib, const char *op, const char *section, + xmlNodePtr data, xmlNodePtr *output_data, int call_options); + +int cib_native_signon(cib_t* cib, enum cib_conn_type type); +int cib_native_signoff(cib_t* cib); +int cib_native_free(cib_t* cib); + +IPC_Channel *cib_native_channel(cib_t* cib); +int cib_native_inputfd(cib_t* cib); + +gboolean cib_native_msgready(cib_t* cib); +int cib_native_rcvmsg(cib_t* cib, int blocking); +gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data); +cib_t *cib_native_new (cib_t *cib); +int cib_native_set_connection_dnotify( + cib_t *cib, void (*dnotify)(gpointer user_data)); + +cib_t* +cib_native_new (cib_t *cib) +{ + cib_native_opaque_t *native = NULL; + crm_malloc(cib->variant_opaque, sizeof(cib_native_opaque_t)); + + native = cib->variant_opaque; + native->command_channel = NULL; + native->callback_channel = NULL; + + /* assign variant specific ops*/ + cib->cmds->variant_op = cib_native_perform_op; + cib->cmds->signon = cib_native_signon; + cib->cmds->signoff = cib_native_signoff; + cib->cmds->free = cib_native_free; + cib->cmds->channel = cib_native_channel; + cib->cmds->inputfd = cib_native_inputfd; + cib->cmds->msgready = cib_native_msgready; + cib->cmds->rcvmsg = cib_native_rcvmsg; + cib->cmds->dispatch = cib_native_dispatch; + + cib->cmds->set_connection_dnotify = cib_native_set_connection_dnotify; + + return cib; +} + +int +cib_native_signon(cib_t* cib, enum cib_conn_type type) +{ + int rc = cib_ok; + char *uuid_ticket = NULL; + struct ha_msg *reg_msg = NULL; + cib_native_opaque_t *native = cib->variant_opaque; + + crm_trace("Connecting command channel"); + if(type == cib_command) { + cib->state = cib_connected_command; + native->command_channel = init_client_ipc_comms_nodispatch( + "cib_rw"); + + } else { + cib->state = cib_connected_query; + native->command_channel = init_client_ipc_comms_nodispatch( + "cib_ro"); + } + + if(native->command_channel == NULL) { + crm_err("Connection to command channel failed"); + rc = cib_connection; + + } else if(native->command_channel->ch_status != IPC_CONNECT) { + crm_err("Connection may have succeeded," + " but authentication to command channel failed"); + rc = cib_authentication; + } + + if(rc == cib_ok) { + crm_trace("Connecting callback channel"); +/* native->callback_source = init_client_ipc_comms( */ + native->callback_channel = init_client_ipc_comms( + "cib_callback", cib_native_dispatch, cib); +/* native->callback_channel = native->callback_source->ch; */ + + if(native->callback_channel == NULL) { + crm_err("Connection to callback channel failed"); + rc = cib_connection; + } + + } else if(rc == cib_ok + && native->callback_channel->ch_status != IPC_CONNECT) { + crm_err("Connection may have succeeded," + " but authentication to callback channel failed"); + rc = cib_authentication; + } + + if(rc == cib_ok) { + const char *msg_type = NULL; + crm_trace("Waiting for msg on command channel"); + reg_msg = msgfromIPC_noauth(native->command_channel); + + msg_type = cl_get_string(reg_msg, F_CIB_OPERATION); + if(safe_str_neq(msg_type, CRM_OP_REGISTER) ) { + crm_err("Invalid registration message: %s", msg_type); + rc = cib_registration_msg; + + } else { + const char *tmp_ticket = NULL; + crm_trace("Retrieving callback channel ticket"); + tmp_ticket = cl_get_string( + reg_msg, F_CIB_CALLBACK_TOKEN); + + if(tmp_ticket == NULL) { + rc = cib_callback_token; + } else { + uuid_ticket = crm_strdup(tmp_ticket); + } + } + + ha_msg_del(reg_msg); + reg_msg = NULL; + } + + if(rc == cib_ok) { + crm_trace("Registering callback channel with ticket %s", + uuid_ticket); + reg_msg = ha_msg_new(2); + ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); + ha_msg_add(reg_msg, F_CIB_CALLBACK_TOKEN, uuid_ticket); + if(msg2ipcchan(reg_msg, native->callback_channel) != HA_OK) { + rc = cib_callback_register; + } + crm_free(uuid_ticket); + ha_msg_del(reg_msg); + + } + if(rc == cib_ok) { + crm_trace("wait for the callback channel setup to complete"); + reg_msg = msgfromIPC_noauth(native->callback_channel); + + if(reg_msg == NULL) { + crm_err("Connection to callback channel not maintined"); + rc = cib_connection; + } + ha_msg_del(reg_msg); + } + + if(rc == cib_ok) { + crm_info("Connection to CIB successful"); + return cib_ok; + } + crm_err("Connection to CIB failed: %s", cib_error2string(rc)); + cib_native_signoff(cib); + return rc; +} + +int +cib_native_signoff(cib_t* cib) +{ + cib_native_opaque_t *native = cib->variant_opaque; + + crm_info("Signing out of the CIB Service"); + + /* close channels */ + if (native->command_channel != NULL) { + native->command_channel->ops->destroy( + native->command_channel); + native->command_channel = NULL; + } + if (native->callback_channel != NULL) { + native->callback_channel->ops->destroy( + native->callback_channel); + native->callback_channel = NULL; + } + cib->state = cib_disconnected; + cib->type = cib_none; + + return cib_ok; +} + +int +cib_native_free (cib_t* cib) +{ + int rc = cib_ok; + + crm_warn("Freeing CIB"); + if(cib->state != cib_disconnected) { + rc = cib_native_signoff(cib); + if(rc == cib_ok) { + crm_free(cib); + } + } + + return rc; +} + +IPC_Channel * +cib_native_channel(cib_t* cib) +{ + cib_native_opaque_t *native = NULL; + if(cib == NULL) { + crm_err("Missing cib object"); + return NULL; + } + + native = cib->variant_opaque; + + if(native != NULL) { + return native->callback_channel; + } + + crm_err("couldnt find variant specific data in %p", cib); + return NULL; +} + + +int +cib_native_inputfd(cib_t* cib) +{ + IPC_Channel *ch = cib_native_channel(cib); + return ch->ops->get_recv_select_fd(ch); +} + +int +cib_native_perform_op( + cib_t *cib, const char *op, const char *section, + xmlNodePtr data, xmlNodePtr *output_data, int call_options) +{ + int rc = HA_OK; + + size_t calldata_len = 0; + + char *calldata = NULL; + const char *output = NULL; + + struct ha_msg *op_msg = NULL; + struct ha_msg *op_reply = NULL; + + cib_native_opaque_t *native = cib->variant_opaque; + + if(cib->state == cib_disconnected) { + return cib_not_connected; + } + + if(output_data != NULL) { + *output_data = NULL; + } + + op_msg = ha_msg_new(5); + if(op == NULL) { + crm_err("No operation specified"); + rc = cib_operation; + } + + if(rc == HA_OK) { + rc = ha_msg_add(op_msg, F_TYPE, "cib"); + } + if(rc == HA_OK) { + rc = ha_msg_add(op_msg, F_CIB_OPERATION, op); + } + if(rc == HA_OK && section != NULL) { + rc = ha_msg_add(op_msg, F_CIB_SECTION, section); + } + if(rc == HA_OK) { + char *tmp = crm_itoa(cib->call_id); + rc = ha_msg_add(op_msg, F_CIB_CALLID, tmp); + crm_free(tmp); + } + if(rc == HA_OK) { + char *tmp = crm_itoa(call_options); + crm_trace("Sending call options: %.8lx, %d, %s", + (long)call_options, call_options, tmp); + rc = ha_msg_add(op_msg, F_CIB_CALLOPTS, tmp); + crm_free(tmp); + } + if(rc == HA_OK) { + calldata = dump_xml_unformatted(data); + if(calldata != NULL) { + calldata_len = strlen(calldata) + 1; + rc = ha_msg_add(op_msg, F_CIB_CALLDATA, calldata); + } + + crm_free(calldata); + } + + if (rc != HA_OK) { + ha_msg_del(op_msg); + crm_err("Failed to create CIB operation message"); + return cib_create_msg; + } + + cib->call_id++; + + rc = msg2ipcchan(op_msg, native->command_channel); + ha_msg_del(op_msg); + + if (rc != HA_OK) { + return cib_send_failed; + } + + if( !(call_options & cib_sync_call)) { + return cib->call_id - 1; + } + + op_reply = msgfromIPC_noauth(native->command_channel); + if (op_reply == NULL) { + crm_err("No reply message"); + return cib_reply_failed; + } + + rc = cib_ok; + + /* Start processing the reply... */ + if(cl_get_int(op_reply, F_CIB_RC, &rc) != HA_OK) { + rc = cib_return_code; + } + + /* eg. op may have been a privelidged action and we are in query mode */ + if(rc != cib_ok) { + ha_msg_del(op_reply); + return rc; + } + + if(!(call_options & cib_discard_reply)) { + output = cl_get_string(op_msg, F_CIB_CALLDATA); + } + + if(output != NULL && output_data == NULL) { + rc = cib_output_ptr; + + } else if(output != NULL) { + *output_data = string2xml(output); + if(*output_data == NULL) { + rc = cib_output_data; + } + } else { + crm_debug("No output in reply to \"%s\" command %d", + op, cib->call_id - 1); + } + + ha_msg_del(op_reply); + + return rc; +} + +gboolean +cib_native_msgready(cib_t* cib) +{ + IPC_Channel *ch = NULL; + cib_native_opaque_t *native = NULL; + + if (cib == NULL) { + crm_err("No CIB!"); + return FALSE; + } + + native = cib->variant_opaque; + + ch = cib_native_channel(cib); + if (ch == NULL) { + crm_err("No channel"); + return FALSE; + } + + if(native->command_channel->ops->is_message_pending( + native->command_channel)) { + crm_warn("Message pending on command channel"); + } + if(native->callback_channel->ops->is_message_pending( + native->callback_channel)) { + crm_info("Message pending on callback channel"); + return TRUE; + } + crm_info("No message pending"); + return FALSE; +} + +int +cib_native_rcvmsg(cib_t* cib, int blocking) +{ + const char *type = NULL; + struct ha_msg* msg = NULL; + IPC_Channel *ch = cib_native_channel(cib); + + /* if it is not blocking mode and no message in the channel, return */ + if (blocking == 0 && cib_native_msgready(cib) == FALSE) { + crm_debug("No message ready and non-blocking..."); + return 0; + + } else if (cib_native_msgready(cib) == FALSE) { + crm_debug("Waiting for message from CIB service..."); + ch->ops->waitin(ch); + } + + /* get the message */ + msg = msgfromIPC_noauth(ch); + if (msg == NULL) { + crm_warn("Received a NULL msg from CIB service."); + return 0; + } + + /* do callbacks */ + type = cl_get_string(msg, F_TYPE); + crm_trace("Activating %s callbacks...", type); + + if(cib->op_callback == NULL) { + crm_debug("No OP callback set, ignoring reply"); + + } else { + int rc = 0; + int call_id = 0; + xmlNodePtr output = NULL; + const char *output_s = NULL; + + cl_get_int(msg, F_CIB_CALLID, &call_id); + cl_get_int(msg, F_CIB_RC, &rc); + output_s = cl_get_string(msg, F_CIB_CALLDATA); + if(output_s != NULL) { + output = string2xml(output_s); + } + + cib->op_callback(msg, call_id, rc, output); + + crm_trace("OP callback activated."); + } + + ha_msg_del(msg); + + return 1; +} + + +gboolean +cib_native_dispatch(IPC_Channel *channel, gpointer user_data) +{ + int lpc = 0; + cib_t *cib = user_data; + + crm_debug("Received callback"); + + if(user_data == NULL){ + crm_err("user_data field must contain the CIB struct"); + return FALSE; + } + + while(cib_native_msgready(cib)) { + lpc++; + /* invoke the callbacks but dont block */ + if(cib_native_rcvmsg(cib, 0) < 1) { + break; + } + } + + crm_debug("%d CIB messages dispatched", lpc); + + if (channel && (channel->ch_status == IPC_DISCONNECT)) { + crm_crit("Lost connection to the CIB service."); + return FALSE; + } + + return TRUE; +} + +int cib_native_set_connection_dnotify( + cib_t *cib, void (*dnotify)(gpointer user_data)) +{ + cib_native_opaque_t *native = NULL; + + if (cib == NULL) { + crm_err("No CIB!"); + return FALSE; + } + + native = cib->variant_opaque; + +#if 0 + if(dnotify == NULL) { + crm_warn("Setting dnotify back to default value"); + native->callback_source->dnotify = + default_ipc_connection_destroy; + + } else { + crm_debug("Setting dnotify"); + native->callback_source->dnotify = dnotify; + } +#endif + return cib_ok; +} + +