diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index cd4a61138e..f686aa05bd 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,570 +1,576 @@ -/* $Id: cibadmin.c,v 1.33 2005/06/02 09:23:43 andrew Exp $ */ +/* $Id: cibadmin.c,v 1.34 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* someone complaining about _ha_msg_mod not being found */ #include int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; const char *crm_system_name = "cibadmin"; IPC_Channel *crmd_channel = NULL; const char *host = NULL; void usage(const char *cmd, int exit_status); enum cib_errors do_init(void); int do_work(const char *xml_text, int command_options, crm_data_t **output); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); crm_data_t *handleCibMod(const char *xml); gboolean admin_message_timeout(gpointer data); void cib_connection_destroy(gpointer user_data); void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); int command_options = 0; const char *cib_action = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; char *id = NULL; char *this_msg_reference = NULL; char *obj_type = NULL; char *clear = NULL; char *status = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int request_id = 0; int operation_status = 0; cib_t *the_cib = NULL; #define OPTARGS "V?i:o:QDUCEX:t:Srwlsh:MBfb" int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; char *admin_input_xml = NULL; crm_data_t *output = NULL; static struct option long_options[] = { /* Top-level Options */ - {CRM_OP_CIB_ERASE, 0, 0, 'E'}, - {CRM_OP_CIB_QUERY, 0, 0, 'Q'}, - {CRM_OP_CIB_CREATE, 0, 0, 'C'}, - {CRM_OP_CIB_REPLACE, 0, 0, 'R'}, - {CRM_OP_CIB_UPDATE, 0, 0, 'U'}, - {CRM_OP_CIB_DELETE, 0, 0, 'D'}, - {CRM_OP_CIB_BUMP, 0, 0, 'B'}, - {CRM_OP_CIB_SYNC, 0, 0, 'S'}, - {CRM_OP_CIB_SLAVE, 0, 0, 'r'}, - {CRM_OP_CIB_MASTER, 0, 0, 'w'}, - {CRM_OP_CIB_ISMASTER,0, 0, 'M'}, + {CIB_OP_ERASE, 0, 0, 'E'}, + {CIB_OP_QUERY, 0, 0, 'Q'}, + {CIB_OP_CREATE, 0, 0, 'C'}, + {CIB_OP_REPLACE, 0, 0, 'R'}, + {CIB_OP_UPDATE, 0, 0, 'U'}, + {CIB_OP_DELETE, 0, 0, 'D'}, + {CIB_OP_BUMP, 0, 0, 'B'}, + {CIB_OP_SYNC, 0, 0, 'S'}, + {CIB_OP_SLAVE, 0, 0, 'r'}, + {CIB_OP_MASTER, 0, 0, 'w'}, + {CIB_OP_ISMASTER,0, 0, 'M'}, {"force-quorum",0, 0, 'f'}, {"local", 0, 0, 'l'}, {"sync-call", 0, 0, 's'}, {"no-bcast", 0, 0, 'b'}, {"host", 0, 0, 'h'}, {F_CRM_DATA, 1, 0, 'X'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, {"timeout", 1, 0, 't'}, /* common options */ {XML_ATTR_ID, 1, 0, 'i'}, {"obj_type", 1, 0, 'o'}, {0, 0, 0, 0} }; crm_log_init(crm_system_name); cl_log_set_facility(LOG_USER); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (safe_str_eq("reference", long_options[option_index].name)) { this_msg_reference = crm_strdup(optarg); } else { printf("Long option (--%s) is not (yet?) properly supported\n", long_options[option_index].name); ++argerr; } break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case 'E': - cib_action = CRM_OP_CIB_ERASE; + cib_action = CIB_OP_ERASE; break; case 'Q': - cib_action = CRM_OP_CIB_QUERY; + cib_action = CIB_OP_QUERY; break; case 'S': - cib_action = CRM_OP_CIB_SYNC; + cib_action = CIB_OP_SYNC; break; case 'U': - cib_action = CRM_OP_CIB_UPDATE; + cib_action = CIB_OP_UPDATE; break; case 'R': - cib_action = CRM_OP_CIB_REPLACE; + cib_action = CIB_OP_REPLACE; break; case 'C': - cib_action = CRM_OP_CIB_CREATE; + cib_action = CIB_OP_CREATE; break; case 'D': - cib_action = CRM_OP_CIB_DELETE; + cib_action = CIB_OP_DELETE; break; case 'M': - cib_action = CRM_OP_CIB_ISMASTER; + cib_action = CIB_OP_ISMASTER; command_options |= cib_scope_local; break; case 'B': - cib_action = CRM_OP_CIB_BUMP; + cib_action = CIB_OP_BUMP; break; case 'r': - cib_action = CRM_OP_CIB_SLAVE; + cib_action = CIB_OP_SLAVE; break; case 'w': - cib_action = CRM_OP_CIB_MASTER; + cib_action = CIB_OP_MASTER; command_options |= cib_scope_local; break; case 'V': command_options = command_options | cib_verbose; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); id = crm_strdup(optarg); break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'X': admin_input_xml = crm_strdup(optarg); break; case 'h': host = crm_strdup(optarg); break; case 'l': command_options |= cib_scope_local; break; case 'b': command_options |= cib_inhibit_bcast; + command_options |= cib_scope_local; break; case 's': command_options |= cib_sync_call; break; case 'f': command_options |= cib_quorum_override; break; default: printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if(cib_action == NULL) { usage(crm_system_name, cib_operation); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } exit_code = do_init(); if(exit_code != cib_ok) { crm_err("Init failed, could not perform requested operations"); fprintf(stderr, "Init failed, could not perform requested operations\n"); return -exit_code; } exit_code = do_work(admin_input_xml, command_options, &output); if (exit_code > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ request_id = exit_code; add_cib_op_callback( request_id, FALSE, NULL, cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug("Setting operation timeout to %dms for call %d", message_timeout_ms, request_id); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); crm_debug_3("%s waiting for reply from the local CIB", crm_system_name); crm_info("Starting mainloop"); g_main_run(mainloop); } else if(exit_code < 0) { crm_err("Call failed: %s", cib_error2string(exit_code)); fprintf(stderr, "Call failed: %s\n", cib_error2string(exit_code)); operation_status = exit_code; } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } crm_data_t* handleCibMod(const char *xml) { const char *attr_name = NULL; const char *attr_value = NULL; crm_data_t *fragment = NULL; crm_data_t *cib_object = NULL; if(xml == NULL) { cib_object = stdin2xml(); } else { cib_object = string2xml(xml); } if(cib_object == NULL) { return NULL; } attr_name = XML_ATTR_ID; attr_value = crm_element_value(cib_object, attr_name); if(attr_name == NULL || strlen(attr_name) == 0) { crm_err("No value for %s specified.", attr_name); return NULL; } crm_debug_4("Object creation complete"); /* create the cib request */ fragment = create_cib_fragment(cib_object, NULL); return fragment; } int do_work(const char *admin_input_xml, int call_options, crm_data_t **output) { /* construct the request */ crm_data_t *msg_data = NULL; char *obj_type_parent = NULL; obj_type_parent = cib_pluralSection(obj_type); - if(strcmp(CRM_OP_CIB_QUERY, cib_action) == 0) { + if(strcmp(CIB_OP_QUERY, cib_action) == 0) { crm_debug_2("Querying the CIB for section: %s", obj_type_parent); return the_cib->cmds->query_from( the_cib, host, obj_type_parent, output, call_options); - } else if (strcmp(CRM_OP_CIB_ERASE, cib_action) == 0) { + } else if (strcmp(CIB_OP_ERASE, cib_action) == 0) { crm_debug_4("CIB Erase op in progress"); return the_cib->cmds->erase(the_cib, output, call_options); - } else if (strcmp(CRM_OP_CIB_CREATE, cib_action) == 0) { + } else if (strcmp(CIB_OP_CREATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->create( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; - } else if (strcmp(CRM_OP_CIB_UPDATE, cib_action) == 0) { + } else if (strcmp(CIB_OP_UPDATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->modify( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; - } else if (strcmp(CRM_OP_CIB_DELETE, cib_action) == 0) { + } else if (strcmp(CIB_OP_DELETE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->delete( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; - } else if (strcmp(CRM_OP_CIB_SYNC, cib_action) == 0) { + } else if (strcmp(CIB_OP_SYNC, cib_action) == 0) { crm_debug_4("Performing %s op...", cib_action); return the_cib->cmds->sync_from( the_cib, host, obj_type_parent, call_options); - } else if (strcmp(CRM_OP_CIB_SLAVE, cib_action) == 0 + } else if (strcmp(CIB_OP_SLAVE, cib_action) == 0 && (call_options ^ cib_scope_local) ) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_slave_all(the_cib, call_options); - } else if (strcmp(CRM_OP_CIB_MASTER, cib_action) == 0) { + } else if (strcmp(CIB_OP_MASTER, cib_action) == 0) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_master(the_cib, call_options); } else if(cib_action != NULL) { crm_debug_4("Passing \"%s\" to variant_op...", cib_action); return the_cib->cmds->variant_op( the_cib, cib_action, host, obj_type_parent, NULL, output, call_options); } else { crm_err("You must specify an operation"); } return cib_operation; } enum cib_errors do_init(void) { enum cib_errors rc = cib_ok; the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [-?Vio] command\n" "\twhere necessary, XML data will be expected using -X" " or on STDIN if -X isnt specified\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); + fprintf(stream, "\t\tValid values are: node, resource, node_state, constraint, nvpair\n"); fprintf(stream, "\t--%s (-%c)\tturn on debug info." " additional instance increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ERASE, 'E'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_QUERY, 'Q'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_CREATE, 'C'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_REPLACE,'R'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_UPDATE, 'U'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_DELETE, 'D'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_BUMP, 'B'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ISMASTER,'M'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_SYNC, 'S'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \t\n", F_CRM_DATA, 'X'); fprintf(stream, "\nAdvanced Options\n"); fprintf(stream, "\t--%s (-%c)\tsend command to specified host." " Applies to %s and %s commands only\n", "host", 'h', - CRM_OP_CIB_QUERY, CRM_OP_CIB_SYNC); + CIB_OP_QUERY, CIB_OP_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" " it altered the CIB\n", "no-bcast", 'b'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); fflush(stream); exit(exit_status); } gboolean admin_message_timeout(gpointer data) { - if(safe_str_eq(cib_action, CRM_OP_CIB_SLAVE)) { + if(safe_str_eq(cib_action, CIB_OP_SLAVE)) { exit_code = cib_ok; fprintf(stdout, "CIB service(s) are in slave mode.\n"); } else { exit_code = cib_reply_failed; fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); } g_main_quit(mainloop); return FALSE; } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { char *admin_input_xml = NULL; crm_info("our callback was invoked"); crm_log_message(LOG_MSG, msg); exit_code = rc; if(output != NULL) { admin_input_xml = dump_xml_formatted(output); } - if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER) && rc != cib_ok) { - crm_info("Local CIB is _not_ the master instance"); - fprintf(stderr, "Local CIB is _not_ the master instance\n"); + if(safe_str_eq(cib_action, CIB_OP_ISMASTER) && rc != cib_ok) { + crm_info("CIB on %s is _not_ the master instance", + host?host:"localhost"); + fprintf(stderr, "CIB on %s is _not_ the master instance", + host?host:"localhost"); - } else if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER)) { - crm_info("Local CIB _is_ the master instance"); - fprintf(stderr, "Local CIB _is_ the master instance\n"); + } else if(safe_str_eq(cib_action, CIB_OP_ISMASTER)) { + crm_info("CIB on %s _is_ the master instance", + host?host:"localhost"); + fprintf(stderr, "CIB on %s _is_ the master instance", + host?host:"localhost"); } else if(rc != 0) { crm_warn("Call %s failed (%d): %s", cib_action, rc, cib_error2string(rc)); fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, cib_error2string(rc)); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); - } else if(safe_str_eq(cib_action, CRM_OP_CIB_QUERY) && output==NULL) { + } else if(safe_str_eq(cib_action, CIB_OP_QUERY) && output==NULL) { crm_err("Output expected in query response"); crm_log_message(LOG_ERR, msg); } else if(output == NULL) { crm_info("Call passed"); } else { crm_info("Call passed"); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } crm_free(admin_input_xml); if(call_id == request_id) { g_main_quit(mainloop); } else { crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id); } } diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c index 736f76d7de..8421dc1b38 100644 --- a/crm/cib/callbacks.c +++ b/crm/cib/callbacks.c @@ -1,1350 +1,1359 @@ -/* $Id: callbacks.c,v 1.58 2005/06/12 06:47:58 alan Exp $ */ +/* $Id: callbacks.c,v 1.59 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include gint cib_GCompareFunc(gconstpointer a, gconstpointer b); gboolean cib_msg_timeout(gpointer data); void cib_GHFunc(gpointer key, gpointer value, gpointer user_data); gboolean ghash_str_clfree(gpointer key, gpointer value, gpointer user_data); gboolean can_write(int flags); HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data); gboolean ccm_manual_check(gpointer data); +extern enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags); +void send_cib_replace(const HA_Message *sync_request, const char *host); +void cib_process_request(const HA_Message *request, gboolean privileged, + gboolean from_peer, cib_client_t *cib_client); +gboolean syncd_once = FALSE; GHashTable *peer_hash = NULL; int next_client_id = 0; gboolean cib_is_master = FALSE; gboolean cib_have_quorum = FALSE; char * ccm_transition_id = NULL; GHashTable *client_list = NULL; GHashTable *ccm_membership = NULL; extern const char *cib_our_uname; extern ll_cluster_t *hb_conn; extern int set_connected_peers(crm_data_t *xml_obj); +/* +typedef struct cib_operation_s +{ + const char* operation; + gboolean modifies_cib; + gboolean needs_privileges; + gboolean needs_quorum; + gboolean needs_section; + gboolean needs_data; + enum cib_errors (*fn)( + const char *, int, const char *, + crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**); +} cib_operation_t; +*/ /* technically bump does modify the cib... * but we want to split the "bump" from the "sync" */ cib_operation_t cib_server_ops[] = { - {NULL, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default}, - {CRM_OP_NOOP, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default}, - {CRM_OP_RETRIVE_CIB, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_query}, - {CRM_OP_CIB_SLAVE, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, - {CRM_OP_CIB_SLAVEALL,TRUE, TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, - {CRM_OP_CIB_MASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, - {CRM_OP_CIB_ISMASTER,FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, - {CRM_OP_CIB_BUMP, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_bump}, - {CRM_OP_CIB_REPLACE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_replace}, - {CRM_OP_CIB_CREATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, - {CRM_OP_CIB_UPDATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, - {CRM_OP_JOIN_ACKNAK, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, - {CRM_OP_SHUTDOWN_REQ,TRUE, TRUE, FALSE,TRUE, TRUE, cib_process_modify}, - {CRM_OP_CIB_DELETE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, - {CRM_OP_CIB_QUERY, FALSE,FALSE,FALSE,TRUE, FALSE,cib_process_query}, - {CRM_OP_CIB_SYNC, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_query}, - {CRM_OP_QUIT, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_quit}, - {CRM_OP_PING, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_ping}, - {CRM_OP_CIB_ERASE, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_erase} + {NULL, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default}, + {CRM_OP_NOOP, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default}, + {CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_diff}, + {CIB_OP_SLAVE, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, + {CIB_OP_SLAVEALL, TRUE, TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, + {CIB_OP_SYNC_ONE, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync_one}, + {CIB_OP_MASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, + {CIB_OP_ISMASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite}, + {CIB_OP_BUMP, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_bump}, + {CIB_OP_REPLACE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_replace}, + {CIB_OP_CREATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, + {CIB_OP_UPDATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, + {CIB_OP_DELETE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify}, + {CIB_OP_QUERY, FALSE,FALSE,FALSE,TRUE, FALSE,cib_process_query}, + {CIB_OP_SYNC, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync}, + {CRM_OP_QUIT, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_quit}, + {CRM_OP_PING, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_ping}, + {CIB_OP_ERASE, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_erase} }; int send_via_callback_channel(HA_Message *msg, const char *token); enum cib_errors cib_process_command( - const HA_Message *request, HA_Message **reply, gboolean privileged); + const HA_Message *request, HA_Message **reply, + crm_data_t **cib_diff, gboolean privileged); gboolean cib_common_callback( IPC_Channel *channel, gpointer user_data, gboolean privileged); enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation); gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client); gboolean cib_client_connect(IPC_Channel *channel, gpointer user_data) { gboolean auth_failed = FALSE; gboolean can_connect = TRUE; gboolean (*client_callback)(IPC_Channel *channel, gpointer user_data) = NULL; cib_client_t *new_client = NULL; crm_debug_3("Connecting channel"); if (channel == NULL) { crm_err("Channel was NULL"); can_connect = FALSE; } else if (channel->ch_status == IPC_DISCONNECT) { crm_err("Channel was disconnected"); can_connect = FALSE; } else if(user_data == NULL) { crm_err("user_data must contain channel name"); can_connect = FALSE; } else { crm_malloc0(new_client, sizeof(cib_client_t)); new_client->id = NULL; new_client->callback_id = NULL; new_client->source = NULL; new_client->channel = channel; new_client->channel_name = user_data; new_client->delegated_calls = NULL; crm_debug_3("Created channel %p for channel %s", new_client, new_client->channel_name); client_callback = NULL; /* choose callback and do auth based on channel_name */ if(safe_str_eq(new_client->channel_name, cib_channel_callback)) { client_callback = cib_null_callback; } else { cl_uuid_t client_id; cl_uuid_generate(&client_id); crm_malloc0(new_client->id, sizeof(char)*36); cl_uuid_unparse(&client_id, new_client->id); new_client->id[35] = EOS; cl_uuid_generate(&client_id); crm_malloc0(new_client->callback_id, sizeof(char)*36); cl_uuid_unparse(&client_id, new_client->callback_id); new_client->callback_id[35] = EOS; client_callback = cib_ro_callback; if(safe_str_eq(new_client->channel_name, cib_channel_rw)) { client_callback = cib_rw_callback; } } } if(auth_failed) { crm_err("Connection to %s channel failed authentication", (char *)user_data); can_connect = FALSE; } if(can_connect == FALSE) { if(new_client) { crm_free(new_client->id); crm_free(new_client->callback_id); } crm_free(new_client); return FALSE; } channel->ops->set_recv_qlen(channel, 100); if(safe_str_eq(new_client->channel_name, cib_channel_callback)) { channel->ops->set_send_qlen(channel, 400); } else { channel->ops->set_send_qlen(channel, 100); } if(client_callback != NULL) { new_client->source = G_main_add_IPC_Channel( G_PRIORITY_LOW, channel, FALSE, client_callback, new_client, default_ipc_connection_destroy); } if(client_callback != cib_null_callback) { /* send msg to client with uuid to use when signing up for * callback channel */ HA_Message *reg_msg = ha_msg_new(3); ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); ha_msg_add(reg_msg, F_CIB_CLIENTID, new_client->id); ha_msg_add( reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id); send_ipc_message(channel, reg_msg); /* make sure we can find ourselves later for sync calls * redirected to the master instance */ g_hash_table_insert(client_list, new_client->id, new_client); } crm_debug_3("Channel %s connected for client %s", new_client->channel_name, new_client->id); return TRUE; } gboolean cib_rw_callback(IPC_Channel *channel, gpointer user_data) { return cib_common_callback(channel, user_data, TRUE); } gboolean cib_ro_callback(IPC_Channel *channel, gpointer user_data) { return cib_common_callback(channel, user_data, FALSE); } gboolean cib_null_callback(IPC_Channel *channel, gpointer user_data) { gboolean did_disconnect = TRUE; HA_Message *op_request = NULL; cib_client_t *cib_client = user_data; cib_client_t *hash_client = NULL; const char *type = NULL; const char *uuid_ticket = NULL; const char *client_name = NULL; gboolean register_failed = FALSE; if(cib_client == NULL) { crm_err("Discarding IPC message from unknown source" " on callback channel."); return FALSE; } while(channel->ops->is_message_pending(channel)) { if (channel->ch_status != IPC_CONNECT) { /* The message which was pending for us is that * the channel is no longer fully connected. * * Dont read requests from disconnected clients */ break; } op_request = msgfromIPC_noauth(channel); type = cl_get_string(op_request, F_CIB_OPERATION); if(safe_str_eq(type, T_CIB_NOTIFY) ) { /* Update the notify filters for this client */ int on_off = 0; ha_msg_value_int( op_request, F_CIB_NOTIFY_ACTIVATE, &on_off); type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE); if(safe_str_eq(type, T_CIB_POST_NOTIFY)) { cib_client->post_notify = on_off; } else if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) { cib_client->pre_notify = on_off; } else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) { cib_client->confirmations = on_off; } else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) { cib_client->diffs = on_off; } continue; } else if(safe_str_neq(type, CRM_OP_REGISTER) ) { crm_warn("Discarding IPC message from %s on callback channel", cib_client->id); crm_msg_del(op_request); continue; } uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN); client_name = cl_get_string(op_request, F_CIB_CLIENTNAME); CRM_DEV_ASSERT(uuid_ticket != NULL); if(crm_assert_failed) { register_failed = crm_assert_failed; } CRM_DEV_ASSERT(client_name != NULL); if(crm_assert_failed) { register_failed = crm_assert_failed; } if(register_failed == FALSE) { hash_client = g_hash_table_lookup(client_list, uuid_ticket); if(hash_client != NULL) { crm_err("Duplicate registration request..." " disconnecting"); register_failed = TRUE; } } if(register_failed) { crm_err("Registration request failed... disconnecting"); crm_msg_del(op_request); return FALSE; } cib_client->id = crm_strdup(uuid_ticket); cib_client->name = crm_strdup(client_name); g_hash_table_insert(client_list, cib_client->id, cib_client); crm_debug_2("Registered %s on %s channel", cib_client->id, cib_client->channel_name); crm_msg_del(op_request); op_request = ha_msg_new(2); ha_msg_add(op_request, F_CIB_OPERATION, CRM_OP_REGISTER); ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id); send_ipc_message(channel, op_request); } did_disconnect = cib_process_disconnect(channel, cib_client); if(did_disconnect) { crm_debug("Client disconnected"); } return did_disconnect; } gboolean cib_common_callback( IPC_Channel *channel, gpointer user_data, gboolean privileged) { int rc = cib_ok; int lpc = 0; - int call_type = 0; - int call_options = 0; - const char *op = NULL; - const char *host = NULL; - HA_Message *op_request = NULL; - HA_Message *op_reply = NULL; - - gboolean needs_processing = FALSE; cib_client_t *cib_client = user_data; if(cib_client == NULL) { crm_err("Receieved call from unknown source. Discarding."); return FALSE; } crm_debug_2("Callback for %s on %s channel", cib_client->id, cib_client->channel_name); while(channel->ops->is_message_pending(channel)) { if (channel->ch_status != IPC_CONNECT) { /* The message which was pending for us is that * the channel is no longer fully connected. * * Dont read requests from disconnected clients */ break; } op_request = msgfromIPC(channel, 0); if (op_request == NULL) { perror("Receive failure:"); break; } crm_debug_2("Processing IPC message from %s on %s channel", cib_client->id, cib_client->channel_name); crm_log_message(LOG_MSG, op_request); crm_log_message_adv(LOG_DEBUG_3, "Client[inbound]", op_request); lpc++; rc = cib_ok; - if(HA_OK != ha_msg_add( - op_request, F_CIB_CLIENTID, cib_client->id)) { - crm_err("Couldnt add F_CIB_CLIENTID to message"); - rc = cib_msg_field_add; - } + CRM_DEV_ASSERT( + ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id) == HA_OK); - if(rc == cib_ok) { - ha_msg_value_int( - op_request, F_CIB_CALLOPTS, &call_options); - crm_debug_3("Call options: %.8lx", (long)call_options); - - host = cl_get_string(op_request, F_CIB_HOST); - op = cl_get_string(op_request, F_CIB_OPERATION); - rc = cib_get_operation_id(op_request, &call_type); + if(crm_assert_failed == FALSE) { + cib_process_request( + op_request, privileged, FALSE, cib_client); } - if(rc == cib_ok - && cib_server_ops[call_type].needs_privileges - && privileged == FALSE) { - rc = cib_not_authorized; - } + crm_debug_3("Cleaning up request"); + crm_msg_del(op_request); + op_request = NULL; + } - needs_processing = FALSE; - if(rc != cib_ok) { - /* TODO: construct error reply */ - crm_err("Pre-processing of command failed: %s", - cib_error2string(rc)); - - } else if(host == NULL && cib_is_master - && !(call_options & cib_scope_local)) { - crm_debug_2("Processing master %s op locally", op); - needs_processing = TRUE; + crm_debug_2("Processed %d messages", lpc); - } else if( - (host == NULL && (call_options & cib_scope_local)) - || safe_str_eq(host, cib_our_uname)) { - crm_debug_2("Processing %s op locally", op); - needs_processing = TRUE; + return cib_process_disconnect(channel, cib_client); +} - } else { - /* send via HA to other nodes */ - ha_msg_add(op_request, F_CIB_DELEGATED, cib_our_uname); - crm_log_message(LOG_MSG, op_request); +void +cib_process_request(const HA_Message *request, gboolean privileged, + gboolean from_peer, cib_client_t *cib_client) +{ + int call_type = 0; + int call_options = 0; - if(host != NULL) { - crm_debug_2("Forwarding %s op to %s", op, host); - send_ha_message(hb_conn, op_request, host); + gboolean process = TRUE; + gboolean needs_reply = TRUE; + gboolean local_notify = FALSE; + gboolean needs_forward = FALSE; + crm_data_t *result_diff = NULL; + + enum cib_errors rc = cib_ok; + HA_Message *op_reply = NULL; + + const char *op = cl_get_string(request, F_CIB_OPERATION); + const char *originator = cl_get_string(request, F_ORIG); + const char *host = cl_get_string(request, F_CIB_HOST); + const char *reply_to = cl_get_string(request, F_CIB_ISREPLY); + const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE); + const char *delegated = cl_get_string(request, F_CIB_DELEGATED); + const char *client_id = NULL; - } else { - crm_debug_2("Forwarding %s op to master instance", - op); - send_ha_message(hb_conn, op_request, NULL); - } + crm_debug_4("%s Processing msg %s", + cib_our_uname, cl_get_string(request, F_SEQ)); - if(call_options & cib_discard_reply) { - crm_debug_2("Client not interested in reply"); - - } else if(call_options & cib_sync_call) { - /* keep track of the request so we can time it - * out if required - */ - HA_Message *saved = cib_msg_copy( - op_request, TRUE); - crm_debug_3("Registering delegated call from %s", - cib_client->id); - cib_client->delegated_calls = g_list_append( - cib_client->delegated_calls, saved); - } - crm_msg_del(op_request); - op_request = NULL; - continue; + if(host != NULL && strlen(host) == 0) { + host = NULL; + } + + ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options); + crm_debug_4("Retrieved call options: %d", call_options); + + crm_debug_2("Processing message from peer (%s) to %s...", + originator, host?host:"master"); + crm_log_message_adv(LOG_DEBUG_3, "Peer[inbound]", request); + + if(rc != cib_ok) { + /* TODO: construct error reply */ + crm_err("Pre-processing of command failed: %s", + cib_error2string(rc)); + + } else if(from_peer == FALSE) { + if(host == NULL && (call_options & cib_scope_local)) { + crm_debug("Processing locally scoped %s op from %s", + op, cib_client->name); + process = TRUE; + local_notify = TRUE; + + } else if(host == NULL && cib_is_master) { + crm_debug("Processing master %s op locally from %s", + op, cib_client->name); + process = TRUE; + local_notify = TRUE; + + } else if(safe_str_eq(host, cib_our_uname)) { + crm_debug("Processing locally addressed %s op from %s", + op, cib_client->name); + process = TRUE; + local_notify = TRUE; + } else { + crm_debug("%s op from %s needs to be forwarded to %s", + op, cib_client->name, + host?host:"the master instance"); + needs_forward = TRUE; } + + } else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) { + crm_debug("Processing global/peer update from %s" + " that originated from us", originator); + needs_reply = FALSE; + local_notify = TRUE; + + } else if(crm_is_true(update)) { + crm_debug("Processing global/peer update from %s", originator); + needs_reply = FALSE; + + } else if(host != NULL && safe_str_eq(host, cib_our_uname)) { + crm_debug("Processing request sent to us from %s", originator); - if(needs_processing) { - crm_debug("Performing local processing: op=%s origin=%s/%s,%s (update=%s)", - op, cib_our_uname, cib_client->id, - cl_get_string(op_request, F_CIB_CALLID), - (rc==cib_ok && cib_server_ops[call_type].modifies_cib)?"true":"false"); - rc = cib_process_command( - op_request, &op_reply, privileged); - if(rc == cib_ok && safe_str_eq(op, CRM_OP_CIB_SYNC)) { - HA_Message *sync_data = cl_get_struct( - op_reply, F_CIB_CALLDATA); - CRM_DEV_ASSERT(sync_data != NULL); - ha_msg_mod(op_request, - F_CIB_OPERATION, CRM_OP_CIB_REPLACE); - ha_msg_add(op_request, - F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); - cl_msg_modstruct( - op_request, F_CIB_CALLDATA, sync_data); - } - crm_debug_3("Processing complete"); + } else if(delegated != NULL && cib_is_master == TRUE) { + crm_debug("Processing request sent to master instance from %s", + originator); + + } else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) { + crm_debug("Forward reply sent from %s to local clients", + originator); + process = FALSE; + needs_reply = FALSE; + local_notify = TRUE; + + } else if(delegated != NULL) { + crm_debug_2("Ignoring msg for master instance"); + return; + + } else if(host != NULL) { + /* this is for a specific instance and we're not it */ + crm_debug_2("Ignoring msg for instance on %s", crm_str(host)); + return; + + } else if(reply_to == NULL && cib_is_master == FALSE) { + /* this is for the master instance and we're not it */ + crm_debug_2("Ignoring reply to %s", crm_str(reply_to)); + return; + + } else { + crm_warn("Nothing for us to do?"); + return; + } + crm_debug_3("Finished determining processing actions"); + + if(needs_forward) { + HA_Message *forward_msg = cib_msg_copy(request, TRUE); + ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname); + crm_log_message(LOG_MSG, forward_msg); + + if(host != NULL) { + crm_debug("Forwarding %s op to %s", op, host); + send_ha_message(hb_conn, forward_msg, host); + + } else { + crm_debug("Forwarding %s op to master instance", op); + send_ha_message(hb_conn, forward_msg, NULL); } - crm_debug_3("processing response cases"); - if(rc != cib_ok) { + if(call_options & cib_discard_reply) { + crm_debug_2("Client not interested in reply"); + crm_msg_del(forward_msg); + + } else if(call_options & cib_sync_call) { + /* keep track of the request so we can time it + * out if required + */ + crm_debug("Registering delegated call from %s", + cib_client->id); + cib_client->delegated_calls = g_list_append( + cib_client->delegated_calls, forward_msg); + } else { + crm_msg_del(forward_msg); + } + return; + } + + if(process) { + crm_debug_3("Performing local processing:" + " op=%s origin=%s/%s,%s (update=%s)", + cl_get_string(request, F_CIB_OPERATION), originator, + cl_get_string(request, F_CIB_CLIENTID), + cl_get_string(request, F_CIB_CALLID), update); + + rc = cib_process_command(request, &op_reply, &result_diff, TRUE); + crm_debug_3("Processing complete"); + + if(rc == cib_diff_resync || rc == cib_diff_failed) { + crm_warn("%s operation failed: %s", + crm_str(op), cib_error2string(rc)); + + } else if(rc != cib_ok) { crm_err("%s operation failed: %s", crm_str(op), cib_error2string(rc)); crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply); crm_debug("Input message"); - crm_log_message(LOG_DEBUG, op_request); + crm_log_message(LOG_DEBUG, request); + } + } + + crm_debug_3("processing response cases"); + + if(local_notify) { + /* send callback to originating child */ + cib_client_t *client_obj = NULL; + HA_Message *client_reply = NULL; + enum cib_errors local_rc = cib_ok; + crm_debug_4("find the client"); + + if(process == FALSE) { + client_reply = cib_msg_copy(request, TRUE); + } else { + client_reply = cib_msg_copy(op_reply, TRUE); } - if(op_reply == NULL) { - crm_debug_4("No reply is required for op %s",crm_str(op)); - - } else if(call_options & cib_sync_call) { - crm_debug_3("Sending sync reply to %s op", crm_str(op)); - crm_log_message(LOG_MSG, op_reply); - if(send_ipc_message(channel, op_reply) == FALSE) { - crm_err("Sync reply failed: %s", - cib_error2string(cib_reply_failed)); - } - + client_id = cl_get_string(request, F_CIB_CLIENTID); + if(client_id != NULL) { + client_obj = g_hash_table_lookup( + client_list, client_id); } else { - enum cib_errors local_rc = cib_ok; - /* send reply via client's callback channel */ - crm_debug_3("Sending async reply %p to %s op", - op_reply, crm_str(op)); - crm_log_message(LOG_MSG, op_reply); - local_rc = send_via_callback_channel( - op_reply, cib_client->callback_id); - if(local_rc != cib_ok) { - crm_warn("ASync reply failed: %s", - cib_error2string(local_rc)); - } + crm_err("No client to sent the response to." + " F_CIB_CLIENTID not set."); } + + crm_debug_3("Sending callback to request originator"); + if(client_obj != NULL) { + crm_debug("Sending %ssync response to %s %s", + (call_options & cib_sync_call)?"":"an a-", + client_obj->id, + from_peer?"(originator of delegated request)":""); - op_reply = NULL; - - crm_debug_3("Processing forward cases"); - if(rc == cib_ok && safe_str_eq(op, CRM_OP_CIB_SYNC)) { - const char *section = cl_get_string( - op_request, F_CIB_SECTION); - crm_info("Syncing section=%s to all instances", - section?section:""); - send_ha_message(hb_conn, op_request, NULL); - - } else if(rc == cib_ok - && cib_server_ops[call_type].modifies_cib - && !(call_options & cib_inhibit_bcast)) { - /* send via HA to other nodes */ - crm_debug_2("Forwarding %s op to all instances", op); - ha_msg_add(op_request, - F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); - send_ha_message(hb_conn, op_request, NULL); + if(call_options & cib_sync_call) { + send_via_callback_channel( + client_reply, client_obj->id); + + } else { + send_via_callback_channel( + client_reply, client_obj->callback_id); + } } else { - if(call_options & cib_inhibit_bcast ) { - crm_debug_3("Request not broadcast: inhibited"); - } - if(cib_server_ops[call_type].modifies_cib == FALSE) { - crm_debug_3("Request not broadcast: R/O call"); - } - if(rc != cib_ok) { - crm_err("Request not broadcast:" - " call failed: %s", - cib_error2string(rc)); - } + crm_warn("Client %s may have left us", + crm_str(client_id)); + crm_msg_del(client_reply); + } + if(local_rc != cib_ok) { + crm_warn("%sSync reply failed: %s", + (call_options & cib_sync_call)?"":"A-", + cib_error2string(local_rc)); + crm_log_message(LOG_DEBUG, op_reply); } + } - crm_debug_3("Cleaning up request"); - crm_msg_del(op_request); - op_request = NULL; + if(needs_reply == FALSE) { + /* nothing more to do... + * this was a non-originating slave update + */ + crm_debug_3("Completed slave update"); + crm_msg_del(op_reply); + free_xml(result_diff); + return; } + + crm_debug_4("add the originator to message"); - crm_debug_2("Processed %d messages", lpc); - - return cib_process_disconnect(channel, cib_client); + rc = cib_get_operation_id(request, &call_type); + + /* from now on we are the server */ + if(rc == cib_ok + && cib_server_ops[call_type].modifies_cib + && !(call_options & cib_inhibit_bcast)) { + /* this (successful) call modified the CIB _and_ the + * change needs to be broadcast... + * send via HA to other nodes + */ + HA_Message *op_bcast = cib_msg_copy(request, FALSE); + crm_debug("Sending update diff to everyone"); + ha_msg_add(op_bcast, F_CIB_ISREPLY, originator); + ha_msg_add(op_bcast, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); + ha_msg_mod(op_bcast, F_CIB_OPERATION, CIB_OP_APPLY_DIFF); + add_message_xml(op_bcast, F_CIB_UPDATE_DIFF, result_diff); + + crm_log_message(LOG_DEBUG_3, op_bcast); + send_ha_message(hb_conn, op_bcast, NULL); + crm_msg_del(op_bcast); + + } else { + if(from_peer && originator != NULL) { + /* send reply via HA to originating node */ + crm_debug("Sending request result to originator only"); + ha_msg_add(op_reply, F_CIB_ISREPLY, originator); + send_ha_message(hb_conn, op_reply, originator); + } + if(call_options & cib_inhibit_bcast ) { + crm_debug("Request not broadcast: inhibited"); + } + if(cib_server_ops[call_type].modifies_cib == FALSE) { + crm_debug("Request not broadcast: R/O call"); + } + if(rc != cib_ok) { + crm_err("Request not broadcast: call failed: %s", + cib_error2string(rc)); + } + } + + crm_msg_del(op_reply); + free_xml(result_diff); + + return; } enum cib_errors -cib_process_command( - const HA_Message *request, HA_Message **reply, gboolean privileged) +cib_process_command(const HA_Message *request, HA_Message **reply, + crm_data_t **cib_diff, gboolean privileged) { crm_data_t *output = NULL; crm_data_t *input = NULL; + crm_data_t *input_fragment = NULL; + crm_data_t *current_cib = the_cib; + crm_data_t *result_cib = NULL; + crm_data_t *local_diff = NULL; + int call_type = 0; int call_options = 0; enum cib_errors rc = cib_ok; const char *op = NULL; const char *call_id = NULL; const char *section = NULL; const char *tmp = NULL; + gboolean global_update = crm_is_true( + cl_get_string(request, F_CIB_GLOBAL_UPDATE)); CRM_DEV_ASSERT(reply != NULL); if(reply) { *reply = NULL; } /* Start processing the request... */ op = cl_get_string(request, F_CIB_OPERATION); call_id = cl_get_string(request, F_CIB_CALLID); ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options); crm_debug_4("Processing call id: %s", call_id); rc = cib_get_operation_id(request, &call_type); if(rc == cib_ok && cib_server_ops[call_type].needs_privileges && privileged == FALSE) { /* abort */ rc = cib_not_authorized; } if(rc == cib_ok + && global_update == FALSE && cib_server_ops[call_type].needs_quorum && can_write(call_options) == FALSE) { rc = cib_no_quorum; } + /* prevent NUMUPDATES from being incrimented - apply the change as-is */ + if(global_update) { + call_options |= cib_inhibit_bcast; + } + if(rc == cib_ok && cib_server_ops[call_type].needs_section) { section = cl_get_string(request, F_CIB_SECTION); - crm_debug_4("Unpacked section as: %s", section); } - if(rc == cib_ok && cib_server_ops[call_type].needs_data) { + if(rc == cib_ok && safe_str_eq(op, CIB_OP_APPLY_DIFF)) { + crm_debug_4("Unpacking diff data in %s", F_CIB_UPDATE_DIFF); + input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF); + input = input_fragment; + if(global_update) { + call_options |= cib_force_diff; + } + + } else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC)) { + input_fragment = ha_msg_copy(request); + input = input_fragment; + + } else if(rc == cib_ok && cib_server_ops[call_type].needs_data) { crm_debug_4("Unpacking data in %s", F_CIB_CALLDATA); - input = get_message_xml(request, F_CIB_CALLDATA); - } + input_fragment = get_message_xml(request, F_CIB_CALLDATA); + input = find_xml_node(input_fragment, XML_TAG_CIB, TRUE); + rc = revision_check(input, current_cib, call_options); + if(rc == cib_ok) { + input = get_object_root(section, input); + } + } + + if(cib_server_ops[call_type].modifies_cib) { + cib_pre_notify( + call_options, op, + get_object_root(section, current_cib), input); + } if(rc == cib_ok) { rc = cib_server_ops[call_type].fn( - op, call_options, section, input, &output); + op, call_options, section, input, + current_cib, &result_cib, &output); } + + if(cib_server_ops[call_type].modifies_cib) { + if(safe_str_eq(op, CIB_OP_APPLY_DIFF)) { + local_diff = copy_xml(input); + } else if(result_cib != NULL && current_cib != result_cib) { + local_diff = diff_cib_object( + current_cib, result_cib, FALSE); + } + if(rc != cib_ok) { + free_xml(result_cib); + + } else if(activateCibXml(result_cib,CIB_FILENAME) < 0){ + crm_warn("Activation failed"); + rc = cib_ACTIVATION; + } + cib_post_notify(call_options, op, input, rc, the_cib); + cib_diff_notify(call_options, op, input, rc, local_diff); + + } else if(result_cib != NULL) { + crm_err("%s call modified the CIB", op); + free_xml(result_cib); + } + + crm_debug_4("Processing reply cases"); if(call_options & cib_discard_reply) { crm_debug_3("No reply needed for call %s", call_id); return rc; } else if(reply == NULL) { crm_debug("No reply possible for call %s", call_id); return rc; } crm_debug_4("Creating a basic reply"); *reply = ha_msg_new(8); ha_msg_add(*reply, F_TYPE, T_CIB); ha_msg_add(*reply, F_CIB_OPERATION, op); ha_msg_add(*reply, F_CIB_CALLID, call_id); ha_msg_add_int(*reply, F_CIB_RC, rc); tmp = cl_get_string(request, F_CIB_CLIENTID); ha_msg_add(*reply, F_CIB_CLIENTID, tmp); tmp = cl_get_string(request, F_CIB_CALLOPTS); ha_msg_add(*reply, F_CIB_CALLOPTS, tmp); crm_debug_4("Attaching output if necessary"); if(output != NULL) { add_message_xml(*reply, F_CIB_CALLDATA, output); } else { crm_debug_3("No output for call %s", call_id); } crm_debug_4("Cleaning up"); + if(cib_diff != NULL) { + *cib_diff = local_diff; + } else { + free_xml(local_diff); + } free_xml(output); - free_xml(input); + free_xml(input_fragment); return rc; } int send_via_callback_channel(HA_Message *msg, const char *token) { cib_client_t *hash_client = NULL; GList *list_item = NULL; enum cib_errors rc = cib_ok; crm_debug_3("Delivering msg %p to client %s", msg, token); if(token == NULL) { crm_err("No client id token, cant send message"); if(rc == cib_ok) { rc = cib_missing; } } else { /* A client that left before we could reply is not really * _our_ error. Warn instead. */ hash_client = g_hash_table_lookup(client_list, token); if(hash_client == NULL) { crm_warn("Cannot find client for token %s", token); rc = cib_client_gone; } else if(hash_client->channel == NULL) { crm_err("Cannot find channel for client %s", token); rc = cib_client_corrupt; } else if(hash_client->channel->ops->get_chan_status( hash_client->channel) != IPC_CONNECT) { crm_warn("Client %s has disconnected", token); rc = cib_client_gone; } } /* this is a more important error so overwriting rc is warrented */ if(msg == NULL) { crm_err("No message to send"); rc = cib_reply_failed; } if(rc == cib_ok) { list_item = g_list_find_custom( hash_client->delegated_calls, msg, cib_GCompareFunc); } if(list_item != NULL) { /* remove it - no need to time it out */ HA_Message *orig_msg = list_item->data; crm_debug_3("Removing msg from delegated list"); hash_client->delegated_calls = g_list_remove( hash_client->delegated_calls, orig_msg); CRM_DEV_ASSERT(orig_msg != msg); crm_msg_del(orig_msg); } if(rc == cib_ok) { crm_debug_3("Delivering reply to client %s", token); if(send_ipc_message(hash_client->channel, msg) == FALSE) { crm_warn("Delivery of reply to client %s/%s failed", hash_client->name, token); rc = cib_reply_failed; } } else { /* be consistent... * send_ipc_message() will free the message, so we should do * so manually if we dont try to send it. */ crm_msg_del(msg); } return rc; } gint cib_GCompareFunc(gconstpointer a, gconstpointer b) { const HA_Message *a_msg = a; const HA_Message *b_msg = b; int msg_a_id = 0; int msg_b_id = 0; ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id); ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id); if(msg_a_id == msg_b_id) { return 0; } else if(msg_a_id < msg_b_id) { return -1; } return 1; } gboolean cib_msg_timeout(gpointer data) { crm_debug_4("Checking if any clients have timed out messages"); g_hash_table_foreach(client_list, cib_GHFunc, NULL); return TRUE; } void cib_GHFunc(gpointer key, gpointer value, gpointer user_data) { cib_client_t *client = value; GListPtr list = client->delegated_calls; HA_Message *msg = NULL; while(list != NULL) { int seen = 0; int timeout = 5; /* 1 iteration == 1 seconds */ HA_Message *reply = NULL; const char *host_to = NULL; msg = list->data; ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen); ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout); host_to = cl_get_string(msg, F_CIB_HOST); crm_debug_4("Timeout %d, seen %d", timeout, seen); if(timeout > 0 && seen < timeout) { int seen2 = 0; crm_debug_4("Updating seen count for msg from client %s", client->id); seen++; ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen); ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen2); list = list->next; continue; } crm_warn("Sending operation timeout msg to client %s", client->id); reply = ha_msg_new(4); ha_msg_add(reply, F_TYPE, T_CIB); ha_msg_add(reply, F_CIB_OPERATION, cl_get_string(msg, F_CIB_OPERATION)); ha_msg_add(reply, F_CIB_CALLID, cl_get_string(msg, F_CIB_CALLID)); if(host_to == NULL) { ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout); } else { ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout); } send_ipc_message(client->channel, reply); list = list->next; client->delegated_calls = g_list_remove( client->delegated_calls, msg); crm_msg_del(msg); } } gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client) { if (channel->ch_status != IPC_CONNECT && cib_client != NULL) { crm_info("Cleaning up after %s channel disconnect from client (%p) %s/%s", cib_client->channel_name, cib_client, crm_str(cib_client->id), crm_str(cib_client->name)); if(cib_client->id != NULL) { g_hash_table_remove(client_list, cib_client->id); } if(cib_client->source != NULL) { crm_debug_3("deleting the IPC Channel"); G_main_del_IPC_Channel(cib_client->source); cib_client->source = NULL; } crm_debug_3("Freeing the cib client %s", crm_str(cib_client->id)); #if 0 /* todo - put this back in once i recheck its safe */ crm_free(cib_client->callback_id); crm_free(cib_client->name); crm_free(cib_client->id); #endif crm_free(cib_client); crm_debug_3("Freed the cib client"); return FALSE; } else if (channel->ch_status != IPC_CONNECT) { crm_warn("Unknown client disconnected"); return FALSE; } return TRUE; } gboolean cib_ha_dispatch(IPC_Channel *channel, gpointer user_data) { int lpc = 0; ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data; while(lpc < 2 && hb_cluster->llc_ops->msgready(hb_cluster)) { lpc++; /* invoke the callbacks but dont block */ hb_cluster->llc_ops->rcvmsg(hb_cluster, 0); } crm_debug_4("%d HA messages dispatched", lpc); if (channel && (channel->ch_status != IPC_CONNECT)) { crm_crit("Lost connection to heartbeat service... exiting"); exit(100); return FALSE; } return TRUE; } void cib_peer_callback(const HA_Message * msg, void* private_data) { - int is_done = 1; - int call_type = 0; - int call_options = 0; - - gboolean process = TRUE; - gboolean needs_reply = TRUE; - gboolean local_notify = FALSE; - - enum cib_errors rc = cib_ok; - HA_Message *op_reply = NULL; - HA_Message *replace_request = NULL; - - const char *op = cl_get_string(msg, F_CIB_OPERATION); + int call_type = 0; const char *originator = cl_get_string(msg, F_ORIG); - const char *request_to = cl_get_string(msg, F_CIB_HOST); - const char *reply_to = cl_get_string(msg, F_CIB_ISREPLY); - const char *update = cl_get_string(msg, F_CIB_GLOBAL_UPDATE); - const char *delegated = cl_get_string(msg, F_CIB_DELEGATED); - const char *client_id = NULL; if(originator == NULL || safe_str_eq(originator, cib_our_uname)) { crm_debug_3("Discarding message %s/%s from ourselves", cl_get_string(msg, F_CIB_CLIENTID), cl_get_string(msg, F_CIB_CALLID)); return; } else if(ccm_membership == NULL) { crm_debug_3("Discarding message %s/%s: membership not established", originator, cl_get_string(msg, F_SEQ)); return; } else if(g_hash_table_lookup(ccm_membership, originator) == NULL) { crm_debug_3("Discarding message %s/%s: not in our membership", originator, cl_get_string(msg, F_CIB_CALLID)); return; } else if(cib_get_operation_id(msg, &call_type) != cib_ok) { crm_err("Invalid operation... discarding msg %s", cl_get_string(msg, F_SEQ)); return; } crm_debug_4("%s Processing msg %s", cib_our_uname, cl_get_string(msg, F_SEQ)); - if(request_to != NULL && strlen(request_to) == 0) { - request_to = NULL; - } - - if(cib_server_ops[call_type].modifies_cib || request_to != NULL - || (reply_to == NULL && cib_is_master)) { - is_done = 0; - } - - crm_debug_2("Processing message from peer (%s) to %s...", - originator, request_to?request_to:"master"); - crm_log_message_adv(LOG_DEBUG_3, "Peer[inbound]", msg); - - if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) { - crm_debug("Processing global/peer update from %s" - " that originated from us", originator); - needs_reply = FALSE; - local_notify = TRUE; - - } else if(crm_is_true(update)) { - crm_debug("Processing global/peer update from %s", originator); - needs_reply = FALSE; - - } else if(request_to != NULL - && safe_str_eq(request_to, cib_our_uname)) { - crm_debug("Processing request sent to us from %s", originator); - - } else if(delegated != NULL && cib_is_master == TRUE) { - crm_debug("Processing request sent to master instance from %s", - originator); - - } else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) { - crm_debug("Forward reply sent from %s to local clients", - originator); - process = FALSE; - needs_reply = FALSE; - local_notify = TRUE; - - } else if(delegated != NULL) { - crm_debug_2("Ignoring msg for master instance"); - return; - - } else if(request_to != NULL) { - /* this is for a specific instance and we're not it */ - crm_debug_2("Ignoring msg for instance on %s", - crm_str(request_to)); - return; - - } else if(reply_to == NULL && cib_is_master == FALSE) { - /* this is for the master instance and we're not it */ - crm_debug_2("Ignoring reply to %s", crm_str(reply_to)); - return; - - } else { - crm_warn("Nothing for us to do?"); - return; - } - crm_debug_3("Finished determining processing actions"); - - ha_msg_value_int(msg, F_CIB_CALLOPTS, &call_options); - crm_debug_4("Retrieved call options: %d", call_options); - - if(process) { - crm_debug_3("Performing local processing: op=%s origin=%s/%s,%s (update=%s)", - cl_get_string(msg, F_CIB_OPERATION), - originator, - cl_get_string(msg, F_CIB_CLIENTID), - cl_get_string(msg, F_CIB_CALLID), - update); - rc = cib_process_command(msg, &op_reply, TRUE); - if(rc == cib_ok && safe_str_eq(op, CRM_OP_CIB_SYNC)) { - HA_Message *sync_data = cl_get_struct( - op_reply, F_CIB_CALLDATA); - CRM_DEV_ASSERT(sync_data != NULL); - - replace_request = cib_msg_copy(msg, TRUE); - ha_msg_mod(replace_request, - F_CIB_OPERATION, CRM_OP_CIB_REPLACE); - ha_msg_add(replace_request, - F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); - ha_msg_add(replace_request, F_CIB_ISREPLY, originator); - ha_msg_addstruct( - replace_request, F_CIB_CALLDATA, sync_data); - } - } - - if(local_notify) { - /* send callback to originating child */ - cib_client_t *client_obj = NULL; - HA_Message *client_reply = NULL; - crm_debug_4("find the client"); - - if(process == FALSE) { - client_reply = cib_msg_copy(msg, TRUE); - } else { - client_reply = cib_msg_copy(op_reply, TRUE); - } - - client_id = cl_get_string(msg, F_CIB_CLIENTID); - if(client_id != NULL) { - client_obj = g_hash_table_lookup( - client_list, client_id); - } else { - crm_err("No client to sent the response to." - " F_CIB_CLIENTID not set."); - } - - crm_debug_3("Sending callback to originator of delegated request"); - if(client_obj != NULL) { - crm_debug("Sending %ssync response to %s" - " (originator of delegated request)", - (call_options & cib_sync_call)?"":"an a-", - client_obj->id); - - if(is_done == 0) { - crm_debug_3("Sending local modify response"); - - } else { - crm_debug_3("Sending master response"); - } - if(call_options & cib_sync_call) { - send_via_callback_channel( - client_reply, client_obj->id); - - } else { - send_via_callback_channel( - client_reply, client_obj->callback_id); - } - - } else { - crm_warn("Client %s may have left us", - crm_str(client_id)); - crm_msg_del(client_reply); - } - } - - if(needs_reply == FALSE) { - /* nothing more to do... - * this was a non-originating slave update - */ - crm_debug_3("Completed slave update"); - crm_msg_del(op_reply); - return; - } - - crm_debug_4("add the originator to message"); - - /* from now on we are the server */ - if(rc == cib_ok && safe_str_eq(op, CRM_OP_CIB_SYNC)) { - const char *section = cl_get_string( - replace_request, F_CIB_SECTION); - crm_info("Syncing section=%s to all instances", - section?section:""); - CRM_DEV_ASSERT(replace_request != NULL); - send_ha_message(hb_conn, replace_request, NULL); - ha_msg_del(replace_request); - - } else if(rc == cib_ok && cib_server_ops[call_type].modifies_cib - && !(call_options & cib_scope_local)) { - /* this (successful) call modified the CIB _and_ the - * change needs to be broadcast... - * send via HA to other nodes - */ - HA_Message *op_bcast = cib_msg_copy(msg, TRUE); - crm_debug_3("Sending update request to everyone"); - ha_msg_add(op_bcast, F_CIB_ISREPLY, originator); - ha_msg_add(op_bcast, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); - crm_log_message(LOG_DEBUG_3, op_bcast); - send_ha_message(hb_conn, op_bcast, NULL); - crm_msg_del(op_bcast); - - } else { - /* send reply via HA to originating node */ - crm_debug_3("Sending request result to originator only"); - ha_msg_add(op_reply, F_CIB_ISREPLY, originator); - send_ha_message(hb_conn, op_reply, originator); - } - crm_msg_del(op_reply); + cib_process_request(msg, TRUE, TRUE, NULL); return; } HA_Message * cib_msg_copy(const HA_Message *msg, gboolean with_data) { int lpc = 0; const char *field = NULL; const char *value = NULL; const HA_Message *value_struct = NULL; const char *field_list[] = { F_TYPE , F_CIB_CLIENTID , F_CIB_CALLOPTS , F_CIB_CALLID , F_CIB_OPERATION , F_CIB_ISREPLY , F_CIB_SECTION , F_CIB_HOST , F_CIB_RC , F_CIB_DELEGATED , F_CIB_OBJID , F_CIB_OBJTYPE , F_CIB_EXISTING , F_CIB_SEENCOUNT , F_CIB_TIMEOUT , F_CIB_CALLBACK_TOKEN , F_CIB_GLOBAL_UPDATE , F_CIB_CLIENTNAME , F_CIB_NOTIFY_TYPE , F_CIB_NOTIFY_ACTIVATE }; const char *data_list[] = { F_CIB_CALLDATA , F_CIB_UPDATE , F_CIB_UPDATE_RESULT }; HA_Message *copy = ha_msg_new(10); if(copy == NULL) { return copy; } for(lpc = 0; lpc < DIMOF(field_list); lpc++) { field = field_list[lpc]; value = cl_get_string(msg, field); if(value != NULL) { ha_msg_add(copy, field, value); } } for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) { field = data_list[lpc]; value_struct = cl_get_struct(msg, field); if(value_struct != NULL) { ha_msg_addstruct(copy, field, value_struct); } } return copy; } enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation) { int lpc = 0; int max_msg_types = DIMOF(cib_server_ops); const char *op = cl_get_string(msg, F_CIB_OPERATION); for (lpc = 0; lpc < max_msg_types; lpc++) { if (safe_str_eq(op, cib_server_ops[lpc].operation)) { *operation = lpc; return cib_ok; } } crm_err("Operation %s is not valid", op); *operation = -1; return cib_operation; } void cib_client_status_callback(const char * node, const char * client, const char * status, void * private) { if(safe_str_eq(client, CRM_SYSTEM_CIB)) { crm_debug_2("Status update: Client %s/%s now has status [%s]", node, client, status); g_hash_table_replace(peer_hash, crm_strdup(node), crm_strdup(status)); set_connected_peers(the_cib); } return; } extern oc_ev_t *cib_ev_token; gboolean ccm_manual_check(gpointer data) { int rc = 0; oc_ev_t *ccm_token = cib_ev_token; crm_debug("manual check"); rc = oc_ev_handle_event(ccm_token); if(0 == rc) { return TRUE; } else { crm_err("CCM connection appears to have failed: rc=%d.", rc); return FALSE; } } gboolean cib_ccm_dispatch(int fd, gpointer user_data) { int rc = 0; oc_ev_t *ccm_token = (oc_ev_t*)user_data; crm_debug("received callback"); rc = oc_ev_handle_event(ccm_token); if(0 == rc) { return TRUE; } else { crm_err("CCM connection appears to have failed: rc=%d.", rc); return FALSE; } } void cib_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data) { int instance = -1; gboolean update_id = FALSE; gboolean update_quorum = FALSE; const oc_ev_membership_t *membership = data; if(membership != NULL) { instance = membership->m_instance; } crm_info("Process CCM event=%s (id=%d)", ccm_event_name(event), instance); switch(event) { case OC_EV_MS_NEW_MEMBERSHIP: case OC_EV_MS_INVALID: update_id = TRUE; update_quorum = TRUE; break; case OC_EV_MS_PRIMARY_RESTORED: update_id = TRUE; break; case OC_EV_MS_NOT_PRIMARY: crm_debug("Ignoring transitional CCM event: %s", ccm_event_name(event)); break; case OC_EV_MS_EVICTED: crm_err("Evicted from CCM: %s", ccm_event_name(event)); update_quorum = TRUE; break; default: crm_err("Unknown CCM event: %d", event); } if(update_id) { CRM_DEV_ASSERT(membership != NULL); if(crm_assert_failed) { return; } if(ccm_transition_id != NULL) { crm_free(ccm_transition_id); ccm_transition_id = NULL; } ccm_transition_id = crm_itoa(instance); set_transition(the_cib); } if(update_quorum) { int members = 0; int offset = 0; unsigned lpc = 0; cib_have_quorum = ccm_have_quorum(event); if(cib_have_quorum) { set_xml_property_copy( the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE); } else { set_xml_property_copy( the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE); } crm_info("Quorum %s after event=%s (id=%d)", cib_have_quorum?"(re)attained":"lost", ccm_event_name(event), instance); if(ccm_membership != NULL) { g_hash_table_foreach_remove( ccm_membership, ghash_str_clfree, NULL); } ccm_membership = g_hash_table_new(g_str_hash, g_str_equal); if(membership != NULL) { members = membership->m_n_member; offset = membership->m_memb_idx; } for(lpc = 0; lpc < members; lpc++) { oc_node_t a_node = membership->m_array[lpc+offset]; char *uname = crm_strdup(a_node.node_uname); g_hash_table_insert( ccm_membership, uname, uname); } } oc_ev_callback_done(cookie); return; } gboolean ghash_str_clfree(gpointer key, gpointer value, gpointer user_data) { if(key != NULL) { crm_free(key); } return TRUE; } gboolean can_write(int flags) { const char *value = NULL; if(cib_have_quorum) { return TRUE; } value = get_crm_option(the_cib, "no_quorum_policy", TRUE); if(safe_str_eq(value, "ignore")) { return TRUE; } if((flags & cib_quorum_override) != 0) { crm_debug("Overriding \"no quorum\" condition"); return TRUE; } return FALSE; } + diff --git a/crm/cib/callbacks.h b/crm/cib/callbacks.h index 1d9a4e499c..d12b0584f7 100644 --- a/crm/cib/callbacks.h +++ b/crm/cib/callbacks.h @@ -1,86 +1,87 @@ -/* $Id: callbacks.h,v 1.9 2005/05/31 11:32:39 andrew Exp $ */ +/* $Id: callbacks.h,v 1.10 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include /* #include */ #include #include #include extern gboolean cib_is_master; extern gboolean cib_have_quorum; extern GHashTable *client_list; extern GHashTable *peer_hash; typedef struct cib_client_s { char *id; char *name; char *callback_id; const char *channel_name; IPC_Channel *channel; GCHSource *source; int pre_notify; int post_notify; int confirmations; int diffs; GList *delegated_calls; } cib_client_t; typedef struct cib_operation_s { const char* operation; gboolean modifies_cib; gboolean needs_privileges; gboolean needs_quorum; gboolean needs_section; gboolean needs_data; enum cib_errors (*fn)( - const char *, int, const char *, crm_data_t*, crm_data_t**); + const char *, int, const char *, + crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**); } cib_operation_t; extern cib_operation_t cib_server_ops[]; extern gboolean cib_client_connect(IPC_Channel *channel, gpointer user_data); extern gboolean cib_null_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_rw_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_ro_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_ha_dispatch (IPC_Channel *channel, gpointer user_data); extern void cib_peer_callback(const HA_Message * msg, void* private_data); extern void cib_client_status_callback(const char * node, const char * client, const char * status, void * private); extern gboolean cib_ccm_dispatch(int fd, gpointer user_data); extern void cib_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data); diff --git a/crm/cib/cibmessages.h b/crm/cib/cibmessages.h index 91ef54bf28..682c16c734 100644 --- a/crm/cib/cibmessages.h +++ b/crm/cib/cibmessages.h @@ -1,64 +1,75 @@ -/* $Id: cibmessages.h,v 1.6 2005/01/26 13:30:55 andrew Exp $ */ +/* $Id: cibmessages.h,v 1.7 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CIB_MESSAGES__H #define CIB_MESSAGES__H extern crm_data_t *createCibRequest( gboolean isLocal, const char *operation, const char *section, const char *verbose, crm_data_t *data); extern enum cib_errors cib_process_default( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_quit( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_ping( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_query( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_erase( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_bump( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_replace( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_modify( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); extern enum cib_errors cib_process_readwrite( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer); + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); +extern enum cib_errors cib_process_diff( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); + +extern enum cib_errors cib_process_sync( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); + +extern enum cib_errors cib_process_sync_one( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer); #endif diff --git a/crm/cib/cibmon.c b/crm/cib/cibmon.c index fd98e6ea3e..963c2675aa 100644 --- a/crm/cib/cibmon.c +++ b/crm/cib/cibmon.c @@ -1,485 +1,461 @@ -/* $Id: cibmon.c,v 1.22 2005/05/31 11:32:39 andrew Exp $ */ +/* $Id: cibmon.c,v 1.23 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* someone complaining about _ha_msg_mod not being found */ #include #define UPDATE_PREFIX "cib.updates:" int exit_code = cib_ok; int got_signal = 0; GMainLoop *mainloop = NULL; const char *crm_system_name = "cibmon"; void usage(const char *cmd, int exit_status); void cib_connection_destroy(gpointer user_data); void cibmon_pre_notify(const char *event, HA_Message *msg); void cibmon_update_confirm(const char *event, HA_Message *msg); gboolean cibmon_shutdown(int nsig, gpointer unused); void cibmon_diff(const char *event, HA_Message *msg); cib_t *the_cib = NULL; #define OPTARGS "V?pPdam:" gboolean pre_notify = FALSE; gboolean post_notify = FALSE; gboolean log_diffs = FALSE; int max_failures = 30; int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; int level = 0; int attempts = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"pre", 0, 0, 'p'}, {"post", 0, 0, 'P'}, {"all", 0, 0, 'a'}, {"diffs", 0, 0, 'd'}, {"max-conn-fail",1, 0, 'm'}, {0, 0, 0, 0} }; crm_log_init(crm_system_name); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cibmon_shutdown, NULL, NULL); cl_set_corerootdir(HA_COREDIR); cl_cdtocoredir(); while (1) { flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); printf("Long option (--%s) is not" " (yet?) properly supported\n", long_options[option_index].name); ++argerr; break; case 'V': level = get_crm_log_level(); cl_log_enable_stderr(TRUE); set_crm_log_level(level+1); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'm': max_failures = crm_atoi(optarg, "30"); break; case 'a': pre_notify = TRUE; post_notify = TRUE; log_diffs = TRUE; break; case 'd': log_diffs = TRUE; break; case 'p': pre_notify = TRUE; break; case 'P': post_notify = TRUE; break; default: printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } the_cib = cib_new(); do { if(attempts != 0) { sleep(1); } exit_code = the_cib->cmds->signon( the_cib, crm_system_name, cib_query); } while(exit_code == cib_connection && attempts++ < max_failures); if(exit_code != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(exit_code)); } if(exit_code == cib_ok) { crm_debug("Setting dnotify"); exit_code = the_cib->cmds->set_connection_dnotify( the_cib, cib_connection_destroy); } if(exit_code == cib_ok && pre_notify) { crm_debug("Setting pre-notify callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_PRE_NOTIFY, cibmon_pre_notify); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_PRE_NOTIFY, cib_error2string(exit_code)); } } if(exit_code == cib_ok && post_notify) { crm_debug("Setting post-notify callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_UPDATE_CONFIRM, cibmon_update_confirm); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_UPDATE_CONFIRM, cib_error2string(exit_code)); } } if(exit_code == cib_ok && log_diffs) { crm_debug("Setting diff callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_DIFF_NOTIFY, cibmon_diff); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_DIFF_NOTIFY, cib_error2string(exit_code)); } } if(exit_code != cib_ok) { crm_err("Setup failed, could not monitor CIB actions"); return -exit_code; } mainloop = g_main_new(FALSE); crm_info("Starting mainloop"); g_main_run(mainloop); crm_debug_3("%s exiting normally", crm_system_name); fflush(stderr); return -exit_code; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; #if 0 fprintf(stream, "usage: %s [-?Vio] command\n" "\twhere necessary, XML data will be expected using -X" " or on STDIN if -X isnt specified\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); fprintf(stream, "\t--%s (-%c)\tturn on debug info." " additional instance increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ERASE, 'E'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_QUERY, 'Q'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_CREATE, 'C'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_REPLACE,'R'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_UPDATE, 'U'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_DELETE, 'D'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_BUMP, 'B'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ISMASTER,'M'); - fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_SYNC, 'S'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \t\n", F_CRM_DATA, 'X'); fprintf(stream, "\nAdvanced Options\n"); fprintf(stream, "\t--%s (-%c)\tsend command to specified host." " Applies to %s and %s commands only\n", "host", 'h', - CRM_OP_CIB_QUERY, CRM_OP_CIB_SYNC); + CIB_OP_QUERY, CRM_OP_CIB_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand only takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); #endif fflush(stream); exit(exit_status); } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } int update_depth = 0; gboolean last_notify_pre = TRUE; void cibmon_pre_notify(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; const char *id = NULL; const char *type = NULL; crm_data_t *update = NULL; crm_data_t *pre_update = NULL; if(msg == NULL) { crm_err("NULL update"); return; } op = cl_get_string(msg, F_CIB_OPERATION); id = cl_get_string(msg, F_CIB_OBJID); type = cl_get_string(msg, F_CIB_OBJTYPE); ha_msg_value_int(msg, F_CIB_RC, &rc); update_depth++; last_notify_pre = TRUE; update = get_message_xml(msg, F_CIB_UPDATE); pre_update = get_message_xml(msg, F_CIB_EXISTING); if(update != NULL) { crm_debug_3(UPDATE_PREFIX"[%s] Performing %s on <%s%s%s>", event, op, type, id?" id=":"", id?id:""); print_xml_formatted(LOG_DEBUG_5, UPDATE_PREFIX, update, "Update"); } else if(update == NULL) { crm_info(UPDATE_PREFIX"[%s] Performing operation %s (on section=%s)", event, op, crm_str(type)); } print_xml_formatted(LOG_DEBUG_3, UPDATE_PREFIX, pre_update, "Existing Object"); free_xml(update); free_xml(pre_update); } void cibmon_update_confirm(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; const char *id = NULL; const char *type = NULL; crm_data_t *update = NULL; crm_data_t *output = NULL; crm_data_t *generation = NULL; if(msg == NULL) { crm_err("NULL update"); return; } op = cl_get_string(msg, F_CIB_OPERATION); id = cl_get_string(msg, F_CIB_OBJID); type = cl_get_string(msg, F_CIB_OBJTYPE); update_depth--; last_notify_pre = FALSE; ha_msg_value_int(msg, F_CIB_RC, &rc); update = get_message_xml(msg, F_CIB_UPDATE); output = get_message_xml(msg, F_CIB_UPDATE_RESULT); generation = get_message_xml(msg, "cib_generation"); if(update == NULL) { if(rc == cib_ok) { crm_debug_2(UPDATE_PREFIX"[%s] %s (to %s) confirmed", event, op, crm_str(type)); } else { crm_warn(UPDATE_PREFIX"[%s] %s (to %s) ABORTED: (%d) %s", event, op, crm_str(type), rc, cib_error2string(rc)); } } else { if(rc == cib_ok) { crm_debug_2(UPDATE_PREFIX"[%s] Operation %s to <%s%s%s> confirmed.", event, op, crm_str(type), id?" id=":"", id?id:""); } else { crm_warn(UPDATE_PREFIX"[%s] Operation %s to <%s %s%s> ABORTED: (%d) %s", event, op, crm_str(type), id?" id=":"", id?id:"", rc, cib_error2string(rc)); } } - if(update == NULL) { + if(update != NULL) { print_xml_formatted( rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX, update, "Update"); } print_xml_formatted( rc==cib_ok?LOG_DEBUG_3:LOG_WARNING, UPDATE_PREFIX, output, "Resulting Object"); if(update_depth == 0) { print_xml_formatted( rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX, generation, "CIB Generation"); } free_xml(update); free_xml(output); free_xml(generation); } + void cibmon_diff(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; crm_data_t *diff = NULL; - crm_data_t *tmp = NULL; - const char *updates = NULL; - const char *old_updates = NULL; - const char *epoche= NULL; - const char *old_epoche= NULL; - const char *admin_epoche= NULL; - const char *old_admin_epoche= NULL; + crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE); + + int log_level = LOG_INFO; if(msg == NULL) { crm_err("NULL update"); return; } - ha_msg_value_int(msg, F_CIB_RC, &rc); - - if(rc < cib_ok) { - return; - } - + ha_msg_value_int(msg, F_CIB_RC, &rc); op = cl_get_string(msg, F_CIB_OPERATION); diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); - tmp = find_xml_node(diff, "diff-added", FALSE); - tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE); - updates = crm_element_value(tmp, XML_ATTR_NUMUPDATES); - - tmp = get_message_xml(msg, "cib_generation"); - epoche = crm_element_value(tmp, XML_ATTR_GENERATION); - admin_epoche = crm_element_value(tmp, XML_ATTR_GENERATION_ADMIN); - - tmp = find_xml_node(diff, "diff-removed", FALSE); - tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE); - old_updates = crm_element_value(tmp, XML_ATTR_NUMUPDATES); - old_epoche = crm_element_value(tmp, XML_ATTR_GENERATION); - if(old_epoche == NULL) { - old_epoche = epoche; - } - old_admin_epoche = crm_element_value(tmp, XML_ATTR_GENERATION_ADMIN); - if(old_admin_epoche == NULL) { - old_admin_epoche = admin_epoche; - } - - if(old_updates != NULL) { - cl_log(LOG_INFO, "Diff: --- %s%s%s.%s (op=%s)", - old_admin_epoche?old_admin_epoche:"", old_admin_epoche?".":"", - old_epoche?old_epoche:" ", old_updates, op); + if(rc < cib_ok) { + log_level = LOG_WARNING; + crm_log_maybe(log_level, "[%s] %s ABORTED: %s", + event, op, cib_error2string(rc)); + + } else { + crm_log_maybe(log_level, "[%s] %s confirmed", event, op); } - if(updates != NULL) { - cl_log(LOG_INFO, "Diff: +++ %s%s%s.%s (op=%s)", - admin_epoche?admin_epoche:"", admin_epoche?".":"", - epoche?epoche:" ", updates, op); + + log_cib_diff(log_level, diff, op); + if(update != NULL) { + print_xml_formatted( + log_level+1, "raw_update", update, NULL); } - log_xml_diff(LOG_INFO, diff, NULL); free_xml(diff); + free_xml(update); } gboolean cibmon_shutdown(int nsig, gpointer unused) { got_signal = 1; if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } return TRUE; } diff --git a/crm/cib/cibprimatives.h b/crm/cib/cibprimatives.h index c4c8ef3257..7cdfbadfbc 100644 --- a/crm/cib/cibprimatives.h +++ b/crm/cib/cibprimatives.h @@ -1,81 +1,80 @@ -/* $Id: cibprimatives.h,v 1.10 2005/01/26 13:30:55 andrew Exp $ */ +/* $Id: cibprimatives.h,v 1.11 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CIB_PRIMATIVES__H #define CIB_PRIMATIVES__H #include #include #include #include #include #include #include #include #include #include #define IS_DAEMON #define IPC_COMMS typedef crm_data_t cibStatus; typedef crm_data_t cibResource; typedef crm_data_t cibConstraint; typedef crm_data_t cibHaNode; /* extern gboolean initialized; */ /* extern crm_data_t *the_cib; */ /* extern crm_data_t *node_search; */ /* extern crm_data_t *resource_search; */ /* extern crm_data_t *constraint_search; */ /* extern crm_data_t *status_search; */ /* extern const char* crm_system_name; */ extern crm_data_t *get_the_CIB(void); extern int addResource (crm_data_t *cib, crm_data_t *anXmlNode); extern int addConstraint(crm_data_t *cib, crm_data_t *anXmlNode); extern int addHaNode (crm_data_t *cib, crm_data_t *anXmlNode); extern int addStatus (crm_data_t *cib, crm_data_t *anXmlNode); extern crm_data_t *findResource (crm_data_t *cib, const char *id); extern crm_data_t *findConstraint(crm_data_t *cib, const char *id); extern crm_data_t *findHaNode (crm_data_t *cib, const char *id); extern crm_data_t *findStatus (crm_data_t *cib, const char *id); extern int updateResource (crm_data_t *cib, crm_data_t *anXmlNode); extern int updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode); extern int updateHaNode (crm_data_t *cib, crm_data_t *anXmlNode); extern int updateStatus (crm_data_t *cib, crm_data_t *anXmlNode); extern int delResource (crm_data_t *cib, crm_data_t *delete_spec); extern int delConstraint(crm_data_t *cib, crm_data_t *delete_spec); extern int delHaNode (crm_data_t *cib, crm_data_t *delete_spec); extern int delStatus (crm_data_t *cib, crm_data_t *delete_spec); extern int add_cib_object (crm_data_t *parent, crm_data_t *new_obj); extern int delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec); -extern int update_cib_object(crm_data_t *parent, crm_data_t *new_obj, - gboolean force); +extern int update_cib_object(crm_data_t *parent, crm_data_t *new_obj); #endif diff --git a/crm/cib/io.c b/crm/cib/io.c index 8db2d186d0..0e4b1823f8 100644 --- a/crm/cib/io.c +++ b/crm/cib/io.c @@ -1,491 +1,518 @@ -/* $Id: io.c,v 1.22 2005/05/31 14:50:46 andrew Exp $ */ +/* $Id: io.c,v 1.23 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char * local_resource_path[] = { XML_CIB_TAG_STATUS, }; const char * resource_path[] = { XML_CIB_TAG_RESOURCES, }; const char * node_path[] = { XML_CIB_TAG_NODES, }; const char * constraint_path[] = { XML_CIB_TAG_CONSTRAINTS, }; gboolean initialized = FALSE; crm_data_t *the_cib = NULL; crm_data_t *node_search = NULL; crm_data_t *resource_search = NULL; crm_data_t *constraint_search = NULL; crm_data_t *status_search = NULL; gboolean cib_writes_enabled = TRUE; extern char *ccm_transition_id; extern gboolean cib_have_quorum; extern GHashTable *peer_hash; int set_connected_peers(crm_data_t *xml_obj); void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data); /* * It is the callers responsibility to free the output of this function */ crm_data_t* readCibXml(char *buffer) { - crm_data_t *root = string2xml(buffer); + crm_data_t *root = NULL; + if(buffer != NULL) { + root = string2xml(buffer); + } if (verifyCibXml(root) == FALSE) { free_xml(root); - return createEmptyCib(); + root = createEmptyCib(); + set_xml_property_copy(root, XML_ATTR_GENERATION_ADMIN, "0"); + set_xml_property_copy(root, XML_ATTR_GENERATION, "0"); + set_xml_property_copy(root, XML_ATTR_NUMUPDATES, "0"); } return root; } /* * It is the callers responsibility to free the output of this function */ crm_data_t* readCibXmlFile(const char *filename) { int s_res = -1; struct stat buf; crm_data_t *root = NULL; - if(filename != NULL) { s_res = stat(filename, &buf); } if (s_res == 0) { FILE *cib_file = fopen(filename, "r"); root = file2xml(cib_file); set_xml_property_copy(root, "generated", XML_BOOLEAN_FALSE); fclose(cib_file); } else { crm_warn("Stat of (%s) failed, file does not exist.", CIB_FILENAME); } if(root != NULL) { int lpc = 0; + const char *value = NULL; + const char *name = NULL; crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, root); for (; status != NULL && lpc < status->nfields; ) { if(status->types[lpc] != FT_STRUCT) { lpc++; continue; } CRM_DEV_ASSERT(cl_msg_remove_offset(status, lpc) == HA_OK); /* dont get stuck in an infinite loop */ if(crm_assert_failed) { lpc++; } } + + name = XML_ATTR_GENERATION_ADMIN; + value = crm_element_value(root, name); + if(value == NULL) { + set_xml_property_copy(root, name, "0"); + } + name = XML_ATTR_GENERATION; + value = crm_element_value(root, name); + if(value == NULL) { + set_xml_property_copy(root, name, "0"); + } + name = XML_ATTR_NUMUPDATES; + value = crm_element_value(root, name); + if(value == NULL) { + set_xml_property_copy(root, name, "0"); + } } if (verifyCibXml(root) == FALSE) { free_xml(root); root = NULL; } return root; } /* * The caller should never free the return value */ crm_data_t* get_the_CIB(void) { return the_cib; } gboolean uninitializeCib(void) { crm_data_t *tmp_cib = the_cib; if(tmp_cib == NULL) { crm_err("The CIB has already been deallocated."); return FALSE; } initialized = FALSE; the_cib = NULL; node_search = NULL; resource_search = NULL; constraint_search = NULL; status_search = NULL; crm_err("Deallocating the CIB."); free_xml(tmp_cib); crm_err("The CIB has been deallocated."); return TRUE; } /* * This method will not free the old CIB pointer or the new one. * We rely on the caller to have saved a pointer to the old CIB * and to free the old/bad one depending on what is appropriate. */ gboolean initializeCib(crm_data_t *new_cib) { #if 0 if(new_cib != NULL) { crm_set_element_parent(new_cib, NULL); } #endif if (verifyCibXml(new_cib)) { initialized = FALSE; the_cib = new_cib; /* update search paths */ /* not used yet... node_search = get_object_root(XML_CIB_TAG_NODES, new_cib); resource_search = get_object_root(XML_CIB_TAG_RESOURCES, new_cib); constraint_search = get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib); status_search = get_object_root(XML_CIB_TAG_STATUS, new_cib); */ initialized = TRUE; } if(initialized == FALSE) { crm_warn("CIB Verification failed"); the_cib = NULL; } else { const char *option = "suppress_cib_writes"; const char *value = NULL; crm_data_t *config = get_object_root( XML_CIB_TAG_CRMCONFIG, new_cib); crm_data_t * a_default = find_entity( config, XML_CIB_TAG_NVPAIR, option); if(a_default != NULL) { value = crm_element_value( a_default, XML_NVPAIR_ATTR_VALUE); } if(value == NULL) { crm_warn("Option %s not set", option); if(cib_writes_enabled == FALSE) { crm_debug("Disk writes to %s enabled", CIB_FILENAME); } cib_writes_enabled = TRUE; } else { gboolean suppress = FALSE; crm_str_to_boolean(value, &suppress); if(cib_writes_enabled != suppress) { cib_writes_enabled = !suppress; if(cib_writes_enabled) { crm_debug("Disk writes to %s enabled", CIB_FILENAME); } else { crm_notice("Disabling CIB disk writes"); } } - } + } + crm_debug_2("Disk writes to %s %s", CIB_FILENAME, cib_writes_enabled?"enabled":"DISABLED"); set_connected_peers(the_cib); set_transition(the_cib); if(cib_have_quorum) { set_xml_property_copy( the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE); } else { set_xml_property_copy( the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE); } } return initialized; } int moveFile(const char *oldname, const char *newname, gboolean backup, char *ext) { /* move 'oldname' to 'newname' by creating a hard link to it * and then removing the original hard link */ int res = 0; struct stat tmp; int s_res = stat(newname, &tmp); if (s_res >= 0) { if (backup == TRUE) { char backname[1024]; static const char *back_ext = "bak"; if (ext != NULL) { back_ext = (char*)ext; } snprintf(backname, sizeof(backname)-1, "%s.%s", newname, back_ext); moveFile(newname, backname, FALSE, NULL); } else { res = unlink(newname); if (res < 0) { perror("Could not remove the current backup of Cib"); return -1; } } } s_res = stat(oldname, &tmp); if (s_res >= 0) { res = link(oldname, newname); if (res < 0) { perror("Could not create backup of current Cib"); return -2; } res = unlink(oldname); if (res < 0) { perror("Could not unlink the current Cib"); return -3; } } return 0; } int activateCibBuffer(char *buffer, const char *filename) { int result = -1; crm_data_t *local_cib = NULL; local_cib = readCibXml(buffer); result = activateCibXml(local_cib, filename); return result; } /* * This method will free the old CIB pointer on success and the new one * on failure. */ +#define ACTIVATION_DIFFS 0 int activateCibXml(crm_data_t *new_cib, const char *filename) { int error_code = cib_ok; crm_data_t *diff = NULL; crm_data_t *saved_cib = get_the_CIB(); const char *filename_bak = CIB_BACKUP; /* calculate */ crm_log_xml_debug_3(new_cib, "Attempting to activate CIB"); CRM_ASSERT(new_cib != saved_cib); crm_validate_data(new_cib); if(saved_cib != NULL) { crm_validate_data(saved_cib); } if (initializeCib(new_cib) == FALSE) { crm_warn("Ignoring invalid or NULL Cib"); error_code = -5; } else if(cib_writes_enabled) { if(saved_cib != NULL) { CRM_DEV_ASSERT(0 >= moveFile(filename, filename_bak, FALSE, NULL)); if (crm_assert_failed) { crm_warn("Could not make backup of the current" " Cib... aborting update."); error_code = -1; } } if(error_code == cib_ok) { crm_debug_3("Writing CIB out to %s", CIB_FILENAME); CRM_DEV_ASSERT(write_xml_file( new_cib, CIB_FILENAME) >= 0); if (crm_assert_failed) { error_code = -4; } } if(error_code == -4 && saved_cib != NULL) { CRM_DEV_ASSERT(moveFile(filename_bak, filename, FALSE, NULL) >= 0); if (crm_assert_failed){ crm_crit("Could not restore the backup of the " " current Cib... panic!"); error_code = -2; /* should probably exit here */ } } CRM_DEV_ASSERT(saved_cib != NULL || error_code == cib_ok); if(crm_assert_failed) { /* oh we are so dead */ crm_crit("Could not write out new CIB and no saved" " version to revert to"); error_code = -3; } else if(error_code != cib_ok) { crm_crit("Update of Cib failed (%d)... reverting" " to last known valid version", error_code); CRM_DEV_ASSERT(initializeCib(saved_cib)); if (crm_assert_failed) { /* oh we are so dead */ crm_crit("Could not re-initialize with the old" " CIB. Can anyone say corruption?"); error_code = -3; } } } #if ACTIVATION_DIFFS /* Make sure memory is cleaned up appropriately */ - diff = diff_xml_object(saved_cib, new_cib, -1); + if(saved_cib != NULL && new_cib != NULL) { + diff = diff_cib_object(saved_cib, new_cib, -1); + } if (error_code != cib_ok) { crm_err("Changes could not be activated: %s", cib_error2string(error_code)); - log_xml_diff(LOG_WARNING, diff, __FUNCTION__); + log_cib_diff(LOG_WARNING, diff, __FUNCTION__); free_xml(new_cib); } else if(saved_cib != NULL) { crm_debug_2("Changes activated"); - log_xml_diff(LOG_DEBUG, diff, __FUNCTION__); + log_cib_diff(LOG_DEBUG, diff, __FUNCTION__); crm_validate_data(saved_cib); free_xml(saved_cib); } free_xml(diff); #else if (error_code != cib_ok) { crm_err("Changes could not be activated: %s", cib_error2string(error_code)); free_xml(new_cib); } else if(saved_cib != NULL) { crm_debug_2("Changes activated"); crm_validate_data(saved_cib); free_xml(saved_cib); } #endif diff = NULL; return error_code; } void set_transition(crm_data_t *xml_obj) { const char *current = crm_element_value( xml_obj, XML_ATTR_CCM_TRANSITION); if(safe_str_neq(current, ccm_transition_id)) { crm_debug("Set transition to %s", ccm_transition_id); set_xml_property_copy( the_cib, XML_ATTR_CCM_TRANSITION, ccm_transition_id); } } int set_connected_peers(crm_data_t *xml_obj) { int active = 0; int current = 0; char *peers_s = NULL; const char *current_s = crm_element_value( xml_obj, XML_ATTR_NUMPEERS); g_hash_table_foreach(peer_hash, GHFunc_count_peers, &active); current = crm_atoi(current_s, "0"); if(current != active) { peers_s = crm_itoa(active); set_xml_property_copy(xml_obj, XML_ATTR_NUMPEERS, peers_s); crm_debug("Set peers to %s", peers_s); crm_free(peers_s); } return active; } void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data) { int *active = user_data; if(safe_str_eq(value, ONLINESTATUS)) { (*active)++; } else if(safe_str_eq(value, JOINSTATUS)) { (*active)++; } } diff --git a/crm/cib/main.c b/crm/cib/main.c index e8b47f73fc..e1ea0cd965 100644 --- a/crm/cib/main.c +++ b/crm/cib/main.c @@ -1,338 +1,339 @@ -/* $Id: main.c,v 1.25 2005/05/18 20:15:57 andrew Exp $ */ +/* $Id: main.c,v 1.26 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include /* #include */ #include /* #include */ #include #include #include #include #include #include #include #include #include #include extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); GMainLoop* mainloop = NULL; const char* crm_system_name = CRM_SYSTEM_CIB; char *cib_our_uname = NULL; oc_ev_t *cib_ev_token; void usage(const char* cmd, int exit_status); int init_start(void); gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name); gboolean cib_shutdown(int nsig, gpointer unused); void cib_ha_connection_destroy(gpointer user_data); gboolean startCib(const char *filename); extern gboolean cib_msg_timeout(gpointer data); ll_cluster_t *hb_conn = NULL; #define OPTARGS "hV" int main(int argc, char ** argv) { int argerr = 0; int flag; crm_log_init(crm_system_name); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cib_shutdown, NULL, NULL); client_list = g_hash_table_new(g_str_hash, g_str_equal); peer_hash = g_hash_table_new(g_str_hash, g_str_equal); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': cl_log_enable_stderr(1); alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ return init_start(); } int init_start(void) { gboolean was_error = FALSE; hb_conn = ll_cluster_new("heartbeat"); if(cib_register_ha(hb_conn, CRM_SYSTEM_CIB) == FALSE) { crm_crit("Cannot sign in to heartbeat... terminating"); fprintf(stderr, "Cannot sign in to heartbeat... terminating"); exit(1); } if(startCib(CIB_FILENAME) == FALSE){ crm_crit("Cannot start CIB... terminating"); exit(1); } was_error = init_server_ipc_comms( crm_strdup(cib_channel_callback), cib_client_connect, default_ipc_connection_destroy); was_error = was_error || init_server_ipc_comms( crm_strdup(cib_channel_ro), cib_client_connect, default_ipc_connection_destroy); was_error = was_error || init_server_ipc_comms( crm_strdup(cib_channel_rw), cib_client_connect, default_ipc_connection_destroy); if(was_error == FALSE) { crm_debug_3("Be informed of CRM Client Status changes"); if (HA_OK != hb_conn->llc_ops->set_cstatus_callback( hb_conn, cib_client_status_callback, hb_conn)) { crm_err("Cannot set cstatus callback: %s", hb_conn->llc_ops->errmsg(hb_conn)); was_error = TRUE; } else { crm_debug_3("Client Status callback set"); } } if(was_error == FALSE) { gboolean did_fail = TRUE; int num_ccm_fails = 0; int max_ccm_fails = 30; int ret; int cib_ev_fd; while(did_fail && was_error == FALSE) { did_fail = FALSE; crm_debug_3("Registering with CCM"); ret = oc_ev_register(&cib_ev_token); if (ret != 0) { crm_warn("CCM registration failed"); did_fail = TRUE; } if(did_fail == FALSE) { crm_debug_3("Setting up CCM callbacks"); ret = oc_ev_set_callback( cib_ev_token, OC_EV_MEMB_CLASS, cib_ccm_msg_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(cib_ev_token, OC_EV_MEMB_CLASS, 0); crm_debug_3("Activating CCM token"); ret = oc_ev_activate(cib_ev_token, &cib_ev_fd); if (ret != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } if(did_fail) { num_ccm_fails++; oc_ev_unregister(cib_ev_token); if(num_ccm_fails < max_ccm_fails){ crm_warn("CCM Connection failed" " %d times (%d max)", num_ccm_fails, max_ccm_fails); sleep(1); } else { crm_err("CCM Activation failed" " %d (max) times", num_ccm_fails); was_error = TRUE; } } } crm_debug_3("CCM Activation passed... all set to go!"); G_main_add_fd(G_PRIORITY_HIGH, cib_ev_fd, FALSE, cib_ccm_dispatch, cib_ev_token, default_ipc_connection_destroy); } if(was_error == FALSE) { /* Async get client status information in the cluster */ crm_debug_3("Requesting an initial dump of CRMD client_status"); hb_conn->llc_ops->client_status( hb_conn, NULL, CRM_SYSTEM_CRMD, -1); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s mainloop", crm_system_name); Gmain_timeout_add(1000, cib_msg_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { crm_err("Couldnt start all communication channels, exiting."); } return 0; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name) { const char *uname = NULL; crm_info("Signing in with Heartbeat"); if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) { crm_err("Cannot sign on with heartbeat: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } crm_set_ha_options(hb_cluster); crm_debug_3("Be informed of CIB messages"); if (HA_OK != hb_cluster->llc_ops->set_msg_callback( hb_cluster, T_CIB, cib_peer_callback, hb_cluster)){ crm_err("Cannot set msg callback: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } crm_debug_3("Finding our node name"); if ((uname = hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) { crm_err("get_mynodeid() failed"); return FALSE; } cib_our_uname = crm_strdup(uname); crm_info("FSA Hostname: %s", cib_our_uname); crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, hb_cluster->llc_ops->ipcchan(hb_cluster), FALSE, cib_ha_dispatch, hb_cluster /* userdata */, cib_ha_connection_destroy); return TRUE; } void cib_ha_connection_destroy(gpointer user_data) { } gboolean cib_shutdown(int nsig, gpointer unused) { static int shuttingdown = 0; if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } return TRUE; } gboolean startCib(const char *filename) { crm_data_t *cib = readCibXmlFile(filename); if (initializeCib(cib)) { crm_info("CIB Initialization completed successfully"); } else { /* free_xml(cib); */ crm_warn("CIB Initialization failed, " "starting with an empty default."); - activateCibXml(createEmptyCib(), filename); + cib = readCibXml(NULL); + activateCibXml(cib, filename); } return TRUE; } diff --git a/crm/cib/messages.c b/crm/cib/messages.c index efd6f6c4c0..a0b8d58270 100644 --- a/crm/cib/messages.c +++ b/crm/cib/messages.c @@ -1,755 +1,867 @@ -/* $Id: messages.c,v 1.38 2005/05/31 11:32:39 andrew Exp $ */ +/* $Id: messages.c,v 1.39 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include extern const char *cib_our_uname; +extern gboolean syncd_once; enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags); int get_revision(crm_data_t *xml_obj, int cur_revision); enum cib_errors updateList( crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed, int operation, const char *section); crm_data_t *createCibFragmentAnswer(const char *section, crm_data_t *failed); enum cib_errors replace_section( const char *section, crm_data_t *tmpCib, crm_data_t *command); gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib); gboolean update_results( crm_data_t *failed, crm_data_t *target, int operation, int return_code); enum cib_errors cib_update_counter( crm_data_t *xml_obj, const char *field, gboolean reset); +enum cib_errors sync_our_cib(HA_Message *request, gboolean all); + enum cib_errors cib_process_default( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event", op); if(answer != NULL) { *answer = NULL; } if(op == NULL) { result = cib_operation; crm_err("No operation specified"); } else if(strcmp(CRM_OP_NOOP, op) == 0) { ; } else { result = cib_NOTSUPPORTED; crm_err("Action [%s] is not supported by the CIB", op); } return result; } enum cib_errors cib_process_quit( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event", op); - cib_pre_notify(options, op, get_the_CIB(), NULL); crm_warn("The CRMd has asked us to exit... complying"); exit(0); return result; } + enum cib_errors cib_process_readwrite( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event", op); - if(safe_str_eq(op, CRM_OP_CIB_ISMASTER)) { + if(safe_str_eq(op, CIB_OP_ISMASTER)) { if(cib_is_master == TRUE) { result = cib_ok; } else { result = cib_not_master; } return result; } - cib_pre_notify(options, op, get_the_CIB(), NULL); - if(safe_str_eq(op, CRM_OP_CIB_MASTER)) { + if(safe_str_eq(op, CIB_OP_MASTER)) { if(cib_is_master == FALSE) { crm_info("We are now in R/W mode"); cib_is_master = TRUE; + syncd_once = TRUE; + } else { crm_debug("We are still in R/W mode"); } } else if(cib_is_master) { crm_info("We are now in R/O mode"); cib_is_master = FALSE; } - cib_post_notify(options, op, NULL, result, NULL); return result; } enum cib_errors cib_process_ping( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event", op); if(answer != NULL) { *answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok"); } return result; } enum cib_errors cib_process_query( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { crm_data_t *obj_root = NULL; enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event for section=%s", op, crm_str(section)); if(answer != NULL) { *answer = NULL; } else { return cib_output_ptr; } -#if 1 if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) { section = NULL; } -#else - if (section == NULL) { - section = XML_CIB_TAG_SECTION_ALL; - } -#endif *answer = create_xml_node(NULL, XML_TAG_FRAGMENT); /* set_xml_property_copy(*answer, XML_ATTR_SECTION, section); */ - obj_root = get_object_root(section, get_the_CIB()); + obj_root = get_object_root(section, existing_cib); if(obj_root == NULL) { result = cib_NOTEXISTS; - } else if(obj_root == get_the_CIB()) { + } else if(obj_root == existing_cib) { set_xml_property_copy(obj_root, "origin", cib_our_uname); add_node_copy(*answer, obj_root); } else { crm_data_t *cib = createEmptyCib(); crm_data_t *query_obj_root = get_object_root(section, cib); - copy_in_properties(cib, get_the_CIB()); + copy_in_properties(cib, existing_cib); set_xml_property_copy(cib, "origin", cib_our_uname); xml_child_iter( obj_root, an_obj, NULL, add_node_copy(query_obj_root, an_obj); ); add_node_copy(*answer, cib); free_xml(cib); } if(result == cib_ok && *answer == NULL) { crm_err("Error creating query response"); result = cib_output_data; } return result; } enum cib_errors cib_process_erase( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { - crm_data_t *cib_diff = NULL; - crm_data_t *tmpCib = NULL; enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event", op); if(answer != NULL) { *answer = NULL; } - tmpCib = createEmptyCib(); + *result_cib = createEmptyCib(); - result = revision_check(get_the_CIB(), tmpCib, options); - copy_in_properties(tmpCib, get_the_CIB()); + result = revision_check(existing_cib, *result_cib, options); + copy_in_properties(*result_cib, existing_cib); - cib_pre_notify(options, op, the_cib, tmpCib); - cib_update_counter(tmpCib, XML_ATTR_NUMUPDATES, TRUE); - - cib_diff = diff_xml_object(the_cib, tmpCib, -1); - if(result == cib_ok && activateCibXml(tmpCib, CIB_FILENAME) < 0) { - result = cib_ACTIVATION; + if(result == cib_ok && !(options & cib_inhibit_bcast)) { + cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE); } - - cib_post_notify(options, op, NULL, result, the_cib); - cib_diff_notify(options, op, NULL, result, cib_diff); - crm_free(cib_diff); - + if(answer != NULL) { *answer = createCibFragmentAnswer(NULL, NULL); } return result; } enum cib_errors cib_process_bump( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { - crm_data_t *cib_diff = NULL; - crm_data_t *tmpCib = NULL; enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event for epoche=%s", op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION))); if(answer != NULL) { *answer = NULL; } - cib_pre_notify(options, op, get_the_CIB(), NULL); + *result_cib = copy_xml(the_cib); - tmpCib = copy_xml_node_recursive(the_cib); - cib_update_counter(tmpCib, XML_ATTR_GENERATION, FALSE); - cib_update_counter(tmpCib, XML_ATTR_NUMUPDATES, FALSE); + cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE); + cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE); - cib_diff = diff_xml_object(the_cib, tmpCib, -1); - if(activateCibXml(tmpCib, CIB_FILENAME) < 0) { - result = cib_ACTIVATION; - } - - cib_post_notify(options, op, NULL, result, get_the_CIB()); - cib_diff_notify(options, op, NULL, result, cib_diff); - crm_free(cib_diff); - if(answer != NULL) { *answer = createCibFragmentAnswer(NULL, NULL); } return result; } +extern ll_cluster_t *hb_conn; +extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data); + +enum cib_errors +cib_process_sync( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) +{ + return sync_our_cib(input, TRUE); +} + +enum cib_errors +cib_process_sync_one( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) +{ + return sync_our_cib(input, FALSE); +} + enum cib_errors cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset) { char *new_value = NULL; char *old_value = NULL; int int_value = -1; /* modify the timestamp */ set_node_tstamp(xml_obj); if(reset == FALSE && crm_element_value(xml_obj, field) != NULL) { old_value = crm_element_value_copy(xml_obj, field); } if(old_value != NULL) { crm_malloc0(new_value, 128*(sizeof(char))); int_value = atoi(old_value); sprintf(new_value, "%d", ++int_value); } else { new_value = crm_strdup("1"); } crm_debug_4("%s %d(%s)->%s", field, int_value, crm_str(old_value), crm_str(new_value)); set_xml_property_copy(xml_obj, field, new_value); crm_free(new_value); crm_free(old_value); return cib_ok; } +enum cib_errors +cib_process_diff( + const char *op, int options, const char *section, crm_data_t *input, + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) +{ + int log_level = LOG_DEBUG; + const char *value = NULL; + const char *reason = NULL; + gboolean apply_diff = TRUE; + gboolean do_resync = FALSE; + enum cib_errors result = cib_ok; + + int this_updates = 0; + int this_epoche = 0; + int this_admin_epoche = 0; + + int diff_add_updates = 0; + int diff_add_epoche = 0; + int diff_add_admin_epoche = 0; + + int diff_del_updates = 0; + int diff_del_epoche = 0; + int diff_del_admin_epoche = 0; + + crm_debug("Processing \"%s\" event", op); + + value = crm_element_value(existing_cib, XML_ATTR_GENERATION); + this_epoche = atoi(value?value:"0"); + + value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES); + this_updates = atoi(value?value:"0"); + + value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN); + this_admin_epoche = atoi(value?value:"0"); + + cib_diff_version_details( + input, + &diff_add_admin_epoche, &diff_add_epoche, &diff_add_updates, + &diff_del_admin_epoche, &diff_del_epoche, &diff_del_updates); + + if(diff_del_admin_epoche == diff_add_admin_epoche + && diff_del_epoche == diff_add_epoche + && diff_del_updates == diff_add_updates) { + apply_diff = FALSE; + log_level = LOG_ERR; + reason = "+ and - versions in the diff did not change"; + log_cib_diff(LOG_ERR, input, __FUNCTION__); + } + + if(apply_diff && diff_del_admin_epoche > this_admin_epoche) { + do_resync = TRUE; + apply_diff = FALSE; + log_level = LOG_INFO; + reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required"; + + } else if(apply_diff && diff_del_admin_epoche < this_admin_epoche) { + apply_diff = FALSE; + log_level = LOG_WARNING; + reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required"; + } + + if(apply_diff && diff_del_epoche > this_epoche) { + do_resync = TRUE; + apply_diff = FALSE; + log_level = LOG_INFO; + reason = "current \""XML_ATTR_GENERATION"\" is less than required"; + + } else if(apply_diff && diff_del_epoche < this_epoche) { + apply_diff = FALSE; + log_level = LOG_WARNING; + reason = "current \""XML_ATTR_GENERATION"\" is greater than required"; + } + + if(apply_diff && diff_del_updates > this_updates) { + do_resync = TRUE; + apply_diff = FALSE; + log_level = LOG_INFO; + reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required"; + + } else if(apply_diff && diff_del_updates < this_updates) { + apply_diff = FALSE; + log_level = LOG_WARNING; + reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required"; + } + + if(apply_diff + && apply_cib_diff(existing_cib, input, result_cib) == FALSE) { + log_level = LOG_WARNING; + reason = "Failed application of an update diff"; + if(options & cib_force_diff && cib_is_master == FALSE) { + log_level = LOG_INFO; + reason = "Failed application of a global update. Requesting full refresh."; + do_resync = TRUE; + } else if(options & cib_force_diff) { + reason = "Failed application of a global update. Not requesting full refresh."; + } + } + + if(reason != NULL) { + crm_log_maybe( + log_level, + "Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s", + diff_del_admin_epoche,diff_del_epoche,diff_del_updates, + diff_add_admin_epoche,diff_add_epoche,diff_add_updates, + this_admin_epoche,this_epoche,this_updates, reason); + + result = cib_diff_failed; + } + + if(do_resync && cib_is_master == FALSE) { + HA_Message *sync_me = ha_msg_new(2); + free_xml(*result_cib); + *result_cib = NULL; + result = cib_diff_resync; + crm_info("Requesting re-sync from peer: %s", reason); + + ha_msg_add(sync_me, F_TYPE, "cib"); + ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE); + + if(send_ha_message(hb_conn, sync_me, NULL) == FALSE) { + result = cib_not_connected; + } + ha_msg_del(sync_me); + + } else if(do_resync) { + crm_err("Not resyncing in master mode"); + } + + + return result; +} + enum cib_errors cib_process_replace( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { gboolean verbose = FALSE; - crm_data_t *tmpCib = NULL; - crm_data_t *cib_update = NULL; - crm_data_t *the_update = NULL; - crm_data_t *cib_diff = NULL; - char *section_name = NULL; enum cib_errors result = cib_ok; crm_debug("Processing \"%s\" event for section=%s", op, crm_str(section)); if(answer != NULL) { *answer = NULL; } if (options & cib_verbose) { verbose = TRUE; } if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) { section = NULL; } - cib_update = find_xml_node(input, XML_TAG_CIB, TRUE); - - if (cib_update == NULL) { + if (input == NULL) { result = cib_NOOBJECT; - } else if (section == NULL) { - tmpCib = copy_xml_node_recursive(cib_update); - the_update = cib_update; - section_name = crm_strdup(crm_element_name(tmpCib)); + } else if(section == NULL) { + int updates = 0; + int epoche = 0; + int admin_epoche = 0; - } else { - tmpCib = copy_xml_node_recursive(get_the_CIB()); - section_name = crm_strdup(section); + int replace_updates = 0; + int replace_epoche = 0; + int replace_admin_epoche = 0; + const char *reason = NULL; - result = replace_section(section_name, tmpCib, input); - the_update = get_object_root(section_name, cib_update); - } + cib_version_details( + existing_cib, &admin_epoche, &epoche, &updates); + cib_version_details(input, &replace_admin_epoche, + &replace_epoche, &replace_updates); + + if(replace_admin_epoche < admin_epoche) { + reason = XML_ATTR_GENERATION_ADMIN; - cib_pre_notify(options, - op, get_object_root(section_name, get_the_CIB()), the_update); + } else if(replace_epoche < epoche) { + reason = XML_ATTR_GENERATION; + + } else if(replace_updates < updates) { + reason = XML_ATTR_NUMUPDATES; + } - if(result == cib_ok) { - cib_update_counter(tmpCib, XML_ATTR_NUMUPDATES, FALSE); + if(reason != NULL) { + crm_err("Replacement %d.%d.%d not applied to %d.%d.%d:" + " current %s is greater than the replacement", + replace_admin_epoche, replace_epoche, + replace_updates, admin_epoche, epoche, updates, + reason); + result = cib_old_data; + } + *result_cib = copy_xml(input); - result = revision_check(the_update, tmpCib, options); - copy_in_properties(tmpCib, cib_update); - } - - cib_diff = diff_xml_object(the_cib, tmpCib, -1); - if (result == cib_ok && activateCibXml(tmpCib, CIB_FILENAME) < 0) { - crm_warn("Replacment of section=%s failed", section); - result = cib_ACTIVATION; + } else { + *result_cib = copy_xml(existing_cib); + result = replace_section(section, *result_cib, input); } - if (verbose || result != cib_ok) { - if(answer != NULL) { - *answer = createCibFragmentAnswer(section_name, NULL); - } + if(result == cib_ok && section != NULL) { + cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE); } - cib_post_notify(options, op, the_update, result, - get_object_root(section_name, get_the_CIB())); - - cib_diff_notify(options, op, NULL, result, cib_diff); - crm_free(cib_diff); + if (answer != NULL && (verbose || result != cib_ok)) { + *answer = createCibFragmentAnswer(section, NULL); + } - crm_free(section_name); return result; } - -/* FILE *msg_cibup_strm = NULL; */ - enum cib_errors cib_process_modify( const char *op, int options, const char *section, crm_data_t *input, - crm_data_t **answer) + crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer) { gboolean verbose = FALSE; - enum cib_errors result = cib_ok; - char *section_name = NULL; - crm_data_t *failed = NULL; - crm_data_t *cib_update = NULL; - crm_data_t *the_update = NULL; - crm_data_t *cib_diff = NULL; - - int cib_update_op = CIB_OP_NONE; - - crm_data_t *tmpCib = NULL; + enum cib_errors result = cib_ok; + int cib_update_op = CIB_UPDATE_OP_NONE; crm_debug("Processing \"%s\" event for section=%s", op, crm_str(section)); failed = create_xml_node(NULL, XML_TAG_FAILED); - if (strcmp(CRM_OP_CIB_CREATE, op) == 0) { - cib_update_op = CIB_OP_ADD; + if (strcmp(CIB_OP_CREATE, op) == 0) { + cib_update_op = CIB_UPDATE_OP_ADD; - } else if (strcmp(CRM_OP_CIB_UPDATE, op) == 0 - || strcmp(CRM_OP_JOIN_ACKNAK, op) == 0 - || strcmp(CRM_OP_SHUTDOWN_REQ, op) == 0) { - cib_update_op = CIB_OP_MODIFY; + } else if (strcmp(CIB_OP_UPDATE, op) == 0) { + cib_update_op = CIB_UPDATE_OP_MODIFY; - } else if (strcmp(CRM_OP_CIB_DELETE, op) == 0) { - cib_update_op = CIB_OP_DELETE; + } else if (strcmp(CIB_OP_DELETE, op) == 0) { + cib_update_op = CIB_UPDATE_OP_DELETE; } else { crm_err("Incorrect request handler invoked for \"%s\" op", crm_str(op)); return cib_operation; } result = cib_ok; if (options & cib_verbose) { verbose = TRUE; } if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) { section = NULL; } if(input == NULL) { crm_err("Cannot perform modification with no data"); return cib_NOOBJECT; } - tmpCib = copy_xml_node_recursive(get_the_CIB()); - cib_update = find_xml_node(input, XML_TAG_CIB, TRUE); + *result_cib = copy_xml(existing_cib); - /* do logging */ - the_update = get_object_root(section, cib_update); - - crm_validate_data(the_update); - crm_validate_data(tmpCib); - - cib_pre_notify(options, op, get_object_root(section, tmpCib), the_update); - - crm_validate_data(the_update); - crm_validate_data(tmpCib); - - result = revision_check(cib_update, tmpCib, options); - copy_in_properties(tmpCib, cib_update); + crm_validate_data(input); + crm_validate_data(*result_cib); /* make changes to a temp copy then activate */ if(section == NULL) { + crm_data_t *sub_input = NULL; + copy_in_properties(*result_cib, input); /* order is no longer important here */ - section_name = crm_strdup(crm_element_name(tmpCib)); - if(result == cib_ok) { - + sub_input = get_object_root(XML_CIB_TAG_NODES, input); result = updateList( - tmpCib, input, failed, cib_update_op, + *result_cib, sub_input, failed, cib_update_op, XML_CIB_TAG_NODES); } if(result == cib_ok) { + sub_input = get_object_root(XML_CIB_TAG_NODES, input); result = updateList( - tmpCib, input, failed, - cib_update_op, XML_CIB_TAG_RESOURCES); + *result_cib, sub_input, failed, cib_update_op, + XML_CIB_TAG_RESOURCES); } if(result == cib_ok) { + sub_input = get_object_root(XML_CIB_TAG_NODES, input); result = updateList( - tmpCib, input, failed, - cib_update_op, XML_CIB_TAG_CONSTRAINTS); + *result_cib, sub_input, failed, cib_update_op, + XML_CIB_TAG_CONSTRAINTS); } if(result == cib_ok) { - result = updateList(tmpCib, input, failed, - cib_update_op, XML_CIB_TAG_STATUS); + sub_input = get_object_root(XML_CIB_TAG_NODES, input); + result = updateList( + *result_cib, sub_input, failed, cib_update_op, + XML_CIB_TAG_STATUS); } } else { - section_name = crm_strdup(section); - result = updateList(tmpCib, input, failed, - cib_update_op, section); + result = updateList( + *result_cib, input, failed, cib_update_op, section); } crm_debug_4("Activating temporary CIB"); - cib_update_counter(tmpCib, XML_ATTR_NUMUPDATES, FALSE); - - cib_diff = diff_xml_object(the_cib, tmpCib, -1); - if (result == cib_ok && activateCibXml(tmpCib, CIB_FILENAME) < 0) { - result = cib_ACTIVATION; - - } else if (result != cib_ok || xml_has_children(failed)) { + if(result == cib_ok && !(options & cib_inhibit_bcast)) { + cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE); + } + + if (result != cib_ok || xml_has_children(failed)) { if(result == cib_ok) { result = cib_unknown; } crm_log_xml_err(failed, "CIB Update failures"); } if (verbose || xml_has_children(failed) || result != cib_ok) { - *answer = createCibFragmentAnswer(section_name, failed); + *answer = createCibFragmentAnswer(section, failed); } - cib_diff_notify(options, op, NULL, result, cib_diff); - crm_free(cib_diff); - - cib_post_notify(options, op, the_update, result, - get_object_root(section_name, get_the_CIB())); - free_xml(failed); - crm_free(section_name); return result; } enum cib_errors -replace_section(const char *section, crm_data_t *tmpCib, crm_data_t *fragment) +replace_section( + const char *section, crm_data_t *tmpCib, crm_data_t *new_section) { - crm_data_t *cib_updates = NULL; - crm_data_t *new_section = NULL; crm_data_t *old_section = NULL; - - cib_updates = find_xml_node(fragment, XML_TAG_CIB, TRUE); /* find the old and new versions of the section */ - new_section = get_object_root(section, cib_updates); old_section = get_object_root(section, tmpCib); if(old_section == NULL) { crm_err("The CIB is corrupt, cannot replace missing section %s", section); return cib_NOSECTION; } else if(new_section == NULL) { crm_err("The CIB is corrupt, cannot set section %s to nothing", section); return cib_NOSECTION; } xml_child_iter( old_section, a_child, NULL, free_xml_from_parent(old_section, a_child); ); copy_in_properties(old_section, new_section); xml_child_iter( new_section, a_child, NULL, add_node_copy(old_section, a_child); ); return cib_ok; } enum cib_errors -updateList(crm_data_t *local_cib, crm_data_t *update_fragment, crm_data_t *failed, +updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed, int operation, const char *section) { int rc = cib_ok; crm_data_t *this_section = get_object_root(section, local_cib); - crm_data_t *cib_updates = NULL; - crm_data_t *xml_section = NULL; - - cib_updates = find_xml_node(update_fragment, XML_TAG_CIB, TRUE); - xml_section = get_object_root(section, cib_updates); if (section == NULL || xml_section == NULL) { crm_err("Section %s not found in message." " CIB update is corrupt, ignoring.", crm_str(section)); return cib_NOSECTION; } - if((CIB_OP_NONE > operation) || (operation > CIB_OP_MAX)) { + if((CIB_UPDATE_OP_NONE > operation) || (operation > CIB_UPDATE_OP_MAX)){ crm_err("Invalid operation on section %s", crm_str(section)); return cib_operation; } set_node_tstamp(this_section); xml_child_iter( xml_section, a_child, NULL, rc = cib_ok; - if(operation == CIB_OP_DELETE) { + if(operation == CIB_UPDATE_OP_DELETE) { rc = delete_cib_object(this_section, a_child); update_results(failed, a_child, operation, rc); - } else if(operation == CIB_OP_MODIFY) { - rc = update_cib_object(this_section, a_child, FALSE); + } else if(operation == CIB_UPDATE_OP_MODIFY) { + rc = update_cib_object(this_section, a_child); update_results(failed, a_child, operation, rc); } else { rc = add_cib_object(this_section, a_child); update_results(failed, a_child, operation, rc); } ); if(rc == cib_ok && xml_has_children(failed)) { rc = cib_unknown; } return rc; } crm_data_t* createCibFragmentAnswer(const char *section, crm_data_t *failed) { crm_data_t *cib = NULL; crm_data_t *fragment = NULL; fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); if (section == NULL - || strlen(section) == 0 - || strcmp(XML_CIB_TAG_SECTION_ALL, section) == 0) { - + || strlen(section) == 0 + || strcmp(XML_CIB_TAG_SECTION_ALL, section) == 0) { + cib = get_the_CIB(); if(cib != NULL) { add_node_copy(fragment, get_the_CIB()); } } else { crm_data_t *obj_root = get_object_root(section, get_the_CIB()); if(obj_root != NULL) { cib = create_xml_node(fragment, XML_TAG_CIB); add_node_copy(cib, obj_root); copy_in_properties(cib, get_the_CIB()); } } if (failed != NULL && xml_has_children(failed)) { add_node_copy(fragment, failed); } set_xml_property_copy(fragment, XML_ATTR_SECTION, section); set_xml_property_copy(fragment, "generated_on", cib_our_uname); return fragment; } gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib) { if(cib_compare_generation(newCib, oldCib) >= 0) { return TRUE; } crm_warn("Generation from update is older than the existing one"); return FALSE; } gboolean update_results( crm_data_t *failed, crm_data_t *target, int operation, int return_code) { gboolean was_error = FALSE; const char *error_msg = NULL; const char *operation_msg = NULL; crm_data_t *xml_node = NULL; operation_msg = cib_op2string(operation); if (return_code != cib_ok) { error_msg = cib_error2string(return_code); xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB); was_error = TRUE; add_node_copy(xml_node, target); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_ID, ID(target)); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target)); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_OP, operation_msg); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_REASON, error_msg); crm_warn("Action %s failed: %s (cde=%d)", operation_msg, error_msg, return_code); } else { crm_debug_3("CIB %s passed", operation_msg); } return was_error; } enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags) { enum cib_errors rc = cib_ok; char *revision = crm_element_value_copy( cib_update, XML_ATTR_CIB_REVISION); const char *cur_revision = crm_element_value( cib_copy, XML_ATTR_CIB_REVISION); crm_validate_data(cib_update); crm_validate_data(cib_copy); if(revision == NULL) { return cib_ok; } else if(cur_revision == NULL || strcmp(revision, cur_revision) > 0) { crm_info("Updating CIB revision to %s", revision); set_xml_property_copy( cib_copy, XML_ATTR_CIB_REVISION, revision); } else { /* make sure we end up with the right value in the end */ set_xml_property_copy( cib_update, XML_ATTR_CIB_REVISION, cur_revision); } if(strcmp(revision, cib_feature_revision_s) > 0) { CRM_DEV_ASSERT(cib_is_master == FALSE); CRM_DEV_ASSERT((flags & cib_scope_local) == 0); if(cib_is_master) { crm_err("Update uses an unsupported tag/feature:" " %s vs %s", revision, cib_feature_revision_s); rc = cib_revision_unsupported; } else if(flags & cib_scope_local) { /* an admin has forced a local change using a tag we * dont understand... ERROR */ crm_err("Local update uses an unsupported tag/feature:" " %s vs %s", revision, cib_feature_revision_s); rc = cib_revision_unsupported; } } crm_free(revision); return rc; } + + +enum cib_errors +sync_our_cib(HA_Message *request, gboolean all) +{ + enum cib_errors result = cib_ok; + const char *host = cl_get_string(request, F_CIB_HOST); + crm_data_t *sync_data = create_cib_fragment(the_cib, NULL); + HA_Message *replace_request = cib_msg_copy(request, FALSE); + + CRM_DEV_ASSERT(sync_data != NULL); + CRM_DEV_ASSERT(replace_request != NULL); + + crm_info("Syncing CIB to %s", all?"all peers":host); + if(host != NULL) { + ha_msg_add(replace_request, F_CIB_ISREPLY, host); + } + ha_msg_mod(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE); + ha_msg_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); + ha_msg_addstruct(replace_request, F_CIB_CALLDATA, sync_data); + + if(send_ha_message(hb_conn, replace_request, all?NULL:host) == FALSE) { + result = cib_not_connected; + } + ha_msg_del(replace_request); + free_xml(sync_data); + return result; +} diff --git a/crm/cib/notify.c b/crm/cib/notify.c index b9a57a635e..5bd9a074de 100644 --- a/crm/cib/notify.c +++ b/crm/cib/notify.c @@ -1,339 +1,337 @@ -/* $Id: notify.c,v 1.26 2005/06/02 09:44:01 andrew Exp $ */ +/* $Id: notify.c,v 1.27 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern GHashTable *client_list; int pending_updates = 0; void cib_notify_client(gpointer key, gpointer value, gpointer user_data); void attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib); void do_cib_notify( int options, const char *op, crm_data_t *update, enum cib_errors result, crm_data_t *result_data, const char *msg_type); void cib_notify_client(gpointer key, gpointer value, gpointer user_data) { IPC_Channel *ipc_client = NULL; HA_Message *update_msg = user_data; cib_client_t *client = value; const char *type = NULL; gboolean is_pre = FALSE; gboolean is_post = FALSE; gboolean is_confirm = FALSE; gboolean is_diff = FALSE; gboolean do_send = FALSE; int qlen = 0; int max_qlen = 0; CRM_DEV_ASSERT(client != NULL); CRM_DEV_ASSERT(update_msg != NULL); type = cl_get_string(update_msg, F_SUBTYPE); CRM_DEV_ASSERT(type != NULL); if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) { is_pre = TRUE; } else if(safe_str_eq(type, T_CIB_POST_NOTIFY)) { is_post = TRUE; } else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) { is_confirm = TRUE; } else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) { is_diff = TRUE; } if(client == NULL) { crm_warn("Skipping NULL client"); return; } else if(client->channel == NULL) { crm_warn("Skipping client with NULL channel"); return; } ipc_client = client->channel; qlen = ipc_client->send_queue->current_qlen; max_qlen = ipc_client->send_queue->max_qlen; if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { crm_debug("Skipping notification to disconnected" " client %s/%s", client->name, client->id); } else if(client->pre_notify && is_pre) { if(qlen < (int)(0.4 * max_qlen)) { do_send = TRUE; } else { crm_warn("Throttling pre-notifications due to" " high load: queue=%d (max=%d)", qlen, max_qlen); } } else if(client->post_notify && is_post) { if(qlen < (int)(0.7 * max_qlen)) { do_send = TRUE; } else { crm_warn("Throttling post-notifications due to" " extreme load: queue=%d (max=%d)", qlen, max_qlen); } } else if(client->diffs && is_diff) { if(qlen < (int)(0.8 * max_qlen)) { do_send = TRUE; } else { crm_warn("Throttling post-notifications due to" " extreme load: queue=%d (max=%d)", qlen, max_qlen); } /* these are critical */ } else if(client->confirmations && is_confirm) { do_send = TRUE; } if(do_send) { crm_debug_3("Notifying client %s/%s of update (queue=%d)", client->name, client->channel_name, qlen); if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) { /* We never want the CIB to exit because our client is slow */ crm_crit("%s-notification of client %s/%s failed - queue saturated", is_confirm?"Confirmation":is_post?"Post":"Pre", client->name, client->id); } else { HA_Message *msg_copy = ha_msg_copy(update_msg); if(crm_send_ipc_message( ipc_client, msg_copy, TRUE) == FALSE) { crm_warn("Notification of client %s/%s failed", client->name, client->id); } } } else { crm_debug_4("Client %s/%s not interested in %s notifications", client->name, client->channel_name, type); } } void cib_pre_notify( int options, const char *op, crm_data_t *existing, crm_data_t *update) { HA_Message *update_msg = NULL; const char *type = NULL; const char *id = NULL; if(options & cib_inhibit_notify) { crm_debug_2("Inhibiting notify."); return; } update_msg = ha_msg_new(6); if(update != NULL) { id = crm_element_value(update, XML_ATTR_ID); } ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY); ha_msg_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY); ha_msg_add(update_msg, F_CIB_OPERATION, op); if(id != NULL) { ha_msg_add(update_msg, F_CIB_OBJID, id); } if(update != NULL) { ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); } else if(existing != NULL) { ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing)); } type = cl_get_string(update_msg, F_CIB_OBJTYPE); attach_cib_generation(update_msg, "cib_generation", the_cib); if(existing != NULL) { add_message_xml(update_msg, F_CIB_EXISTING, existing); } if(update != NULL) { add_message_xml(update_msg, F_CIB_UPDATE, update); } g_hash_table_foreach(client_list, cib_notify_client, update_msg); if(update == NULL) { crm_debug_2("Performing operation %s (on section=%s)", op, type); } else { crm_debug_2("Performing %s on <%s%s%s>", op, type, id?" id=":"", id?id:""); } crm_msg_del(update_msg); } void cib_post_notify(int options, const char *op, crm_data_t *update, enum cib_errors result, crm_data_t *new_obj) { if(options & cib_inhibit_notify) { crm_debug_2("Inhibiting notify."); return; } do_cib_notify( options, op, update, result, new_obj, T_CIB_UPDATE_CONFIRM); } void cib_diff_notify(int options, const char *op, crm_data_t *update, enum cib_errors result, crm_data_t *diff) { do_cib_notify(options, op, update, result, diff, T_CIB_DIFF_NOTIFY); } void do_cib_notify( int options, const char *op, crm_data_t *update, enum cib_errors result, crm_data_t *result_data, const char *msg_type) { HA_Message *update_msg = NULL; - char *type = NULL; - char *id = NULL; + const char *type = NULL; + const char *id = NULL; if(options & cib_inhibit_notify) { crm_debug_2("Inhibiting notify."); return; } update_msg = ha_msg_new(8); - if(update != NULL && crm_element_value(result_data, XML_ATTR_ID) != NULL){ - id = crm_element_value_copy(result_data, XML_ATTR_ID); + if(result_data != NULL) { + id = crm_element_value(result_data, XML_ATTR_ID); } ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY); ha_msg_add(update_msg, F_SUBTYPE, msg_type); ha_msg_add(update_msg, F_CIB_OPERATION, op); ha_msg_add_int(update_msg, F_CIB_RC, result); if(id != NULL) { ha_msg_add(update_msg, F_CIB_OBJID, id); } if(update != NULL) { crm_debug_4("Setting type to update->name: %s", crm_element_name(update)); ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); - type = crm_strdup(crm_element_name(update)); + type = crm_element_name(update); } else if(result_data != NULL) { crm_debug_4("Setting type to new_obj->name: %s", crm_element_name(result_data)); ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data)); - type = crm_strdup(crm_element_name(result_data)); + type = crm_element_name(result_data); } else { crm_debug_4("Not Setting type"); } attach_cib_generation(update_msg, "cib_generation", the_cib); if(update != NULL) { add_message_xml(update_msg, F_CIB_UPDATE, update); } if(result_data != NULL) { add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data); } crm_debug_3("Notifying clients"); g_hash_table_foreach(client_list, cib_notify_client, update_msg); if(update == NULL) { if(result == cib_ok) { crm_debug_2("Operation %s (on section=%s) completed", op, crm_str(type)); } else { crm_warn("Operation %s (on section=%s) FAILED: (%d) %s", op, crm_str(type), result, cib_error2string(result)); } } else { if(result == cib_ok) { crm_debug_2("Completed %s of <%s %s%s>", op, crm_str(type), id?"id=":"", id?id:""); } else { crm_warn("%s of <%s %s%s> FAILED: %s", op,crm_str(type), id?"id=":"", id?id:"", cib_error2string(result)); } } - crm_free(id); - crm_free(type); crm_msg_del(update_msg); crm_debug_3("Notify complete"); } void attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib) { crm_data_t *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); if(a_cib != NULL) { copy_in_properties(generation, a_cib); } add_message_xml(msg, field, generation); free_xml(generation); } diff --git a/crm/cib/primatives.c b/crm/cib/primatives.c index 8f16b67d81..494617312d 100644 --- a/crm/cib/primatives.c +++ b/crm/cib/primatives.c @@ -1,597 +1,556 @@ -/* $Id: primatives.c,v 1.18 2005/05/31 14:50:46 andrew Exp $ */ +/* $Id: primatives.c,v 1.19 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * In case of confusion, this is the memory management policy for * all functions in this file. * * All add/modify functions use copies of supplied data. * It is therefore appropriate that the callers free the supplied data * at some point after the function has finished. * * All delete functions will handle the freeing of deleted data * but not the function arguments. */ void update_node_state(crm_data_t *existing_node, crm_data_t *update); /* --- Resource */ int addResource(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return add_cib_object(root, anXmlNode); } crm_data_t* findResource(crm_data_t *cib, const char *id) { crm_data_t *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_RESOURCES, cib); ret = find_entity(root, XML_CIB_TAG_RESOURCE, id); return ret; } int updateResource(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root = NULL; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); - return update_cib_object(root, anXmlNode, FALSE); + return update_cib_object(root, anXmlNode); } int delResource(crm_data_t *cib, crm_data_t *delete_spec) { const char *id = ID(delete_spec); crm_data_t *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return delete_cib_object(root, delete_spec); } /* --- Constraint */ int addConstraint(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return add_cib_object(root, anXmlNode); } crm_data_t* findConstraint(crm_data_t *cib, const char *id) { crm_data_t *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id); return ret; } int updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); - return update_cib_object(root, anXmlNode, FALSE); + return update_cib_object(root, anXmlNode); } int delConstraint(crm_data_t *cib, crm_data_t *delete_spec) { const char *id = ID(delete_spec); crm_data_t *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } /* --- HaNode */ int addHaNode(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); return add_cib_object(root, anXmlNode); } crm_data_t* findHaNode(crm_data_t *cib, const char *id) { crm_data_t *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_NODES, cib); ret = find_entity(root, XML_CIB_TAG_NODE, id); return ret; } int updateHaNode(crm_data_t *cib, cibHaNode *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); - return update_cib_object(root, anXmlNode, FALSE); + return update_cib_object(root, anXmlNode); } int delHaNode(crm_data_t *cib, crm_data_t *delete_spec) { const char *id = ID(delete_spec); crm_data_t *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } /* --- Status */ int addStatus(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return add_cib_object(root, anXmlNode); } crm_data_t* findStatus(crm_data_t *cib, const char *id) { crm_data_t *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_STATUS, cib); ret = find_entity(root, XML_CIB_TAG_STATE, id); return ret; } int updateStatus(crm_data_t *cib, crm_data_t *anXmlNode) { const char *id = ID(anXmlNode); crm_data_t *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); - return update_cib_object(root, anXmlNode, FALSE); + return update_cib_object(root, anXmlNode); } int delStatus(crm_data_t *cib, crm_data_t *delete_spec) { const char *id = ID(delete_spec); crm_data_t *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_STATE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return delete_cib_object(root, delete_spec); } int delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec) { const char *object_name = NULL; const char *object_id = NULL; crm_data_t *equiv_node = NULL; int result = cib_ok; if(delete_spec != NULL) { object_name = crm_element_name(delete_spec); } object_id = crm_element_value(delete_spec, XML_ATTR_ID); if(delete_spec == NULL) { result = cib_NOOBJECT; } else if(parent == NULL) { result = cib_NOPARENT; } else if(object_id == NULL) { /* placeholder object */ equiv_node = find_xml_node(parent, object_name, FALSE); } else { equiv_node = find_entity(parent, object_name, object_id); } -#if INTERMEDIATE_NOTIFICATIONS - cib_pre_notify(CRM_OP_CIB_DELETE, equiv_node, delete_spec); -#endif if(result != cib_ok) { ; /* nothing */ } else if(equiv_node == NULL) { result = cib_NOTEXISTS; } else if(xml_has_children(delete_spec)) { /* only leaves are deleted */ zap_xml_from_parent(parent, equiv_node); } else { xml_child_iter( delete_spec, child, NULL, int tmp_result = delete_cib_object(equiv_node, child); /* only the first error is likely to be interesting */ if(tmp_result != cib_ok && result == cib_ok) { result = tmp_result; } ); } -#if INTERMEDIATE_NOTIFICATIONS - cib_post_notify(CRM_OP_CIB_DELETE, delete_spec, result, equiv_node); -#endif - return result; } int add_cib_object(crm_data_t *parent, crm_data_t *new_obj) { enum cib_errors result = cib_ok; const char *object_name = NULL; const char *object_id = NULL; crm_data_t *equiv_node = NULL; if(new_obj != NULL) { object_name = crm_element_name(new_obj); } object_id = crm_element_value(new_obj, XML_ATTR_ID); if(new_obj == NULL) { result = cib_NOOBJECT; } else if(parent == NULL) { result = cib_NOPARENT; } else if(object_id == NULL) { /* placeholder object */ equiv_node = find_xml_node(parent, object_name, FALSE); } else { equiv_node = find_entity(parent, object_name, object_id); } -#if INTERMEDIATE_NOTIFICATIONS - cib_pre_notify(CRM_OP_CIB_CREATE, equiv_node, new_obj); -#endif if(result != cib_ok) { ; /* do nothing */ } else if(equiv_node != NULL) { result = cib_EXISTS; } else if(add_node_copy(parent, new_obj) == NULL) { result = cib_NODECOPY; } - -#if INTERMEDIATE_NOTIFICATIONS - cib_post_notify(CRM_OP_CIB_CREATE, new_obj, result, new_obj); -#endif return result; } int -update_cib_object(crm_data_t *parent, crm_data_t *new_obj, gboolean force) +update_cib_object(crm_data_t *parent, crm_data_t *update) { const char *replace = NULL; const char *object_name = NULL; - char *object_id = NULL; - crm_data_t *equiv_node = NULL; + const char *object_id = NULL; + crm_data_t *target = NULL; int result = cib_ok; - - if(new_obj != NULL) { - object_name = crm_element_name(new_obj); - if(crm_element_value(new_obj, XML_ATTR_ID) != NULL){ - object_id = crm_element_value_copy(new_obj,XML_ATTR_ID); - } - } - if(new_obj == NULL) { - result = cib_NOOBJECT; + CRM_DEV_ASSERT(update != NULL); + if(crm_assert_failed) { return cib_NOOBJECT; } - } else if(parent == NULL) { - result = cib_NOPARENT; + CRM_DEV_ASSERT(parent != NULL); + if(crm_assert_failed) { return cib_NOPARENT; } - } else if(object_id == NULL) { + object_name = crm_element_name(update); + object_id = ID(update); + + CRM_DEV_ASSERT(object_name != NULL); + if(crm_assert_failed) { return cib_NOOBJECT; } + + if(object_id == NULL) { /* placeholder object */ - equiv_node = find_xml_node(parent, object_name, FALSE); + target = find_xml_node(parent, object_name, FALSE); } else { - equiv_node = find_entity(parent, object_name, object_id); + target = find_entity(parent, object_name, object_id); } -#if INTERMEDIATE_NOTIFICATIONS - cib_pre_notify(CRM_OP_CIB_UPDATE, equiv_node, new_obj); -#endif - if(result != cib_ok) { - ; /* nothing */ - - } else if(equiv_node == NULL) { - crm_debug_2("No node to update, creating %s instead", - crm_element_name(new_obj)); - if(parent == NULL) { - crm_err("Failed to add <%s id=%s> (NULL parent)", - object_name, object_id); - result = cib_NODECOPY; - - } else if(add_node_copy(parent, new_obj) == NULL) { - crm_err("Failed to add <%s id=%s>", - crm_str(object_name), crm_str(object_id)); - result = cib_NODECOPY; - } else { - crm_debug_2("Added <%s id=%s>", - crm_str(object_name), crm_str(object_id)); - - if(object_id == NULL) { - /* placeholder object */ - equiv_node = find_xml_node( - parent, object_name, TRUE); - - } else { - equiv_node = find_entity( - parent, object_name, object_id); - } - } - - } else { - crm_debug_2("Found node <%s id=%s> to update", + if(target == NULL) { + target = add_node_copy(parent, update); + crm_debug_2("Added <%s id=%s>", crm_str(object_name), crm_str(object_id)); - replace = crm_element_value(new_obj, XML_CIB_ATTR_REPLACE); + CRM_DEV_ASSERT(target != NULL); + if(crm_assert_failed) { return cib_NODECOPY; } + + return cib_ok; - if(replace != NULL) { - crm_data_t *remove = find_xml_node( - equiv_node, replace, FALSE); - if(remove != NULL) { - crm_debug_3("Replacing node <%s> in <%s>", - replace, crm_element_name(equiv_node)); - zap_xml_from_parent(equiv_node, remove); - } - xml_remove_prop(new_obj, XML_CIB_ATTR_REPLACE); - xml_remove_prop(equiv_node, XML_CIB_ATTR_REPLACE); + } + + crm_debug_2("Found node <%s id=%s> to update", + crm_str(object_name), crm_str(object_id)); + + replace = crm_element_value(update, XML_CIB_ATTR_REPLACE); + + if(replace != NULL) { + crm_data_t *remove = find_xml_node(target, replace, FALSE); + if(remove != NULL) { + crm_debug_3("Replacing node <%s> in <%s>", + replace, crm_element_name(target)); + zap_xml_from_parent(target, remove); } + xml_remove_prop(update, XML_CIB_ATTR_REPLACE); + xml_remove_prop(target, XML_CIB_ATTR_REPLACE); + } + + if(safe_str_eq(XML_CIB_TAG_STATE, object_name)){ + update_node_state(target, update); - if(safe_str_eq(XML_CIB_TAG_STATE, object_name)){ - update_node_state(equiv_node, new_obj); - - } else { - copy_in_properties(equiv_node, new_obj); - } + } else { + copy_in_properties(target, update); + } - crm_debug_3("Processing children of <%s id=%s>", - crm_str(object_name), crm_str(object_id)); + CRM_DEV_ASSERT(cl_is_allocated(object_name)); + if(object_id != NULL) { + CRM_DEV_ASSERT(cl_is_allocated(object_id)); + } + + crm_debug_3("Processing children of <%s id=%s>", + crm_str(object_name), crm_str(object_id)); + + xml_child_iter( + update, a_child, NULL, + int tmp_result = 0; + crm_debug_3("Updating child <%s id=%s>", + crm_element_name(a_child), ID(a_child)); - xml_child_iter( - new_obj, a_child, NULL, - int tmp_result = 0; - crm_debug_3("Updating child <%s id=%s>", - crm_element_name(a_child), - crm_element_value(a_child, XML_ATTR_ID)); + tmp_result = update_cib_object(target, a_child); + + /* only the first error is likely to be interesting */ + if(tmp_result != cib_ok) { + crm_err("Error updating child <%s id=%s>", + crm_element_name(a_child), ID(a_child)); - tmp_result = - update_cib_object(equiv_node, a_child, force); - - /* only the first error is likely to be interesting */ - if(tmp_result != cib_ok) { - crm_err("Error updating child <%s id=%s>", - crm_element_name(a_child), - crm_element_value(a_child, XML_ATTR_ID)); - - if(result == cib_ok) { - result = tmp_result; - } + if(result == cib_ok) { + result = tmp_result; } - ); - - } + } + ); + crm_debug_3("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id)); - -#if INTERMEDIATE_NOTIFICATIONS - cib_post_notify(CRM_OP_CIB_UPDATE, new_obj, result, equiv_node); -#endif - crm_free(object_id); + return result; } void update_node_state(crm_data_t *target, crm_data_t *update) { const char *source = NULL; gboolean any_updates = FALSE; gboolean clear_stonith = FALSE; gboolean clear_shutdown = FALSE; xml_prop_iter( update, local_prop_name, local_prop_value, if(local_prop_name == NULL) { /* error */ } else if(strcmp(local_prop_name, XML_ATTR_ID) == 0) { } else if(strcmp(local_prop_name, XML_ATTR_TSTAMP) == 0) { } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_SHUTDOWN) == 0) { clear_shutdown = TRUE; } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_STONITH) == 0) { clear_stonith = TRUE; clear_shutdown = TRUE; } else if(strcmp(local_prop_name, XML_CIB_ATTR_SOURCE) == 0) { source = local_prop_value; } else { any_updates = TRUE; set_xml_property_copy( target, local_prop_name, local_prop_value); } ); xml_remove_prop(target, XML_CIB_ATTR_CLEAR_SHUTDOWN); if(clear_shutdown) { /* unset XML_CIB_ATTR_SHUTDOWN */ crm_debug_2("Clearing %s", XML_CIB_ATTR_SHUTDOWN); xml_remove_prop(target, XML_CIB_ATTR_SHUTDOWN); any_updates = TRUE; } xml_remove_prop(target, XML_CIB_ATTR_CLEAR_STONITH); if(clear_stonith) { /* unset XML_CIB_ATTR_STONITH */ crm_debug_2("Clearing %s", XML_CIB_ATTR_STONITH); xml_remove_prop(target, XML_CIB_ATTR_STONITH); any_updates = TRUE; } if(any_updates) { set_node_tstamp(target); set_xml_property_copy(target, XML_CIB_ATTR_SOURCE, source); } } diff --git a/crm/crmd/cib.c b/crm/crmd/cib.c index 0282e084f8..0ffaba6b8f 100644 --- a/crm/crmd/cib.c +++ b/crm/crmd/cib.c @@ -1,280 +1,280 @@ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /* for access */ #include #include #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include #include #include #include #include #include struct crm_subsystem_s *cib_subsystem = NULL; int cib_retries = 0; /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; if(action & stop_actions) { if(fsa_cib_conn != NULL && fsa_cib_conn->state != cib_disconnected) { fsa_cib_conn->cmds->signoff(fsa_cib_conn); } } if(action & start_actions) { if(cur_state != S_STOPPING) { if(fsa_cib_conn == NULL) { fsa_cib_conn = cib_new(); } if(cib_ok != fsa_cib_conn->cmds->signon( fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command)){ crm_debug("Could not connect to the CIB service"); #if 0 } else if(cib_ok != fsa_cib_conn->cmds->set_op_callback( fsa_cib_conn, crmd_cib_op_callback)) { crm_err("Could not set op callback"); #endif } else if(fsa_cib_conn->cmds->set_connection_dnotify( fsa_cib_conn, crmd_cib_connection_destroy)!=cib_ok){ crm_err("Could not set dnotify callback"); } else { set_bit_inplace( fsa_input_register, R_CIB_CONNECTED); } if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { cib_retries++; crm_warn("Couldn't complete CIB registration %d" " times... pause and retry", cib_retries); if(cib_retries < 30) { crm_timer_start(wait_timer); crmd_fsa_stall(NULL); } else { crm_err("Could not complete CIB" " registration %d times..." " hard error", cib_retries); register_fsa_error( C_FSA_INTERNAL, I_ERROR, NULL); } } else { cib_retries = 0; } } else { crm_info("Ignoring request to start %s after shutdown", this_subsys->name); } } return result; } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { HA_Message *answer = NULL; enum crmd_fsa_input result = I_NULL; ha_msg_input_t *cib_msg = fsa_typed_data(fsa_dt_ha_msg); const char *sys_from = cl_get_string(cib_msg->msg, F_CRM_SYS_FROM); if(fsa_cib_conn->state == cib_disconnected) { if(cur_state != S_STOPPING) { crm_err("CIB is disconnected"); crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg); return I_NULL; } crm_info("CIB is disconnected"); crm_log_message_adv(LOG_DEBUG, "CIB Input", cib_msg->msg); return I_NULL; } if(action & A_CIB_INVOKE) { if(safe_str_eq(sys_from, CRM_SYSTEM_CRMD)) { action = A_CIB_INVOKE_LOCAL; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { action = A_CIB_INVOKE_LOCAL; } } if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) { int call_options = 0; enum cib_errors rc = cib_ok; crm_data_t *cib_frag = NULL; const char *section = NULL; const char *op = cl_get_string(cib_msg->msg, F_CRM_TASK); section = cl_get_string(cib_msg->msg, F_CIB_SECTION); ha_msg_value_int(cib_msg->msg, F_CIB_CALLOPTS, &call_options); crm_log_message(LOG_MSG, cib_msg->msg); crm_log_xml_debug_3(cib_msg->xml, "[CIB update]"); if(op == NULL) { crm_err("Invalid CIB Message"); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return I_NULL; } cib_frag = NULL; rc = fsa_cib_conn->cmds->variant_op( fsa_cib_conn, op, NULL, section, cib_msg->xml, &cib_frag, call_options); if(rc < cib_ok || (action & A_CIB_INVOKE)) { answer = create_reply(cib_msg->msg, cib_frag); ha_msg_add(answer,XML_ATTR_RESULT,cib_error2string(rc)); } if(action & A_CIB_INVOKE) { if(relay_message(answer, TRUE) == FALSE) { crm_err("Confused what to do with cib result"); crm_log_message(LOG_ERR, answer); crm_msg_del(answer); result = I_ERROR; } } else if(rc < cib_ok) { ha_msg_input_t *input = NULL; crm_err("Internal CRM/CIB command from %s() failed: %s", msg_data->origin, cib_error2string(rc)); crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg); crm_log_message_adv(LOG_WARNING, "CIB Reply", answer); input = new_ha_msg_input(answer); register_fsa_input(C_FSA_INTERNAL, I_ERROR, input); crm_msg_del(answer); delete_ha_msg_input(input); } return result; } else { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return I_NULL; } /* frees fragment as part of delete_ha_msg_input() */ void update_local_cib_adv( crm_data_t *msg_data, gboolean do_now, const char *raised_from) { HA_Message *msg = NULL; ha_msg_input_t *fsa_input = NULL; int call_options = cib_quorum_override|cib_scope_local; CRM_DEV_ASSERT(msg_data != NULL); crm_malloc0(fsa_input, sizeof(ha_msg_input_t)); - msg = create_request(CRM_OP_CIB_UPDATE, msg_data, NULL, + msg = create_request(CIB_OP_UPDATE, msg_data, NULL, CRM_SYSTEM_CIB, CRM_SYSTEM_CRMD, NULL); ha_msg_add(msg, F_CIB_SECTION, crm_element_value(msg_data, XML_ATTR_SECTION)); ha_msg_add_int(msg, F_CIB_CALLOPTS, call_options); ha_msg_add(msg, "call_origin", raised_from); fsa_input->msg = msg; fsa_input->xml = msg_data; if(AM_I_DC && crm_assert_failed) { /* register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); */ } if(do_now == FALSE) { crm_debug_3("Registering event with FSA"); register_fsa_input_adv(C_FSA_INTERNAL, I_CIB_OP, fsa_input, 0, FALSE, raised_from); } else { fsa_data_t *op_data = NULL; crm_debug_3("Invoking CIB handler directly"); crm_malloc0(op_data, sizeof(fsa_data_t)); op_data->fsa_cause = C_FSA_INTERNAL; op_data->fsa_input = I_CIB_OP; op_data->origin = raised_from; op_data->data = fsa_input; op_data->data_type = fsa_dt_ha_msg; do_cib_invoke(A_CIB_INVOKE_LOCAL, C_FSA_INTERNAL, fsa_state, I_CIB_OP, op_data); crm_free(op_data); crm_debug_3("CIB handler completed"); } crm_debug_3("deleting input"); crm_msg_del(fsa_input->msg); free_xml(fsa_input->xml); crm_free(fsa_input); crm_debug_3("deleted input"); } diff --git a/include/crm/cib.h b/include/crm/cib.h index b55e3f0642..b124e9dca6 100644 --- a/include/crm/cib.h +++ b/include/crm/cib.h @@ -1,308 +1,343 @@ -/* $Id: cib.h,v 1.25 2005/05/31 11:43:56 andrew Exp $ */ +/* $Id: cib.h,v 1.26 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CIB__H #define CIB__H #include #include #include #include #define cib_feature_revision 1 #define cib_feature_revision_s "1" enum cib_variant { cib_native, cib_database, cib_edir }; enum cib_state { cib_connected_command, cib_connected_query, cib_disconnected }; enum cib_conn_type { cib_command, cib_query, cib_no_connection }; enum cib_call_options { cib_none = 0x00000000, cib_verbose = 0x00000001, cib_discard_reply = 0x00000010, cib_scope_local = 0x00000100, cib_sync_call = 0x00001000, cib_inhibit_notify = 0x00010000, cib_quorum_override = 0x00100000, - cib_inhibit_bcast = 0x01000000 + cib_inhibit_bcast = 0x01000000, + cib_force_diff = 0x10000000 }; #define cib_default_options = cib_none enum cib_errors { cib_ok = 0, cib_operation = -1, cib_create_msg = -2, cib_not_connected = -3, cib_not_authorized = -4, cib_send_failed = -5, cib_reply_failed = -6, cib_return_code = -7, cib_output_ptr = -8, cib_output_data = -9, cib_connection = -10, cib_authentication = -11, cib_missing = -12, cib_variant = -28, CIBRES_MISSING_ID = -13, CIBRES_MISSING_TYPE = -14, CIBRES_MISSING_FIELD = -15, CIBRES_OBJTYPE_MISMATCH = -16, CIBRES_CORRUPT = -17, CIBRES_OTHER = -18, cib_unknown = -19, cib_STALE = -20, cib_EXISTS = -21, cib_NOTEXISTS = -22, cib_ACTIVATION = -23, cib_NOSECTION = -24, cib_NOOBJECT = -25, cib_NOPARENT = -26, cib_NODECOPY = -27, cib_NOTSUPPORTED = -29, cib_registration_msg = -30, cib_callback_token = -31, cib_callback_register = -32, cib_msg_field_add = -33, cib_client_gone = -34, cib_not_master = -35, cib_client_corrupt = -36, cib_master_timeout = -37, cib_revision_unsupported= -38, cib_revision_unknown = -39, cib_missing_data = -40, cib_remote_timeout = -41, - cib_no_quorum = -42 + cib_no_quorum = -42, + cib_diff_failed = -43, + cib_diff_resync = -44, + cib_old_data = -45 }; -enum cib_op { - CIB_OP_NONE = 0, - CIB_OP_ADD, - CIB_OP_MODIFY, - CIB_OP_DELETE, - CIB_OP_MAX +enum cib_update_op { + CIB_UPDATE_OP_NONE = 0, + CIB_UPDATE_OP_ADD, + CIB_UPDATE_OP_MODIFY, + CIB_UPDATE_OP_DELETE, + CIB_UPDATE_OP_MAX }; enum cib_section { cib_section_none, cib_section_all, cib_section_nodes, cib_section_constraints, cib_section_resources, cib_section_crmconfig, cib_section_status }; +#define CIB_OP_SLAVE "cib_slave" +#define CIB_OP_SLAVEALL "cib_slave_all" +#define CIB_OP_MASTER "cib_master" +#define CIB_OP_SYNC "cib_sync" +#define CIB_OP_SYNC_ONE "cib_sync_one" +#define CIB_OP_ISMASTER "cib_ismaster" +#define CIB_OP_BUMP "cib_bump" +#define CIB_OP_QUERY "cib_query" +#define CIB_OP_CREATE "cib_create" +#define CIB_OP_UPDATE "cib_update" +#define CIB_OP_DELETE "cib_delete" +#define CIB_OP_ERASE "cib_erase" +#define CIB_OP_REPLACE "cib_replace" +#define CIB_OP_NOTIFY "cib_notify" +#define CIB_OP_APPLY_DIFF "cib_apply_diff" + #define F_CIB_CLIENTID "cib_clientid" #define F_CIB_CALLOPTS "cib_callopt" #define F_CIB_CALLID "cib_callid" #define F_CIB_CALLDATA "cib_calldata" #define F_CIB_OPERATION "cib_op" #define F_CIB_ISREPLY "cib_isreplyto" #define F_CIB_SECTION "cib_section" #define F_CIB_HOST "cib_host" #define F_CIB_RC "cib_rc" #define F_CIB_DELEGATED "cib_delegated_from" #define F_CIB_OBJID "cib_object" #define F_CIB_OBJTYPE "cib_object_type" #define F_CIB_EXISTING "cib_existing_object" #define F_CIB_SEENCOUNT "cib_seen" #define F_CIB_TIMEOUT "cib_timeout" #define F_CIB_UPDATE "cib_update" #define F_CIB_CALLBACK_TOKEN "cib_callback_token" #define F_CIB_GLOBAL_UPDATE "cib_update" #define F_CIB_UPDATE_RESULT "cib_update_result" #define F_CIB_CLIENTNAME "cib_clientname" #define F_CIB_NOTIFY_TYPE "cib_notify_type" #define F_CIB_NOTIFY_ACTIVATE "cib_notify_activate" +#define F_CIB_UPDATE_DIFF "cib_update_diff" #define T_CIB "cib" #define T_CIB_NOTIFY "cib_notify" /* notify sub-types */ #define T_CIB_PRE_NOTIFY "cib_pre_notify" #define T_CIB_POST_NOTIFY "cib_post_notify" #define T_CIB_UPDATE_CONFIRM "cib_update_confirmation" #define T_CIB_DIFF_NOTIFY "cib_diff_notify" #define cib_channel_ro "cib_ro" #define cib_channel_rw "cib_rw" #define cib_channel_callback "cib_callback" typedef struct cib_s cib_t; typedef struct cib_api_operations_s { int (*variant_op)( cib_t *cib, const char *op, const char *host, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*signon) ( cib_t *cib, const char *name, enum cib_conn_type type); int (*signoff)(cib_t *cib); int (*free) (cib_t *cib); int (*set_op_callback)( cib_t *cib, void (*callback)( const HA_Message *msg, int callid , int rc, crm_data_t *output)); int (*add_notify_callback)( cib_t *cib, const char *event, void (*callback)( const char *event, HA_Message *msg)); int (*del_notify_callback)( cib_t *cib, const char *event, void (*callback)( const char *event, HA_Message *msg)); int (*set_connection_dnotify)( cib_t *cib, void (*dnotify)(gpointer user_data)); IPC_Channel *(*channel)(cib_t* cib); int (*inputfd)(cib_t* cib); int (*noop)(cib_t *cib, int call_options); int (*ping)( cib_t *cib, crm_data_t **output_data, int call_options); int (*query)(cib_t *cib, const char *section, crm_data_t **output_data, int call_options); int (*query_from)( cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options); int (*is_master) (cib_t *cib); int (*set_master)(cib_t *cib, int call_options); int (*set_slave) (cib_t *cib, int call_options); int (*set_slave_all)(cib_t *cib, int call_options); int (*sync)(cib_t *cib, const char *section, int call_options); int (*sync_from)( cib_t *cib, const char *host, const char *section, int call_options); int (*bump_epoch)(cib_t *cib, int call_options); int (*create)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int (*modify)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int (*replace)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int (*delete)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int (*erase)( cib_t *cib, crm_data_t **output_data, int call_options); int (*quit)(cib_t *cib, int call_options); gboolean (*msgready)(cib_t* cib); int (*rcvmsg)(cib_t* cib, int blocking); gboolean (*dispatch)(IPC_Channel *channel, gpointer user_data); int (*register_callback)( cib_t* cib, const char *callback, int enabled); } cib_api_operations_t; struct cib_s { enum cib_state state; enum cib_conn_type type; int call_id; int call_timeout; void *variant_opaque; GList *notify_list; void (*op_callback)(const HA_Message *msg, int call_id, int rc, crm_data_t *output); cib_api_operations_t *cmds; }; typedef struct cib_notify_client_s { const char *event; const char *obj_id; /* implement one day */ const char *obj_type; /* implement one day */ void (*callback)( const char *event, HA_Message *msg); } cib_notify_client_t; typedef struct cib_callback_client_s { void (*callback)( const HA_Message*, int, int, crm_data_t*, void*); void *user_data; gboolean only_success; } cib_callback_client_t; /* Core functions */ extern cib_t *cib_new(void); extern gboolean startCib(const char *filename); extern crm_data_t *get_cib_copy(cib_t *cib); extern crm_data_t *cib_get_generation(cib_t *cib); extern int cib_compare_generation(crm_data_t *left, crm_data_t *right); extern 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*)); extern void remove_cib_op_callback(int call_id, gboolean all_callbacks); extern int num_cib_op_callbacks(void); /* Utility functions */ extern crm_data_t *get_object_root(const char *object_type,crm_data_t *the_root); extern crm_data_t *create_cib_fragment_adv( crm_data_t *update, const char *section, const char *source); extern char *cib_pluralSection(const char *a_section); extern const char *get_crm_option( crm_data_t *cib, const char *name, gboolean do_warn); /* Error Interpretation*/ extern const char *cib_error2string(enum cib_errors); -extern const char *cib_op2string(enum cib_op); +extern const char *cib_op2string(enum cib_update_op); extern crm_data_t *createEmptyCib(void); extern gboolean verifyCibXml(crm_data_t *cib); extern int cib_section2enum(const char *a_section); #define create_cib_fragment(update,section) create_cib_fragment_adv(update, section, __FUNCTION__) +extern crm_data_t *diff_cib_object( + crm_data_t *old, crm_data_t *new,gboolean suppress); + +extern gboolean apply_cib_diff( + crm_data_t *old, crm_data_t *diff, crm_data_t **new); + +extern void log_cib_diff(int log_level, crm_data_t *diff, const char *function); + +extern gboolean cib_diff_version_details( + crm_data_t *diff, int *admin_epoche, int *epoche, int *updates, + int *_admin_epoche, int *_epoche, int *_updates); + +extern gboolean cib_version_details( + crm_data_t *cib, int *admin_epoche, int *epoche, int *updates); #endif diff --git a/include/crm/crm.h b/include/crm/crm.h index 9df44067bb..c22c9e5930 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,306 +1,292 @@ -/* $Id: crm.h,v 1.64 2005/05/31 11:43:56 andrew Exp $ */ +/* $Id: crm.h,v 1.65 2005/06/13 11:54:53 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRM__H #define CRM__H #include #include #include #include #include #include #ifdef MCHECK #include #endif #include #ifndef CRM_DEV_BUILD # define CRM_DEV_BUILD 0 #endif #define ipc_call_diff_max_ms 5000 #define action_diff_warn_ms 5000 #define action_diff_max_ms 20000 #define fsa_diff_warn_ms 10000 #define fsa_diff_max_ms 30000 #include #define CRM_ASSERT(expr) if((expr) == FALSE) { \ do_crm_log(LOG_CRIT, __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ abort(); \ } extern gboolean crm_assert_failed; #define CRM_DEV_ASSERT(expr) crm_assert_failed = FALSE; \ if((expr) == FALSE) { \ crm_assert_failed = TRUE; \ do_crm_log(CRM_DEV_BUILD?LOG_CRIT:LOG_ERR, \ __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ if(CRM_DEV_BUILD) { \ abort(); \ } \ } /* Clean these up at some point, some probably should be runtime options */ #define WORKING_DIR HA_VARLIBDIR"/heartbeat/crm" #define BIN_DIR HA_LIBDIR"/heartbeat" #define SOCKET_LEN 1024 #define APPNAME_LEN 256 #define MAX_IPC_FAIL 5 #define CIB_FILENAME WORKING_DIR"/cib.xml" #define CIB_BACKUP WORKING_DIR"/cib_backup.xml" #define CRM_VERSION "0.8" #define MSG_LOG 1 #define DOT_FSA_ACTIONS 1 #define DOT_ALL_FSA_INPUTS 1 /* #define FSA_TRACE 1 */ #define INFINITY_S "INFINITY" #define MINUS_INFINITY_S "-INFINITY" #define INFINITY 1000000.0 /* Sub-systems */ #define CRM_SYSTEM_DC "dc" #define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ #define CRM_SYSTEM_CIB "cib" #define CRM_SYSTEM_CRMD "crmd" #define CRM_SYSTEM_LRMD "lrmd" #define CRM_SYSTEM_PENGINE "pengine" #define CRM_SYSTEM_TENGINE "tengine" /* Valid operations */ #define CRM_OP_NOOP "noop" -/* soon to be moved to cib.h */ -#define CRM_OP_CIB_SLAVE "cib_slave" -#define CRM_OP_CIB_SLAVEALL "cib_slave_all" -#define CRM_OP_CIB_MASTER "cib_master" -#define CRM_OP_CIB_SYNC "cib_sync" -#define CRM_OP_CIB_ISMASTER "cib_ismaster" -#define CRM_OP_CIB_BUMP "cib_bump" -#define CRM_OP_CIB_QUERY "cib_query" -#define CRM_OP_CIB_CREATE "cib_create" -#define CRM_OP_CIB_UPDATE "cib_update" -#define CRM_OP_CIB_DELETE "cib_delete" -#define CRM_OP_CIB_ERASE "cib_erase" -#define CRM_OP_CIB_REPLACE "cib_replace" -#define CRM_OP_CIB_NOTIFY "cib_notify" - #define CRM_OP_JOIN_ANNOUNCE "join_announce" #define CRM_OP_JOIN_OFFER "join_offer" #define CRM_OP_JOIN_REQUEST "join_request" #define CRM_OP_JOIN_ACKNAK "join_ack_nack" #define CRM_OP_JOIN_CONFIRM "join_confirm" #define CRM_OP_DIE "die_no_respawn" #define CRM_OP_RETRIVE_CIB "retrieve_cib" #define CRM_OP_PING "ping" #define CRM_OP_VOTE "vote" #define CRM_OP_HELLO "hello" #define CRM_OP_HBEAT "dc_beat" #define CRM_OP_PECALC "pe_calc" #define CRM_OP_ABORT "abort" #define CRM_OP_QUIT "quit" #define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" #define CRM_OP_SHUTDOWN_REQ "req_shutdown" #define CRM_OP_SHUTDOWN "do_shutdown" #define CRM_OP_FENCE "stonith" #define CRM_OP_EVENTCC "event_cc" #define CRM_OP_TEABORT "te_abort" #define CRM_OP_TEABORTED "te_abort_confirmed" /* we asked */ #define CRM_OP_TE_HALT "te_halt" #define CRM_OP_TECOMPLETE "te_complete" #define CRM_OP_TETIMEOUT "te_timeout" #define CRM_OP_TRANSITION "transition" #define CRM_OP_REGISTER "register" #define CRM_OP_DEBUG_UP "debug_inc" #define CRM_OP_DEBUG_DOWN "debug_dec" #define CRMD_STATE_ACTIVE "member" #define CRMD_STATE_INACTIVE "down" #define CRMD_JOINSTATE_DOWN "down" #define CRMD_JOINSTATE_PENDING "pending" #define CRMD_JOINSTATE_MEMBER "member" #define CRMD_ACTION_START "start" #define CRMD_ACTION_STARTED "running" #define CRMD_ACTION_START_FAIL "start_failed" #define CRMD_ACTION_START_PENDING "starting" #define CRMD_ACTION_STOP "stop" #define CRMD_ACTION_STOPPED "stopped" #define CRMD_ACTION_STOP_FAIL "stop_failed" #define CRMD_ACTION_STOP_PENDING "stopping" #define CRMD_ACTION_MON "monitor" #define CRMD_ACTION_MON_PENDING CRMD_ACTION_STARTED #define CRMD_ACTION_MON_OK CRMD_ACTION_STARTED #define CRMD_ACTION_MON_FAIL "monitor_failed" /* #define CRMD_ACTION_GENERIC "pending" */ #define CRMD_ACTION_GENERIC_PENDING "pending" #define CRMD_ACTION_GENERIC_OK "complete" #define CRMD_ACTION_GENERIC_FAIL "pending_failed" typedef GList* GListPtr; #define crm_atoi(text, default) atoi(text?text:default) extern gboolean safe_str_eq(const char *a, const char *b); extern gboolean safe_str_neq(const char *a, const char *b); #define slist_iter(child, child_type, parent, counter, a) \ { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ int counter = 0; \ for(; __crm_iter_head != NULL; counter++) { \ child = __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ } #define LOG_DEBUG_2 LOG_DEBUG+1 #define LOG_DEBUG_3 LOG_DEBUG+2 #define LOG_DEBUG_4 LOG_DEBUG+3 #define LOG_DEBUG_5 LOG_DEBUG+4 #define LOG_DEBUG_6 LOG_DEBUG+5 #define LOG_MSG LOG_DEBUG_3 #define crm_crit(w...) do_crm_log(LOG_CRIT, __FILE__, __FUNCTION__, w) #define crm_err(w...) do_crm_log(LOG_ERR, __FILE__, __FUNCTION__, w) #define crm_warn(w...) do_crm_log(LOG_WARNING, __FILE__, __FUNCTION__, w) #define crm_notice(w...) do_crm_log(LOG_NOTICE, __FILE__, __FUNCTION__, w) #define crm_info(w...) do_crm_log(LOG_INFO, __FILE__, __FUNCTION__, w) #define crm_log_maybe(level, fmt...) if(crm_log_level >= level) { \ do_crm_log(level, __FILE__, __FUNCTION__, fmt); \ } #define crm_debug(fmt...) crm_log_maybe(LOG_DEBUG, fmt) #define crm_debug_2(fmt...) crm_log_maybe(LOG_DEBUG_2, fmt) /* If this is not a developmental build, give the compiler every chance to * optimize these away */ #if CRM_DEV_BUILD # define crm_debug_3(fmt...) crm_log_maybe(LOG_DEBUG_3, fmt) # define crm_debug_4(fmt...) crm_log_maybe(LOG_DEBUG_4, fmt) # define crm_debug_5(fmt...) crm_log_maybe(LOG_DEBUG_5, fmt) #else # define crm_debug_3(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_debug_4(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_debug_5(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } #endif extern void crm_log_message_adv( int level, const char *alt_debugfile, const HA_Message *msg); #define crm_log_message(level, msg) if(crm_log_level >= level) { \ crm_log_message_adv(level, NULL, msg); \ } #define crm_do_action(level, actions) if(crm_log_level >= level) { \ actions; \ } #define crm_action_info(x) crm_do_action(LOG_INFO, x) #define crm_action_debug(x) crm_do_action(LOG_DEBUG, x) #define crm_action_debug_2(x) crm_do_action(LOG_DEBUG_2, x) #define crm_action_debug_3(x) crm_do_action(LOG_DEBUG_3, x) +#define crm_action_debug_4(x) crm_do_action(LOG_DEBUG_4, x) #define crm_log_xml(level, text, xml) if(crm_log_level >= level) { \ print_xml_formatted(level, __FUNCTION__, xml, text); \ } #define crm_log_xml_crit(xml, text) crm_log_xml(LOG_CRIT, text, xml) #define crm_log_xml_err(xml, text) crm_log_xml(LOG_ERR, text, xml) #define crm_log_xml_warn(xml, text) crm_log_xml(LOG_WARNING, text, xml) #define crm_log_xml_notice(xml, text) crm_log_xml(LOG_NOTICE, text, xml) #define crm_log_xml_info(xml, text) crm_log_xml(LOG_INFO, text, xml) #define crm_log_xml_debug(xml, text) crm_log_xml(LOG_DEBUG, text, xml) #define crm_log_xml_debug_2(xml, text) crm_log_xml(LOG_DEBUG_2, text, xml) #define crm_log_xml_debug_3(xml, text) crm_log_xml(LOG_DEBUG_3, text, xml) #define crm_log_xml_debug_4(xml, text) crm_log_xml(LOG_DEBUG_4, text, xml) #define crm_log_xml_debug_5(xml, text) crm_log_xml(LOG_DEBUG_5, text, xml) #define crm_str(x) (const char*)(x?x:"") #if CRM_USE_MALLOC # define crm_malloc0(new_obj,length) \ { \ new_obj = malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ exit(1); \ } else { \ memset(new_obj, 0, length); \ } \ } # define crm_free(x) if(x) { free(x); x=NULL; } # define crm_is_allocated(obj) obj?TRUE:FALSE #else # if CRM_DEV_BUILD # define crm_malloc0(new_obj,length) \ { \ if(new_obj) { \ crm_err("Potential memory leak:" \ " %s at %s:%d not NULL before alloc.", \ #new_obj, __FILE__, __LINE__); \ abort(); \ } \ new_obj = cl_malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ abort(); \ } \ memset(new_obj, 0, length); \ } #else # define crm_malloc0(new_obj,length) \ { \ new_obj = cl_malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ abort(); \ } \ memset(new_obj, 0, length); \ } # endif # define crm_free(x) if(x) { \ CRM_ASSERT(cl_is_allocated(x) == 1); \ cl_free(x); \ x=NULL; \ } # define crm_is_allocated(obj) cl_is_allocated(obj) #endif #define crm_msg_del(msg) if(msg != NULL) { ha_msg_del(msg); msg = NULL; } #endif