diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index 68046f687a..697c5c1a9e 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,928 +1,928 @@ -/* $Id: crmadmin.c,v 1.55 2005/07/07 22:09:55 andrew Exp $ */ +/* $Id: crmadmin.c,v 1.56 2005/08/17 08:57:29 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 #ifdef HAVE_GETOPT_H # include #endif #include int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); void crmd_ipc_connection_destroy(gpointer user_data); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); crm_data_t *handleCibMod(void); int do_find_resource(const char *rsc, crm_data_t *xml_node); int do_find_resource_list(int level, crm_data_t *xml_node); int do_find_node_list(crm_data_t *xml_node); gboolean admin_message_timeout(gpointer data); gboolean is_node_online(crm_data_t *node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; gboolean DO_OPTION = FALSE; gboolean DO_STANDBY = FALSE; enum debug DO_DEBUG = debug_none; const char *crmd_operation = NULL; crm_data_t *msg_options = NULL; const char *standby_on_off = "on"; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; const char *crm_system_name = "crmadmin"; #define OPTARGS "V?K:S:HE:DW:d:i:RNs:a:qt:o:" int main(int argc, char **argv) { int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'q'}, {"reference", 1, 0, 0}, {XML_ATTR_TIMEOUT, 1, 0, 't'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"die", 0, 0, 0}, /* kill a node, no respawn */ {"crm_debug_inc", 1, 0, 'i'}, {"crm_debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"standby", 1, 0, 's'}, {"active", 1, 0, 'a'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"resources", 0, 0, 'R'}, {"nodes", 0, 0, 'N'}, {"whereis", 1, 0, 'W'}, {"option", 1, 0, 'o'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcmp("die", long_options[option_index].name) == 0) { DO_RESET = TRUE; crmd_operation = CRM_OP_DIE; } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; #endif /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'W': DO_RESOURCE = TRUE; crm_debug_2("Option %c => %s", flag, optarg); rsc_name = crm_strdup(optarg); break; case 'K': DO_RESET = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); crmd_operation = CRM_OP_LOCAL_SHUTDOWN; break; case 'o': DO_OPTION = TRUE; crm_debug_2("Option %c => %s", flag, optarg); crm_option = crm_strdup(optarg); break; case 'q': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 's': DO_STANDBY = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'a': DO_STANDBY = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); standby_on_off = "off"; break; case 'S': DO_HEALTH = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'R': DO_RESOURCE_LIST = TRUE; break; case 'H': DO_HEALTH = 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); } hb_cluster = do_init(); if (hb_cluster != NULL) { int res = do_work(hb_cluster); if (res >= 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); expected_responses++; if(res == 0) { crm_debug_2("no reply expected," " wait for the hello message only"); } else { crm_debug_2("Waiting for reply from the local CRM"); } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { crm_err("No message to send"); operation_status = -1; } } else { crm_warn("Init failed, could not perform requested operations"); operation_status = -2; } crm_debug_2("%s exiting normally", crm_system_name); return operation_status; } int do_work(ll_cluster_t * hb_cluster) { int ret = 1; /* construct the request */ crm_data_t *msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose); crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_debug_2("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_PING; if (BE_VERBOSE) { expected_responses = -1;/* wait until timeout instead */ } crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_VOTE; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; crmd_operation = CRM_OP_PING; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST || DO_OPTION || DO_STANDBY) { cib_t * the_cib = cib_new(); crm_data_t *output = NULL; int call_options = cib_sync_call; enum cib_errors rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command); if(rc != cib_ok) { return -1; } else if(DO_RESOURCE) { output = get_cib_copy(the_cib); do_find_resource(rsc_name, output); } else if(DO_RESOURCE_LIST) { crm_data_t *rscs = NULL; output = get_cib_copy(the_cib); rscs = get_object_root(XML_CIB_TAG_RESOURCES, output); do_find_resource_list(0, rscs); } else if(DO_NODE_LIST) { output = get_cib_copy(the_cib); do_find_node_list(output); } else if(DO_OPTION) { char *name = NULL; char *value = NULL; crm_data_t *xml_option = NULL; crm_data_t *fragment = NULL; if(decodeNVpair(crm_option, '=', &name, &value)==FALSE){ crm_err("%s needs to be of the form" " =", crm_option); return -1; } xml_option = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_option, XML_NVPAIR_ATTR_NAME, name); crm_xml_add(xml_option, XML_NVPAIR_ATTR_VALUE, value); fragment = create_cib_fragment(xml_option, NULL); free_xml(xml_option); crm_free(name); crm_free(value); rc = the_cib->cmds->modify( the_cib, XML_CIB_TAG_CRMCONFIG, fragment, NULL, call_options|cib_discard_reply); free_xml(fragment); } else if(DO_STANDBY) { crm_data_t *a_node = NULL; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; a_node = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_xml_add(a_node, XML_ATTR_ID, dest_node); xml_obj = create_xml_node(a_node, XML_TAG_ATTR_SETS); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, "standby"); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, "standby"); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, standby_on_off); fragment = create_cib_fragment(a_node, NULL); free_xml(a_node); rc = the_cib->cmds->modify( the_cib, XML_CIB_TAG_NODES, fragment, NULL, call_options|cib_discard_reply); free_xml(fragment); } free_xml(output); the_cib->cmds->signoff(the_cib); exit(rc); } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_UP; ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_DOWN; ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) sys_to = CRM_SYSTEM_CRMD; else sys_to = CRM_SYSTEM_DC; } { HA_Message *cmd = create_request( crmd_operation, msg_data, dest_node, sys_to, crm_system_name, admin_uuid); if(this_msg_reference != NULL) { ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference); } send_ipc_message(crmd_channel, cmd); } return ret; } void crmd_ipc_connection_destroy(gpointer user_data) { crm_info("Connection to CRMd was terminated"); exit(1); } ll_cluster_t * do_init(void) { int facility; GCHSource *src = NULL; ll_cluster_t *hb_cluster = NULL; /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); crm_debug_2("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_malloc0(admin_uuid, sizeof(char) * 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } src = init_client_ipc_comms( CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); set_IPC_Channel_dnotify(src, crmd_ipc_connection_destroy); return hb_cluster; } return NULL; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename = NULL; int filename_len = 0; const char *result = NULL; - g_source_remove(message_timer_id); + Gmain_timeout_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); } if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; received_responses++; new_input = new_ipc_msg_input(msg); crm_log_message(LOG_MSG, new_input->msg); msg->msg_done(msg); if (new_input->xml == NULL) { crm_info("XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_info("Message was not a CRM response. Discarding."); continue; } result = cl_get_string(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } if(DO_HEALTH) { const char *state = crm_element_value( new_input->xml, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM), cl_get_string(new_input->msg, F_CRM_HOST_FROM), state, crm_element_value(new_input->xml,XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_WHOIS_DC) { const char *dc = cl_get_string( new_input->msg, F_CRM_HOST_FROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc0(filename, sizeof(char) * filename_len); if(filename != NULL) { sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file(new_input->xml, filename)) { crm_crit("Could not save response to" " %s", filename); } } } } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_debug_2( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { 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; } int do_find_resource(const char *rsc, crm_data_t *xml_node) { int found = 0; crm_data_t *nodestates = get_object_root(XML_CIB_TAG_STATUS, xml_node); const char *path2[] = { XML_CIB_TAG_LRM, XML_LRM_TAG_RESOURCES }; xml_child_iter( nodestates, a_node, XML_CIB_TAG_STATE, crm_data_t *rscstates = NULL; if(is_node_online(a_node) == FALSE) { crm_debug_3("Skipping offline node: %s", crm_element_value(a_node, XML_ATTR_ID)); continue; } rscstates = find_xml_node_nested(a_node, path2, DIMOF(path2)); xml_child_iter( rscstates, rsc_state, XML_LRM_TAG_RESOURCE, const char *id = crm_element_value( rsc_state,XML_ATTR_ID); const char *target = crm_element_value( a_node, XML_ATTR_UNAME); const char *last_op = crm_element_value( rsc_state,XML_LRM_ATTR_LASTOP); const char *op_code = crm_element_value( rsc_state,XML_LRM_ATTR_OPSTATUS); crm_debug_3("checking %s:%s for %s", target, id, rsc); if(safe_str_neq(rsc, id)){ crm_debug_4("no match"); continue; } if(safe_str_eq("stop", last_op)) { crm_debug_3("resource %s is stopped on: %s", rsc, target); } else if(safe_str_eq(op_code, "-1")) { crm_debug_3("resource %s is pending on: %s", rsc, target); } else if(safe_str_neq(op_code, "0")) { crm_debug_3("resource %s is failed on: %s", rsc, target); } else { crm_debug_3("resource %s is running on: %s", rsc, target); printf("resource %s is running on: %s\n", rsc, target); if(BE_SILENT) { fprintf(stderr, "%s ", target); } found++; } ); if(BE_SILENT) { fprintf(stderr, "\n"); } ); if(found == 0) { printf("resource %s is NOT running\n", rsc); } return found; } gboolean is_node_online(crm_data_t *node_state) { const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && crm_is_true(ccm_state) && safe_str_eq(crm_state, ONLINESTATUS)) { crm_debug_3("Node %s is online", uname); return TRUE; } crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s", uname, crm_str(ha_state), crm_str(ccm_state), crm_str(join_state), crm_str(exp_state), crm_str(crm_state)); crm_debug_3("Node %s is offline", uname); return FALSE; } int do_find_resource_list(int level, crm_data_t *resource_list) { int lpc = 0; int found = 0; const char *name = NULL; const char *type = NULL; const char *class = NULL; xml_child_iter( resource_list, rsc, NULL, name = crm_element_name(rsc); if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { class = crm_element_value(rsc, "class"); type = crm_element_value(rsc, XML_ATTR_TYPE); for(lpc = 0; lpc < level; lpc++) { printf("\t"); } found++; printf("%s: %s (%s::%s)\n", name, ID(rsc), crm_str(class), crm_str(type)); } else if(safe_str_eq(name, XML_CIB_TAG_GROUP) || safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { for(lpc = 0; lpc < level; lpc++) { printf("\t"); } printf("%s: %s (complex)\n", name, ID(rsc)); do_find_resource_list(level+1, rsc); found++; } ); if(found == 0) { for(lpc = 0; lpc < level; lpc++) { printf("\t"); } printf("NO resources configured\n"); } return found; } int do_find_node_list(crm_data_t *xml_node) { int found = 0; crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); xml_child_iter( nodes, node, XML_CIB_TAG_NODE, printf("%s node: %s (%s)\n", crm_element_value(node, XML_ATTR_TYPE), crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); found++; ); if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q'); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", CRM_OP_DEBUG_UP,'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", CRM_OP_DEBUG_DOWN,'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); fprintf(stream, "\t--%s (-%c)\t: " "request the names of all resources\n", "resources", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "request the location of \n", "whereis", 'W'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to enter \"standby\" mode\n", "standby", 's'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to exit \"standby\" mode\n", "active", 'a'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c index afe585d657..1e14f9dd56 100644 --- a/crm/crmd/utils.c +++ b/crm/crmd/utils.c @@ -1,1316 +1,1316 @@ /* * 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 void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy); /* A_DC_TIMER_STOP, A_DC_TIMER_START, * A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START * A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START */ enum crmd_fsa_input do_timer_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) { gboolean timer_op_ok = TRUE; enum crmd_fsa_input result = I_NULL; if(action & A_DC_TIMER_STOP) { timer_op_ok = crm_timer_stop(election_trigger); } else if(action & A_FINALIZE_TIMER_STOP) { timer_op_ok = crm_timer_stop(finalization_timer); } else if(action & A_INTEGRATE_TIMER_STOP) { timer_op_ok = crm_timer_stop(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_STOP) { */ /* timer_op_ok = crm_timer_stop(election_timeout); */ } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { crm_timer_start(election_trigger); if(AM_I_DC) { /* there can be only one */ result = I_ELECTION; } } else if(action & A_FINALIZE_TIMER_START) { crm_timer_start(finalization_timer); } else if(action & A_INTEGRATE_TIMER_START) { crm_timer_start(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_START) { */ /* crm_timer_start(election_timeout); */ } return I_NULL; } gboolean crm_timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; if(timer == election_trigger) { crm_info("Election Trigger (%s) just popped!", fsa_input2string(timer->fsa_input)); } else if(timer == election_timeout) { crm_info("Election Timeout (%s) just popped!", fsa_input2string(timer->fsa_input)); } else { crm_info("Timer %s just popped!", fsa_input2string(timer->fsa_input)); } if(timer->repeat == FALSE) { crm_timer_stop(timer); /* make it _not_ go off again */ } if(timer->fsa_input == I_INTEGRATED) { register_fsa_input_before( C_TIMER_POPPED, timer->fsa_input, NULL); } else if(timer->fsa_input == I_FINALIZED && fsa_state != S_FINALIZE_JOIN) { crm_debug("Discarding I_FINALIZED event in state: %s", fsa_state2string(fsa_state)); } else if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } G_main_set_trigger(fsa_source); return TRUE; } gboolean crm_timer_start(fsa_timer_t *timer) { const char *timer_desc = NULL; if(timer == election_trigger) { timer_desc = "Election Trigger"; } else if(timer == election_timeout) { timer_desc = "Election Timeout"; } else { timer_desc = "Timer"; } if((timer->source_id == (guint)-1 || timer->source_id == (guint)-2) && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add( timer->period_ms, timer->callback, (void*)timer); crm_debug("Started %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); } else if(timer->period_ms < 0) { crm_err("Tried to start %s (%s:%dms) with a -ve period", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); } else { crm_debug("%s (%s:%dms) already running: src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); return FALSE; } return TRUE; } gboolean crm_timer_stop(fsa_timer_t *timer) { const char *timer_desc = NULL; if(timer == election_trigger) { timer_desc = "Election Trigger"; } else if(timer == election_timeout) { timer_desc = "Election Timeout"; } else if(timer == wait_timer) { timer_desc = "Stall Timeout"; } else { timer_desc = "Timer"; } if(timer == NULL) { crm_err("Attempted to stop NULL timer"); return FALSE; } else if(timer->source_id != (guint)-1 && timer->source_id != (guint)-2) { crm_debug("Stopping %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); - g_source_remove(timer->source_id); + Gmain_timeout_remove(timer->source_id); timer->source_id = -2; } else { crm_debug_2("%s (%s:%dms) already stopped", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); timer->source_id = -2; return FALSE; } return TRUE; } long long toggle_bit(long long action_list, long long action) { crm_debug_5("Toggling bit %.16llx", action); action_list ^= action; crm_debug_5("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "Clearing bit\t%.16llx", action); /* ensure its set */ action_list |= action; /* then toggle */ action_list = action_list ^ action; return action_list; } long long set_bit(long long action_list, long long action) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "Setting bit\t%.16llx", action); action_list |= action; return action_list; } gboolean is_set(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); return ((action_list & action) == action); } gboolean is_set_any(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); return ((action_list & action) != 0); } const char * fsa_input2string(enum crmd_fsa_input input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; break; case I_CCM_EVENT: inputAsText = "I_CCM_EVENT"; break; case I_CIB_OP: inputAsText = "I_CIB_OP"; break; case I_CIB_UPDATE: inputAsText = "I_CIB_UPDATE"; break; case I_DC_TIMEOUT: inputAsText = "I_DC_TIMEOUT"; break; case I_ELECTION: inputAsText = "I_ELECTION"; break; case I_PE_CALC: inputAsText = "I_PE_CALC"; break; case I_RELEASE_DC: inputAsText = "I_RELEASE_DC"; break; case I_ELECTION_DC: inputAsText = "I_ELECTION_DC"; break; case I_ERROR: inputAsText = "I_ERROR"; break; case I_FAIL: inputAsText = "I_FAIL"; break; case I_INTEGRATED: inputAsText = "I_INTEGRATED"; break; case I_FINALIZED: inputAsText = "I_FINALIZED"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; case I_JOIN_OFFER: inputAsText = "I_JOIN_OFFER"; break; case I_JOIN_REQUEST: inputAsText = "I_JOIN_REQUEST"; break; case I_JOIN_RESULT: inputAsText = "I_JOIN_RESULT"; break; case I_NOT_DC: inputAsText = "I_NOT_DC"; break; case I_RECOVERED: inputAsText = "I_RECOVERED"; break; case I_RELEASE_FAIL: inputAsText = "I_RELEASE_FAIL"; break; case I_RELEASE_SUCCESS: inputAsText = "I_RELEASE_SUCCESS"; break; case I_RESTART: inputAsText = "I_RESTART"; break; case I_PE_SUCCESS: inputAsText = "I_PE_SUCCESS"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_TE_SUCCESS: inputAsText = "I_TE_SUCCESS"; break; case I_STOP: inputAsText = "I_STOP"; break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; case I_WAIT_FOR_EVENT: inputAsText = "I_WAIT_FOR_EVENT"; break; case I_LRM_EVENT: inputAsText = "I_LRM_EVENT"; break; case I_PENDING: inputAsText = "I_PENDING"; break; case I_HALT: inputAsText = "I_HALT"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if(inputAsText == NULL) { crm_err("Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(enum crmd_fsa_state state) { const char *stateAsText = NULL; switch(state){ case S_IDLE: stateAsText = "S_IDLE"; break; case S_ELECTION: stateAsText = "S_ELECTION"; break; case S_INTEGRATION: stateAsText = "S_INTEGRATION"; break; case S_FINALIZE_JOIN: stateAsText = "S_FINALIZE_JOIN"; break; case S_NOT_DC: stateAsText = "S_NOT_DC"; break; case S_POLICY_ENGINE: stateAsText = "S_POLICY_ENGINE"; break; case S_RECOVERY: stateAsText = "S_RECOVERY"; break; case S_RELEASE_DC: stateAsText = "S_RELEASE_DC"; break; case S_PENDING: stateAsText = "S_PENDING"; break; case S_STOPPING: stateAsText = "S_STOPPING"; break; case S_TERMINATE: stateAsText = "S_TERMINATE"; break; case S_TRANSITION_ENGINE: stateAsText = "S_TRANSITION_ENGINE"; break; case S_STARTING: stateAsText = "S_STARTING"; break; case S_HALT: stateAsText = "S_HALT"; break; case S_ILLEGAL: stateAsText = "S_ILLEGAL"; break; } if(stateAsText == NULL) { crm_err("State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(enum crmd_fsa_cause cause) { const char *causeAsText = NULL; switch(cause){ case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_CCM_CALLBACK: causeAsText = "C_CCM_CALLBACK"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_HEARTBEAT_FAILED: causeAsText = "C_HEARTBEAT_FAILED"; break; case C_SUBSYSTEM_CONNECT: causeAsText = "C_SUBSYSTEM_CONNECT"; break; case C_LRM_OP_CALLBACK: causeAsText = "C_LRM_OP_CALLBACK"; break; case C_LRM_MONITOR_CALLBACK: causeAsText = "C_LRM_MONITOR_CALLBACK"; break; case C_CRMD_STATUS_CALLBACK: causeAsText = "C_CRMD_STATUS_CALLBACK"; break; case C_HA_DISCONNECT: causeAsText = "C_HA_DISCONNECT"; break; case C_FSA_INTERNAL: causeAsText = "C_FSA_INTERNAL"; break; case C_ILLEGAL: causeAsText = "C_ILLEGAL"; break; } if(causeAsText == NULL) { crm_err("Cause %d is unknown", cause); causeAsText = ""; } return causeAsText; } const char * fsa_action2string(long long action) { const char *actionAsText = NULL; switch(action){ case A_NOTHING: actionAsText = "A_NOTHING"; break; case A_ELECTION_START: actionAsText = "A_ELECTION_START"; break; case A_READCONFIG: actionAsText = "A_READCONFIG"; break; case O_RELEASE: actionAsText = "O_RELEASE"; break; case A_STARTUP: actionAsText = "A_STARTUP"; break; case A_STARTED: actionAsText = "A_STARTED"; break; case A_HA_CONNECT: actionAsText = "A_HA_CONNECT"; break; case A_HA_DISCONNECT: actionAsText = "A_HA_DISCONNECT"; break; case A_LRM_CONNECT: actionAsText = "A_LRM_CONNECT"; break; case A_LRM_EVENT: actionAsText = "A_LRM_EVENT"; break; case A_LRM_INVOKE: actionAsText = "A_LRM_INVOKE"; break; case A_LRM_DISCONNECT: actionAsText = "A_LRM_DISCONNECT"; break; case A_CL_JOIN_QUERY: actionAsText = "A_CL_JOIN_QUERY"; break; case A_DC_TIMER_STOP: actionAsText = "A_DC_TIMER_STOP"; break; case A_DC_TIMER_START: actionAsText = "A_DC_TIMER_START"; break; case A_INTEGRATE_TIMER_START: actionAsText = "A_INTEGRATE_TIMER_START"; break; case A_INTEGRATE_TIMER_STOP: actionAsText = "A_INTEGRATE_TIMER_STOP"; break; case A_FINALIZE_TIMER_START: actionAsText = "A_FINALIZE_TIMER_START"; break; case A_FINALIZE_TIMER_STOP: actionAsText = "A_FINALIZE_TIMER_STOP"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; case A_CL_JOIN_ANNOUNCE: actionAsText = "A_CL_JOIN_ANNOUNCE"; break; case A_CL_JOIN_REQUEST: actionAsText = "A_CL_JOIN_REQUEST"; break; case A_CL_JOIN_RESULT: actionAsText = "A_CL_JOIN_RESULT"; break; case A_DC_JOIN_OFFER_ALL: actionAsText = "A_DC_JOIN_OFFER_ALL"; break; case A_DC_JOIN_OFFER_ONE: actionAsText = "A_DC_JOIN_OFFER_ONE"; break; case A_DC_JOIN_PROCESS_REQ: actionAsText = "A_DC_JOIN_PROCESS_REQ"; break; case A_DC_JOIN_PROCESS_ACK: actionAsText = "A_DC_JOIN_PROCESS_ACK"; break; case A_DC_JOIN_FINALIZE: actionAsText = "A_DC_JOIN_FINALIZE"; break; case A_MSG_PROCESS: actionAsText = "A_MSG_PROCESS"; break; case A_MSG_ROUTE: actionAsText = "A_MSG_ROUTE"; break; case A_RECOVER: actionAsText = "A_RECOVER"; break; case A_DC_RELEASE: actionAsText = "A_DC_RELEASE"; break; case A_DC_RELEASED: actionAsText = "A_DC_RELEASED"; break; case A_DC_TAKEOVER: actionAsText = "A_DC_TAKEOVER"; break; case A_SHUTDOWN: actionAsText = "A_SHUTDOWN"; break; case A_SHUTDOWN_REQ: actionAsText = "A_SHUTDOWN_REQ"; break; case A_STOP: actionAsText = "A_STOP "; break; case A_EXIT_0: actionAsText = "A_EXIT_0"; break; case A_EXIT_1: actionAsText = "A_EXIT_1"; break; case A_CCM_CONNECT: actionAsText = "A_CCM_CONNECT"; break; case A_CCM_DISCONNECT: actionAsText = "A_CCM_DISCONNECT"; break; case A_CCM_EVENT: actionAsText = "A_CCM_EVENT"; break; case A_CCM_UPDATE_CACHE: actionAsText = "A_CCM_UPDATE_CACHE"; break; case A_CIB_BUMPGEN: actionAsText = "A_CIB_BUMPGEN"; break; case A_CIB_INVOKE: actionAsText = "A_CIB_INVOKE"; break; case O_CIB_RESTART: actionAsText = "O_CIB_RESTART"; break; case A_CIB_START: actionAsText = "A_CIB_START"; break; case A_CIB_STOP: actionAsText = "A_CIB_STOP"; break; case A_TE_INVOKE: actionAsText = "A_TE_INVOKE"; break; case O_TE_RESTART: actionAsText = "O_TE_RESTART"; break; case A_TE_START: actionAsText = "A_TE_START"; break; case A_TE_STOP: actionAsText = "A_TE_STOP"; break; case A_TE_CANCEL: actionAsText = "A_TE_CANCEL"; break; case A_PE_INVOKE: actionAsText = "A_PE_INVOKE"; break; case O_PE_RESTART: actionAsText = "O_PE_RESTART"; break; case A_PE_START: actionAsText = "A_PE_START"; break; case A_PE_STOP: actionAsText = "A_PE_STOP"; break; case A_NODE_BLOCK: actionAsText = "A_NODE_BLOCK"; break; case A_UPDATE_NODESTATUS: actionAsText = "A_UPDATE_NODESTATUS"; break; case A_LOG: actionAsText = "A_LOG "; break; case A_ERROR: actionAsText = "A_ERROR "; break; case A_WARN: actionAsText = "A_WARN "; break; } if(actionAsText == NULL) { crm_err("Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } void fsa_dump_inputs(int log_level, const char *text, long long input_register) { if(input_register == A_NOTHING) { return; } if(text == NULL) { text = "Input register contents:"; } if(is_set(input_register, R_THE_DC)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_THE_DC)", text, R_THE_DC); } if(is_set(input_register, R_STARTING)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_STARTING)", text, R_STARTING); } if(is_set(input_register, R_SHUTDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN); } if(is_set(input_register, R_STAYDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN); } if(is_set(input_register, R_JOIN_OK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK); } if(is_set(input_register, R_HAVE_RES)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_HAVE_RES)", text, R_HAVE_RES); } if(is_set(input_register, R_INVOKE_PE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE); } if(is_set(input_register, R_CIB_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if(is_set(input_register, R_PE_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if(is_set(input_register, R_TE_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if(is_set(input_register, R_LRM_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } if(is_set(input_register, R_CIB_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); } if(is_set(input_register, R_PE_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED); } if(is_set(input_register, R_TE_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED); } if(is_set(input_register, R_REQ_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND); } if(is_set(input_register, R_PE_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_PEND)", text, R_PE_PEND); } if(is_set(input_register, R_TE_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_PEND)", text, R_TE_PEND); } if(is_set(input_register, R_RESP_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND); } if(is_set(input_register, R_CIB_DONE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE); } if(is_set(input_register, R_HAVE_CIB)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB); } if(is_set(input_register, R_CIB_ASKED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED); } if(is_set(input_register, R_CCM_DATA)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA); } if(is_set(input_register, R_PEER_DATA)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA); } if(is_set(input_register, R_IN_RECOVERY)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY); } } void fsa_dump_actions(long long action, const char *text) { int log_level = LOG_DEBUG_3; if(is_set(action, A_READCONFIG)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if(is_set(action, A_DC_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if(is_set(action, A_FINALIZE_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if(is_set(action, A_FINALIZE_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if(is_set(action, A_CL_JOIN_REQUEST)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if(is_set(action, A_CL_JOIN_RESULT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if(is_set(action, A_DC_JOIN_OFFER_ALL)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text); } if(is_set(action, A_DC_JOIN_OFFER_ONE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text); } if(is_set(action, A_DC_JOIN_PROCESS_REQ)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text); } if(is_set(action, A_DC_JOIN_PROCESS_ACK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text); } if(is_set(action, A_DC_JOIN_FINALIZE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_RECOVER)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CCM_EVENT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_EVENT) %s", A_CCM_EVENT, text); } if(is_set(action, A_CCM_UPDATE_CACHE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_UPDATE_CACHE) %s", A_CCM_UPDATE_CACHE, text); } if(is_set(action, A_CIB_BUMPGEN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_BUMPGEN) %s", A_CIB_BUMPGEN, text); } if(is_set(action, A_CIB_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_INVOKE) %s", A_CIB_INVOKE, text); } if(is_set(action, A_CIB_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_PE_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_WARN ) %s", A_WARN, text); } } void create_node_entry(const char *uuid, const char *uname, const char *type) { /* make sure a node entry exists for the new node * * this will add anyone except the first ever node in the cluster * since it will also be the DC which doesnt go through the * join process (with itself). We can include a special case * later if desired. */ crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug_3("Creating node entry for %s", uname); set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname); crm_xml_add(tmp1, XML_ATTR_UNAME, uname); crm_xml_add(tmp1, XML_ATTR_TYPE, type); update_local_cib(create_cib_fragment(tmp1, NULL)); free_xml(tmp1); } struct crmd_ccm_data_s * copy_ccm_data(const struct crmd_ccm_data_s *ccm_input) { const oc_ev_membership_t *oc_in = (const oc_ev_membership_t *)ccm_input->oc; struct crmd_ccm_data_s *ccm_input_copy = NULL; crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s)); ccm_input_copy->oc = copy_ccm_oc_data(oc_in); ccm_input_copy->event = ccm_input->event; return ccm_input_copy; } oc_ev_membership_t * copy_ccm_oc_data(const oc_ev_membership_t *oc_in) { unsigned lpc = 0; int size = 0; int offset = 0; unsigned num_nodes = 0; oc_ev_membership_t *oc_copy = NULL; if(oc_in->m_n_member > 0 && num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) { num_nodes = oc_in->m_n_member + oc_in->m_memb_idx; crm_debug_3("Updated ccm nodes to %d - 1", num_nodes); } if(oc_in->m_n_in > 0 && num_nodes < oc_in->m_n_in + oc_in->m_in_idx) { num_nodes = oc_in->m_n_in + oc_in->m_in_idx; crm_debug_3("Updated ccm nodes to %d - 2", num_nodes); } if(oc_in->m_n_out > 0 && num_nodes < oc_in->m_n_out + oc_in->m_out_idx) { num_nodes = oc_in->m_n_out + oc_in->m_out_idx; crm_debug_3("Updated ccm nodes to %d - 3", num_nodes); } /* why 2*?? * ccm code does it like this so i guess its right... */ size = sizeof(oc_ev_membership_t) + sizeof(int) + 2*num_nodes*sizeof(oc_node_t); crm_debug_3("Copying %d ccm nodes", num_nodes); crm_malloc0(oc_copy, size); oc_copy->m_instance = oc_in->m_instance; oc_copy->m_n_member = oc_in->m_n_member; oc_copy->m_memb_idx = oc_in->m_memb_idx; oc_copy->m_n_out = oc_in->m_n_out; oc_copy->m_out_idx = oc_in->m_out_idx; oc_copy->m_n_in = oc_in->m_n_in; oc_copy->m_in_idx = oc_in->m_in_idx; crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)", oc_in->m_instance, oc_in->m_n_member, oc_in->m_memb_idx, oc_in->m_n_in, oc_in->m_in_idx, oc_in->m_n_out, oc_in->m_out_idx); offset = oc_in->m_memb_idx; for(lpc = 0; lpc < oc_in->m_n_member; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm member node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_in_idx; for(lpc = 0; lpc < oc_in->m_n_in; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm new node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_out_idx; for(lpc = 0; lpc < oc_in->m_n_out; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm lost node %d", lpc); copy_ccm_node(a_node, a_node_copy); } return oc_copy; } void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy) { crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s", a_node.node_id, a_node.node_born_on, a_node.node_uname); a_node_copy->node_id = a_node.node_id; a_node_copy->node_born_on = a_node.node_born_on; a_node_copy->node_uname = NULL; if(a_node.node_uname != NULL) { a_node_copy->node_uname = crm_strdup(a_node.node_uname); } else { crm_err("Node Id %d had a NULL uname!", a_node.node_id); } crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s", a_node_copy->node_id, a_node_copy->node_born_on, a_node_copy->node_uname); } crm_data_t* create_node_state( const char *uuid, const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, const char *src) { crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug_2("%s Creating node state entry for %s", src, uname); set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname); crm_xml_add(node_state, XML_ATTR_UNAME, uname); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state); crm_xml_add(node_state, "origin", src); crm_log_xml_debug_3(node_state, "created"); return node_state; } gboolean need_transition(enum crmd_fsa_state state) { if(state == S_POLICY_ENGINE || state == S_TRANSITION_ENGINE || state == S_IDLE) { return TRUE; } return FALSE; } extern GHashTable *ipc_clients; void process_client_disconnect(crmd_client_t *curr_client) { struct crm_subsystem_s *the_subsystem = NULL; CRM_DEV_ASSERT(curr_client != NULL); if(crm_assert_failed) { return; } crm_debug_2("received HUP from %s", curr_client->table_key); if (curr_client->sub_sys == NULL) { crm_debug("Client hadn't registered with us yet"); } else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { the_subsystem->ipc = NULL; } /* else that was a transient client */ if (curr_client->table_key != NULL) { /* * Key is destroyed below: * curr_client->table_key * Value is cleaned up by: * G_main_del_IPC_Channel */ g_hash_table_remove(ipc_clients, curr_client->table_key); } crm_free(curr_client->table_key); crm_free(curr_client->sub_sys); crm_free(curr_client->uuid); crm_free(curr_client); } diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 743925114e..d3480af314 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,1031 +1,1031 @@ -/* $Id: tengine.c,v 1.93 2005/08/10 09:25:10 andrew Exp $ */ +/* $Id: tengine.c,v 1.94 2005/08/17 08:57:28 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 gboolean graph_complete = FALSE; GListPtr graph = NULL; IPC_Channel *crm_ch = NULL; uint transition_idle_timeout = 30*1000; /* 30 seconds */ void fire_synapse(synapse_t *synapse); gboolean initiate_action(action_t *action); gboolean confirm_synapse(synapse_t *synapse, int action_id); void check_synapse_triggers(synapse_t *synapse, int action_id); void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); te_timer_t *transition_timer = NULL; te_timer_t *abort_timer = NULL; int transition_counter = 1; char *te_uuid = NULL; const te_fsa_state_t te_state_matrix[i_invalid][s_invalid] = { /* s_idle, s_in_transition, s_abort_pending, s_updates_pending */ /* Got an i_transition */{ s_in_transition, s_abort_pending, s_abort_pending, s_updates_pending }, /* Got an i_cancel */{ s_idle, s_abort_pending, s_abort_pending, s_updates_pending }, /* Got an i_complete */{ s_idle, s_idle, s_abort_pending, s_updates_pending }, /* Got an i_cmd_complete*/{ s_idle, s_in_transition, s_updates_pending, s_updates_pending }, /* Got an i_cib_complete*/{ s_idle, s_in_transition, s_abort_pending, s_idle }, /* Got an i_cib_confirm */{ s_idle, s_in_transition, s_abort_pending, s_updates_pending }, /* Got an i_cib_notify */{ s_idle, s_in_transition, s_abort_pending, s_updates_pending } }; te_fsa_state_t te_fsa_state = s_idle; gboolean initialize_graph(void) { remove_cib_op_callback(-1, TRUE); if(transition_timer == NULL) { crm_malloc0(transition_timer, sizeof(te_timer_t)); transition_timer->timeout = 10; transition_timer->source_id = -1; transition_timer->reason = timeout_timeout; transition_timer->action = NULL; } else { stop_te_timer(transition_timer); } if(abort_timer == NULL) { crm_malloc0(abort_timer, sizeof(te_timer_t)); abort_timer->timeout = 10; abort_timer->source_id = -1; abort_timer->reason = timeout_abort; abort_timer->action = NULL; } else { stop_te_timer(abort_timer); } if(te_uuid == NULL) { cl_uuid_t new_uuid; crm_malloc0(te_uuid, sizeof(char)*38); cl_uuid_generate(&new_uuid); cl_uuid_unparse(&new_uuid, te_uuid); crm_info("Registering TE UUID: %s", te_uuid); } while(g_list_length(graph) > 0) { synapse_t *synapse = g_list_nth_data(graph, 0); while(g_list_length(synapse->actions) > 0) { action_t *action = g_list_nth_data(synapse->actions,0); synapse->actions = g_list_remove( synapse->actions, action); if(action->timer->source_id > 0) { crm_debug_3("Removing timer for action: %d", action->id); - g_source_remove(action->timer->source_id); + Gmain_timeout_remove(action->timer->source_id); } free_xml(action->xml); crm_free(action->timer); crm_free(action); } while(g_list_length(synapse->inputs) > 0) { action_t *action = g_list_nth_data(synapse->inputs, 0); synapse->inputs = g_list_remove(synapse->inputs, action); free_xml(action->xml); crm_free(action); } graph = g_list_remove(graph, synapse); crm_free(synapse); } graph = NULL; return TRUE; } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int match_graph_event(action_t *action, crm_data_t *event, const char *event_node) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_uname = NULL; const char *this_rsc = NULL; const char *magic = NULL; const char *this_event; char *update_te_uuid = NULL; const char *update_event; action_t *match = NULL; int op_status_i = -3; int transition_i = -1; if(event == NULL) { crm_debug_4("Ignoring NULL event"); return -1; } this_rsc = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); if(this_rsc == NULL) { crm_debug_4("Skipping non-resource event"); return -1; } crm_debug_3("Processing \"%s\" change", crm_element_name(event)); update_event = crm_element_value(event, XML_ATTR_ID); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); if(magic == NULL) { /* crm_debug("Skipping \"non-change\""); */ crm_log_xml_debug(event, "Skipping \"non-change\""); return -3; } this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK); this_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); this_uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); this_event = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); CRM_DEV_ASSERT(this_event != NULL); if(safe_str_neq(this_event, update_event)) { crm_debug_2("Action %d : Event mismatch %s vs. %s", action->id, this_event, update_event); } else if(safe_str_neq(this_node, event_node)) { crm_debug_2("Action %d : Node mismatch %s (%s) vs. %s", action->id, this_node, this_uname, event_node); } else { match = action; } if(match == NULL) { return -1; } crm_debug("Matched action (%d) %s", action->id, this_event); CRM_DEV_ASSERT(decode_transition_magic( magic, &update_te_uuid, &transition_i, &op_status_i)); if(transition_i == -1) { /* we never expect these - recompute */ crm_err("Detected an action initiated outside of a transition"); crm_log_message(LOG_ERR, event); return -5; } else if(safe_str_neq(update_te_uuid, te_uuid)) { crm_err("Detected an action from a different transitioner:" " %s vs. %s", update_te_uuid, te_uuid); return -6; } else if(transition_counter != transition_i) { crm_warn("Detected an action from a different transition:" " %d vs. %d", transition_i, transition_counter); return -3; } /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ allow_fail = crm_element_value(match->xml, "allow_fail"); switch(op_status_i) { case -3: crm_err("Action returned the same as last time..." " whatever that was!"); crm_log_message(LOG_ERR, event); break; case LRM_OP_PENDING: crm_debug("Ignoring pending operation"); return -4; break; case LRM_OP_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Action %s on %s failed: %s", update_event, event_node, op_status2text(op_status_i)); if(FALSE == crm_is_true(allow_fail)) { send_complete("Action failed", event, te_failed, i_cancel); return -2; } break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: crm_err("Unsupported action result: %d", op_status_i); send_complete("Unsupport action result", event, te_failed, i_cancel); return -2; } te_log_action(LOG_INFO, "Action %d confirmed", match->id); match->complete = TRUE; process_trigger(match->id); if(te_fsa_state != s_in_transition) { return -3; } return match->id; } int match_down_event(const char *target, const char *filter, int rc) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; action_t *match = NULL; slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, crm_data_t *action_args = NULL; if(action->type != action_type_crm) { continue; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); /* if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID)) { */ /* continue; */ /* } else */ if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } if(safe_str_eq(this_action, CRM_OP_FENCE)) { action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); this_node = crm_element_value( action_args, XML_LRM_ATTR_TARGET_UUID); } else if(safe_str_eq(this_action, CRM_OP_SHUTDOWN)) { this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); } else { crm_err("Action %d : Bad action %s", action->id, this_action); continue; } if(safe_str_neq(this_node, target)) { crm_debug("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; ); if(match != NULL) { break; } ); if(match == NULL) { crm_debug_3("didnt match current action"); return -1; } crm_debug_3("matched"); /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ switch(rc) { case STONITH_SUCCEEDED: break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: allow_fail = crm_element_value(match->xml, "allow_fail"); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", target, rc); send_complete("Stonith failed", match->xml, te_failed, i_cancel); return -2; } break; default: crm_err("Unsupported action result: %d", rc); send_complete("Unsupport Stonith result", match->xml, te_failed, i_cancel); return -2; } crm_debug_3("Action %d was successful, looking for next action", match->id); match->complete = TRUE; return match->id; } gboolean process_graph_event(crm_data_t *event, const char *event_node) { int rc = -1; int action_id = -1; int op_status_i = 0; const char *task = NULL; const char *rsc_id = NULL; const char *op_status = NULL; if(event == NULL) { crm_debug("a transition is starting"); process_trigger(action_id); check_for_completion(); return TRUE; } task = crm_element_value(event, XML_LRM_ATTR_LASTOP); rsc_id = crm_element_value(event, XML_ATTR_ID); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); if(op_status_i == -1) { /* just information that the action was sent */ crm_debug("Ignoring TE initiated updates"); return TRUE; } } crm_debug("Processing CIB update: %s on %s: %s", rsc_id, event_node, op_status2text(op_status_i)); if(crm_element_value(event, XML_ATTR_TRANSITION_MAGIC) == NULL) { crm_log_xml_debug(event, "Skipping \"non-change\""); action_id = -3; } slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, rc = match_graph_event(action, event, event_node); if(action_id >= 0 && rc >= 0) { crm_err("Additional match found: %d [%d]", rc, action_id); } else if(rc != -1) { action_id = rc; } ); if(action_id != -1) { crm_debug("Terminating search: %d", action_id); break; } ); if(action_id == -1) { /* didnt find a match... * now try any dangling inputs */ slist_iter( synapse, synapse_t, graph, lpc, slist_iter( action, action_t, synapse->inputs, lpc2, rc = match_graph_event(action,event,event_node); if(action_id >=0 && rc >=0 && rc != action_id) { crm_err("Additional match found:" " %d [%d]", rc, action_id); } else if(rc != -1) { action_id = rc; } ); if(action_id != -1) { break; } ); } if(action_id > -1) { crm_log_xml_debug_3(event, "Event found"); } else if(action_id == -2) { crm_log_xml_info(event, "Event failed"); } else if(action_id == -3) { crm_log_xml_info(event, "Old event found"); } else if(action_id == -4) { crm_log_xml_debug(event, "Pending event found"); } else { /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ crm_debug("Search terminated: %d", action_id); send_complete("Event not matched", event, te_update, i_cancel); return FALSE; } check_for_completion(); return TRUE; } void check_for_completion(void) { if(graph_complete) { /* allow some slack until we are pretty sure nothing * else is happening */ crm_info("Transition complete"); send_complete("complete", NULL, te_done, i_complete); } else { /* restart the transition timer again */ crm_debug_3("Transition not yet complete"); start_te_timer(transition_timer); } } gboolean initiate_action(action_t *action) { gboolean ret = FALSE; gboolean send_command = FALSE; const char *on_node = NULL; const char *id = NULL; const char *task = NULL; const char *timeout = NULL; const char *msg_task = XML_GRAPH_TAG_RSC_OP; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); id = crm_element_value(action->xml, XML_ATTR_ID); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); timeout = crm_element_value(action->xml, XML_ATTR_TIMEOUT); if(id == NULL || strlen(id) == 0 || task == NULL || strlen(task) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s", crm_element_name(action->xml), crm_str(id), crm_str(task)); } else if(action->type == action_type_pseudo){ te_log_action(LOG_INFO, "Executing pseudo-event (%d): " "%s on %s", action->id, task, on_node); action->complete = TRUE; process_trigger(action->id); ret = TRUE; } else if(action->type == action_type_crm && safe_str_eq(task, CRM_OP_FENCE)){ crm_data_t *action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); const char *uuid = NULL; const char *target = NULL; const char *name = NULL; stonith_ops_t * st_op = NULL; xml_child_iter( action_args, nvpair, XML_CIB_TAG_NVPAIR, name = crm_element_value(nvpair, XML_NVPAIR_ATTR_NAME); if(safe_str_eq(name, XML_LRM_ATTR_TARGET)) { target = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } else if(safe_str_eq(name, XML_LRM_ATTR_TARGET_UUID)) { uuid = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } ); CRM_DEV_ASSERT(target != NULL); CRM_DEV_ASSERT(uuid != NULL); te_log_action(LOG_INFO,"Executing fencing operation (%s) on %s", id, target); #ifdef TESTING ret = TRUE; action->complete = TRUE; process_trigger(action->id); return TRUE; #endif crm_malloc0(st_op, sizeof(stonith_ops_t)); st_op->optype = RESET; st_op->timeout = crm_atoi(timeout, "10000"); /* ten seconds */ st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); if(stonithd_input_IPC_channel() == NULL) { crm_err("Cannot fence %s - stonith not available", target); } else if (ST_OK == stonithd_node_fence( st_op )) { ret = TRUE; } } else if(on_node == NULL || strlen(on_node) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s on %s", crm_element_name(action->xml), crm_str(id), crm_str(task), crm_str(on_node)); } else if(action->type == action_type_crm){ te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", id, task, on_node); #ifdef TESTING action->complete = TRUE; process_trigger(action->id); return TRUE; #endif /* action->complete = TRUE; */ msg_task = task; send_command = TRUE; } else if(action->type == action_type_rsc){ /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ #ifdef TESTING action->invoked = FALSE; cib_action_update(action, LRM_OP_DONE); return TRUE; #endif action->invoked = FALSE; if(safe_str_eq(task, CRMD_ACTION_STOP) || safe_str_eq(task, CRMD_ACTION_NOTIFY)) { cib_action_updated(NULL, 0, cib_ok, NULL, action); } else { cib_action_update(action, LRM_OP_PENDING); } ret = TRUE; } else { te_log_action(LOG_ERR, "Failed on unsupported command type: " "%s, %s (id=%s) on %s", crm_element_name(action->xml), task, id, on_node); } if(send_command) { HA_Message *cmd = NULL; char *counter = crm_itoa(transition_counter); cmd = create_request(msg_task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key(transition_counter, te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); if(ret && action->timeout > 0) { crm_debug_3("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } return ret; } gboolean cib_action_update(action_t *action, int status) { char *code = NULL; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; char *op_id = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override; if(status == LRM_OP_TIMEOUT) { if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(action->xml), task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(action->xml), task, target); } } code = crm_itoa(status); /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(state, XML_ATTR_UUID, target_uuid); crm_xml_add(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); crm_xml_add(xml_op, XML_ATTR_ID, task); op_id = generate_op_key(rsc_id, task, action->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(rsc, XML_LRM_ATTR_RSCSTATE, get_rsc_state(task, status)); crm_xml_add(rsc, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(rsc, XML_LRM_ATTR_RC, code); crm_xml_add(rsc, XML_LRM_ATTR_LASTOP, task); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1"); crm_xml_add(xml_op, XML_LRM_ATTR_RC, code); crm_xml_add(xml_op, "origin", __FUNCTION__); crm_free(code); code = generate_transition_key(transition_counter, te_uuid); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code); crm_free(code); code = generate_transition_magic( crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code); crm_free(code); set_node_tstamp(xml_op); fragment = create_cib_fragment(state, NULL); crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); #ifndef TESTING rc = te_cib_conn->cmds->modify( te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task, rsc_id, target, rc); if(status == LRM_OP_PENDING) { crm_debug_2("Waiting for callback id: %d", rc); add_cib_op_callback(rc, FALSE, action, cib_action_updated); } #else te_log_action(LOG_INFO, "Initiating action %d: %s %s on %s", action->id, task, rsc_id, target); call_options = 0; { HA_Message *cmd = ha_msg_new(11); ha_msg_add(cmd, F_TYPE, T_CRM); ha_msg_add(cmd, F_CRM_VERSION, CRM_VERSION); ha_msg_add(cmd, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); ha_msg_add(cmd, F_CRM_TASK, CRM_OP_EVENTCC); ha_msg_add(cmd, F_CRM_SYS_TO, CRM_SYSTEM_TENGINE); ha_msg_add(cmd, F_CRM_SYS_FROM, CRM_SYSTEM_TENGINE); ha_msg_addstruct(cmd, crm_element_name(state), state); send_ipc_message(crm_ch, cmd); } #endif free_xml(fragment); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; const char *task = NULL; const char *rsc_id = NULL; const char *on_node = NULL; action_t *action = user_data; char *counter = crm_itoa(transition_counter); CRM_DEV_ASSERT(action != NULL); if(crm_assert_failed) { return; } CRM_DEV_ASSERT(action->xml != NULL); if(crm_assert_failed) { return; } rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); rsc_id = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key(transition_counter, te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); crm_free(counter); if(rc < cib_ok) { crm_err("Update for action %d: %s %s on %s FAILED", action->id, task, rsc_id, on_node); send_complete(cib_error2string(rc), output, te_failed, i_cancel); return; } if(te_fsa_state != s_in_transition) { int pending_updates = num_cib_op_callbacks(); if(pending_updates == 0) { send_complete("CIB update queue empty", output, te_done, i_cib_complete); } else { crm_debug("Still waiting on %d callbacks", pending_updates); } crm_debug("Not executing action: Not in a transition: %d", te_fsa_state); return; } crm_info("Initiating action %d: %s %s on %s", action->id, task, rsc_id, on_node); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request(task, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); #ifndef TESTING send_ipc_message(crm_ch, cmd); #else crm_log_message(LOG_INFO, cmd); #endif action->invoked = TRUE; if(action->timeout > 0) { crm_debug_3("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } gboolean initiate_transition(void) { crm_info("Initating transition"); process_graph_event(NULL, NULL); return TRUE; } void check_synapse_triggers(synapse_t *synapse, int action_id) { synapse->triggers_complete = TRUE; if(synapse->confirmed) { crm_debug_3("Skipping confirmed synapse %d", synapse->id); return; } else if(synapse->complete == FALSE) { crm_debug_3("Checking pre-reqs for %d", synapse->id); /* lookup prereqs */ slist_iter( prereq, action_t, synapse->inputs, lpc, crm_debug_3("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_debug_3("Marking input %d complete", action_id); prereq->complete = TRUE; } else if(prereq->complete == FALSE) { crm_debug_3("Inputs for synapse %d not satisfied", synapse->id); synapse->triggers_complete = FALSE; } ); } } void fire_synapse(synapse_t *synapse) { if(synapse == NULL) { crm_err("Synapse was NULL!"); return; } crm_debug_3("Checking if synapse %d needs to be fired", synapse->id); if(synapse->complete) { crm_debug_3("Skipping complete synapse %d", synapse->id); return; } else if(synapse->triggers_complete == FALSE) { crm_debug_3("Synapse %d not yet satisfied", synapse->id); return; } crm_debug("All inputs for synapse %d satisfied... invoking actions", synapse->id); synapse->complete = TRUE; slist_iter( action, action_t, synapse->actions, lpc, /* allow some leeway */ int tmp_time = 2 * action->timeout; gboolean passed = FALSE; action->invoked = TRUE; /* Invoke the action and start the timer */ passed = initiate_action(action); if(passed == FALSE) { crm_err("Failed initiating <%s id=%d> in synapse %d", crm_element_name(action->xml), action->id, synapse->id); send_complete("Action init failed", action->xml, te_failed, i_cancel); return; } if(tmp_time > transition_timer->timeout) { crm_debug("Action %d: Increasing IDLE timer to %d", action->id, tmp_time); transition_timer->timeout = tmp_time; } ); crm_debug("Synapse %d complete", synapse->id); } gboolean confirm_synapse(synapse_t *synapse, int action_id) { gboolean complete = TRUE; synapse->confirmed = TRUE; slist_iter( action, action_t, synapse->actions, lpc, if(action->complete == FALSE) { complete = FALSE; synapse->confirmed = FALSE; crm_debug_3("Found an incomplete action" " - transition not complete"); break; } ); if(complete) { crm_debug("Synapse %d complete (action=%d)", synapse->id, action_id); } return complete; } void process_trigger(int action_id) { if(te_fsa_state != s_in_transition) { int unconfirmed = unconfirmed_actions(); crm_info("Trigger from action %d (%d more) discarded:" " Not in transition", action_id, unconfirmed); if(unconfirmed == 0) { send_complete("Last pending action confirmed", NULL, te_abort_confirmed, i_cmd_complete); } return; } graph_complete = TRUE; crm_debug_3("Processing trigger from action %d", action_id); /* something happened, stop the timer and start it again at the end */ stop_te_timer(transition_timer); slist_iter( synapse, synapse_t, graph, lpc, if(synapse->confirmed) { crm_debug_3("Skipping confirmed synapse %d", synapse->id); continue; } check_synapse_triggers(synapse, action_id); fire_synapse(synapse); if(graph == NULL) { crm_err("Trigger processing aborted after failed synapse"); break; } crm_debug_3("Checking if %d is confirmed", synapse->id); if(synapse->complete == FALSE) { crm_debug_3("Found an incomplete synapse" " - transition not complete"); /* indicate that the transition is not yet complete */ graph_complete = FALSE; } else if(synapse->confirmed == FALSE) { gboolean confirmed = confirm_synapse(synapse,action_id); graph_complete = graph_complete && confirmed; } crm_debug_3("%d is %s", synapse->id, synapse->confirmed?"confirmed":synapse->complete?"complete":"pending"); ); } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index 58606c2ec7..6a3008b377 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,527 +1,527 @@ -/* $Id: utils.c,v 1.42 2005/07/19 19:06:42 andrew Exp $ */ +/* $Id: utils.c,v 1.43 2005/08/17 08:57:28 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 cib_t *te_cib_conn; extern int global_transition_timer; extern int transition_counter; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); gboolean timer_callback(gpointer data); int unconfirmed_actions(void) { int unconfirmed = 0; crm_debug_2("Unconfirmed actions..."); slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, if(action->invoked && action->complete == FALSE) { unconfirmed++; crm_debug("Action %d: unconfirmed",action->id); } ); ); return unconfirmed; } void send_complete(const char *text, crm_data_t *msg, te_reason_t reason, te_fsa_input_t input) { int log_level = LOG_DEBUG; int unconfirmed = unconfirmed_actions(); int pending_callbacks = num_cib_op_callbacks(); HA_Message *cmd = NULL; const char *op = CRM_OP_TEABORT; static te_reason_t last_reason = te_done; static crm_data_t *last_msg = NULL; static const char *last_text = NULL; te_fsa_state_t last_state = te_fsa_state; te_fsa_state = te_state_matrix[input][te_fsa_state]; if(te_fsa_state != last_state) { crm_debug("State change %d->%d", last_state, te_fsa_state); } if(te_fsa_state == s_abort_pending && (unconfirmed == 0 || reason == te_timeout || reason == te_abort_timeout)) { crm_debug("Faking i_cmd_complete: %d/%d", last_state, input); te_fsa_state = te_state_matrix[i_cmd_complete][te_fsa_state]; crm_debug("State change %d->%d", last_state, te_fsa_state); crm_debug("Stopping abort timer"); stop_te_timer(abort_timer); } else if(te_fsa_state ==s_abort_pending && te_fsa_state !=last_state) { abort_timer->timeout = transition_timer->timeout; crm_info("Starting abort timer: %dms", abort_timer->timeout); start_te_timer(abort_timer); } if(te_fsa_state == s_updates_pending && pending_callbacks == 0) { crm_debug("Faking i_cib_complete: %d/%d", last_state, input); te_fsa_state = te_state_matrix[i_cib_complete][te_fsa_state]; crm_debug("State change %d->%d", last_state, te_fsa_state); } if(te_fsa_state == last_state && (last_state==s_abort_pending || last_state==s_updates_pending)) { crm_info("Transaction already cancelled"); } switch(reason) { case te_update: te_log_action( LOG_DEBUG, "%d - Transition status: %s by CIB update: %s", transition_counter, last_state!=s_idle?"Aborted":"Triggered", text); if(msg != NULL) { if(safe_str_eq(crm_element_name(msg), XML_TAG_CIB)) { crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg); crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB); crm_debug("Cause:" " full CIB replace/update"); copy_in_properties(generation, msg); crm_log_xml_debug(generation, "[generation]"); crm_log_xml_debug(status, "[in ]"); free_xml(generation); } else { crm_log_xml_debug(msg, "Cause"); } } break; case te_halt: te_log_action( LOG_INFO, "%d - Transition status: Stopped%s%s", transition_counter, text?": ":"", text?text:""); break; case te_abort_confirmed: te_log_action( LOG_INFO, "%d - Transition status: Confirmed Stopped%s%s", transition_counter, text?": ":"", text?text:""); break; case te_abort: te_log_action( LOG_INFO,"%d - Transition status: Stopped%s%s", transition_counter, text?": ":"", text?text:""); break; case te_done: te_log_action( LOG_INFO,"%d - Transition status: Complete%s%s", transition_counter, text?": ":"", text?text:""); break; case te_abort_timeout: te_log_action( LOG_ERR, "%d - Transition status: Abort timed out after %dms", transition_counter, abort_timer->timeout); log_level = LOG_WARNING; break; case te_timeout: te_log_action( LOG_ERR, "%d - Transition status: Timed out after %dms", transition_counter, transition_timer->timeout); log_level = LOG_WARNING; break; case te_failed: te_log_action( LOG_ERR, "%d - Transition status: Aborted by failed action: %s", transition_counter, text); crm_log_xml_debug(msg, "Cause"); log_level = LOG_WARNING; break; } if(te_fsa_state != s_idle) { if(last_text == NULL) { /* store the original input */ crm_debug("Storing TE input."); last_msg = NULL; if(msg != NULL) { last_msg = copy_xml(msg); } last_text = text; last_reason = reason; } crm_info("%d - Delay abort until %d updates and %d actions complete (state=%d).", transition_counter, pending_callbacks, unconfirmed, te_fsa_state); return; } else if(last_text != NULL) { /* restore the original reason we aborted */ crm_debug("Restoring TE input."); msg = last_msg; text = last_text; reason = last_reason; last_msg = NULL; last_text = NULL; } CRM_DEV_ASSERT(pending_callbacks == 0); print_state(log_level); initialize_graph(); switch(reason) { case te_abort: case te_abort_timeout: case te_failed: case te_update: op = CRM_OP_TEABORT; break; case te_halt: op = CRM_OP_TECOMPLETE; break; case te_abort_confirmed: op = CRM_OP_TEABORTED; break; case te_done: op = CRM_OP_TECOMPLETE; break; case te_timeout: op = CRM_OP_TETIMEOUT; break; } cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(text != NULL) { ha_msg_add(cmd, "message", text); } free_xml(last_msg); #ifdef TESTING if(reason == te_done) { crm_log_message(LOG_INFO, cmd); } else { crm_log_message(LOG_ERR, cmd); } g_main_quit(mainloop); return; #else send_ipc_message(crm_ch, cmd); #endif #if 0 if(is_ipc_empty(crm_ch) && is_ipc_empty(te_cib_conn->cmds->channel(te_cib_conn)) ) { static gboolean mem_needs_init = TRUE; if(mem_needs_init) { crm_debug("Reached a stable point:" " reseting memory usage stats to zero"); crm_zero_mem_stats(NULL); mem_needs_init = FALSE; } else { crm_err("Reached a stable point:" " checking memory usage"); crm_mem_stats(NULL); } } #endif } void print_state(unsigned int log_level) { gboolean first_synapse = TRUE; if(graph == NULL && log_level > LOG_DEBUG) { crm_debug("## Empty transition graph ##"); return; } slist_iter( synapse, synapse_t, graph, lpc, first_synapse = FALSE; crm_log_maybe(log_level, "Synapse %d %s", synapse->id, synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending"); if(synapse->confirmed == FALSE) { slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, log_level); ); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, log_level); ); } ); if(first_synapse && log_level > LOG_DEBUG) { crm_debug("## Empty transition graph ##"); return; } } void print_input(const char *prefix, action_t *input, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)", prefix, input->id, input->complete?"Satisfied":"Pending", actiontype2text(input->type)); if(input->complete == FALSE) { crm_log_xml(log_level+2, "\t\t\tRaw input: ", input->xml); } } void print_action(const char *prefix, action_t *action, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight": action->sent_update?"Update sent":"Pending", action->can_fail?"can":"cannot"); switch(action->type) { case action_type_pseudo: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tResource Op: %s/%s on %s (%s)", prefix, crm_element_value( action->xml, XML_LRM_ATTR_RSCID), crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET), crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID)); break; case action_type_crm: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tCRM Op: %s on %s (%s)", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET), crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID)); break; } if(action->timeout > 0 || action->timer->source_id > 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); } if(action->complete == FALSE) { crm_log_xml(log_level+2, "\t\t\tRaw action: ", action->xml); } } gboolean timer_callback(gpointer data) { te_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (te_timer_t*)data; if(timer->source_id > 0) { - g_source_remove(timer->source_id); + Gmain_timeout_remove(timer->source_id); } timer->source_id = -1; crm_warn("Timer popped in state=%d", te_fsa_state); if(timer->reason == timeout_abort) { crm_err("Transition abort timeout reached..." " marking transition complete."); send_complete(XML_ATTR_TIMEOUT, NULL, te_abort_timeout, i_cmd_complete); return TRUE; } else if(te_fsa_state != s_in_transition) { crm_debug("Ignoring timeout while not in transition"); return TRUE; } else if(timer->reason == timeout_timeout) { /* global timeout - abort the transition */ crm_warn("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout, i_cancel); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } else if(timer->reason == timeout_action_warn) { print_action("Action missed its timeout", timer->action, LOG_WARNING); return TRUE; } else { /* fail the action * - which may or may not abort the transition */ /* TODO: send a cancel notice to the LRM */ /* TODO: use the ack from above to update the CIB */ return cib_action_update(timer->action, LRM_OP_TIMEOUT); } } gboolean start_te_timer(te_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->timeout > 0) { timer->source_id = Gmain_timeout_add( timer->timeout, timer_callback, (void*)timer); return TRUE; } else if(timer->timeout < 0) { crm_err("Tried to start timer with -ve period"); } else { crm_debug_3("#!!#!!# Timer already running (%d)", timer->source_id); } return FALSE; } gboolean stop_te_timer(te_timer_t *timer) { if(timer == NULL) { return FALSE; } if(((int)timer->source_id) > 0) { - g_source_remove(timer->source_id); + Gmain_timeout_remove(timer->source_id); timer->source_id = -2; } else { return FALSE; } return TRUE; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } const char * get_rsc_state(const char *task, op_status_t status) { if(safe_str_eq(CRMD_ACTION_START, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_START_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STARTED; } else { return CRMD_ACTION_START_FAIL; } } else if(safe_str_eq(CRMD_ACTION_STOP, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_STOP_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STOPPED; } else { return CRMD_ACTION_STOP_FAIL; } } else { if(safe_str_eq(CRMD_ACTION_MON, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_MON_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_MON_OK; } else { return CRMD_ACTION_MON_FAIL; } } else { const char *rsc_state = NULL; if(status == LRM_OP_PENDING) { rsc_state = CRMD_ACTION_GENERIC_PENDING; } else if(status == LRM_OP_DONE) { rsc_state = CRMD_ACTION_GENERIC_OK; } else { rsc_state = CRMD_ACTION_GENERIC_FAIL; } crm_warn("Using status \"%s\" for op \"%s\"..." " this is still in the experimental stage.", rsc_state, task); return rsc_state; } } }