diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c index c2c98e851d..400badfa7c 100755 --- a/lib/crm/cib/cib_client.c +++ b/lib/crm/cib/cib_client.c @@ -1,835 +1,986 @@ /* * 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 +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, 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_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, 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_slave_all = cib_client_set_slave_all; 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); - + if(verify_cib_cmds(new_cib) == FALSE) { + return NULL; + } + 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); + cib, CRM_OP_NOOP, NULL, 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); + cib, CRM_OP_PING, NULL,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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_QUERY, host, 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, CRM_OP_CIB_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, CRM_OP_CIB_SLAVE, NULL,NULL,NULL, call_options); + cib, CRM_OP_CIB_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, CRM_OP_CIB_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("Adding cib_scope_local to options"); return cib->cmds->variant_op( - cib, CRM_OP_CIB_MASTER, NULL,NULL,NULL, call_options); + cib, CRM_OP_CIB_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, CRM_OP_CIB_BUMP, NULL, NULL, NULL, call_options); + cib, CRM_OP_CIB_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) { 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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_CREATE, NULL, 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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_UPDATE, NULL, 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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_REPLACE, NULL, NULL, + data, output_data, 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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_DELETE, NULL, 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); + return cib->cmds->variant_op(cib, CRM_OP_CIB_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, call_options); + cib, CRM_OP_QUIT, NULL, 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; + 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; } 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); + crm_xml_trace(left, "left"); + crm_xml_trace(left, "right"); + if(int_gen_l < int_gen_r) { + crm_trace("lt"); return -1; } else if(int_gen_l > int_gen_r) { + crm_trace("gt"); return 1; } + crm_trace("eq"); 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; } + +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->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; +} diff --git a/lib/crm/cib/cib_native.c b/lib/crm/cib/cib_native.c index 7cf59c7f45..445d06c718 100755 --- a/lib/crm/cib/cib_native.c +++ b/lib/crm/cib/cib_native.c @@ -1,528 +1,535 @@ /* * 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, + cib_t *cib, const char *op, const char *host, 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, + cib_t *cib, const char *op, const char *host, 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); + op_msg = ha_msg_new(7); 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 && host != NULL) { + rc = ha_msg_add(op_msg, F_CIB_HOST, host); + } 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); + } else { + crm_debug("Calldata string was NULL (xml=%p)", data); } 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++; - + + crm_debug("Sending message to CIB service"); + cl_log_message(op_msg); 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(ha_msg_value_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; ha_msg_value_int(msg, F_CIB_CALLID, &call_id); ha_msg_value_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; }