diff --git a/crmd/control.c b/crmd/control.c index c0500ea206..facb597c39 100644 --- a/crmd/control.c +++ b/crmd/control.c @@ -1,919 +1,935 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "../lib/common/stack.h" #include #include #include #include #include #include #include #include #include char *ipc_server = NULL; extern gboolean crm_connect_corosync(void); extern void crmd_ha_connection_destroy(gpointer user_data); void crm_shutdown(int nsig); gboolean crm_read_options(gpointer user_data); gboolean fsa_has_quorum = FALSE; GHashTable *ipc_clients = NULL; crm_trigger_t *fsa_source = NULL; crm_trigger_t *config_read = NULL; /* A_HA_CONNECT */ void do_ha_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 registered = FALSE; if(action & A_HA_DISCONNECT) { if(is_openais_cluster()) { crm_peer_destroy(); terminate_ais_connection(); crm_info("Disconnected from OpenAIS"); #if SUPPORT_HEARTBEAT } else if(fsa_cluster_conn != NULL) { set_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn, FALSE); crm_info("Disconnected from Heartbeat"); #endif } } if(action & A_HA_CONNECT) { crm_set_status_callback(&ais_status_callback); if(is_openais_cluster()) { #if SUPPORT_COROSYNC registered = crm_connect_corosync(); #endif } else if(is_heartbeat_cluster()) { #if SUPPORT_HEARTBEAT registered = crm_cluster_connect( &fsa_our_uname, &fsa_our_uuid, crmd_ha_msg_callback, crmd_ha_connection_destroy, &fsa_cluster_conn); #endif } #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { crm_debug_3("Be informed of Node Status changes"); if (registered && fsa_cluster_conn->llc_ops->set_nstatus_callback( fsa_cluster_conn, crmd_ha_status_callback, fsa_cluster_conn) != HA_OK){ crm_err("Cannot set nstatus callback: %s", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); registered = FALSE; } crm_debug_3("Be informed of CRM Client Status changes"); if (registered && fsa_cluster_conn->llc_ops->set_cstatus_callback( fsa_cluster_conn, crmd_client_status_callback, fsa_cluster_conn) != HA_OK) { crm_err("Cannot set cstatus callback: %s", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); registered = FALSE; } if(registered) { crm_debug_3("Requesting an initial dump of CRMD client_status"); fsa_cluster_conn->llc_ops->client_status( fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); } } #endif if(registered == FALSE) { set_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } clear_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); crm_info("Connected to the cluster"); } if(action & ~(A_HA_CONNECT|A_HA_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } } /* A_SHUTDOWN */ void do_shutdown(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) { /* just in case */ set_bit_inplace(fsa_input_register, R_SHUTDOWN); if(is_heartbeat_cluster()) { if(is_set(fsa_input_register, pe_subsystem->flag_connected)) { crm_info("Terminating the %s", pe_subsystem->name); if(stop_subsystem(pe_subsystem, TRUE) == FALSE) { /* its gone... */ crm_err("Faking %s exit", pe_subsystem->name); clear_bit_inplace(fsa_input_register, pe_subsystem->flag_connected); } else { crm_info("Waiting for subsystems to exit"); crmd_fsa_stall(NULL); } } crm_info("All subsystems stopped, continuing"); } if(stonith_api) { /* Prevent it from comming up again */ clear_bit_inplace(fsa_input_register, R_ST_REQUIRED); crm_info("Disconnecting STONITH..."); stonith_api->cmds->disconnect(stonith_api); } } /* A_SHUTDOWN_REQ */ void do_shutdown_req(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) { xmlNode *msg = NULL; crm_info("Sending shutdown request to DC: %s", crm_str(fsa_our_dc)); msg = create_request( CRM_OP_SHUTDOWN_REQ, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); /* set_bit_inplace(fsa_input_register, R_STAYDOWN); */ if(send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } free_xml(msg); } extern char *max_generation_from; extern xmlNode *max_generation_xml; extern GHashTable *resources; extern GHashTable *voted; extern GHashTable *reload_hash; void log_connected_client(gpointer key, gpointer value, gpointer user_data); void log_connected_client(gpointer key, gpointer value, gpointer user_data) { crmd_client_t *client = value; crm_err("%s is still connected at exit", client->table_key); } static void free_mem(fsa_data_t *msg_data) { g_main_loop_quit(crmd_mainloop); g_main_loop_unref(crmd_mainloop); #if SUPPORT_HEARTBEAT if(fsa_cluster_conn) { fsa_cluster_conn->llc_ops->delete(fsa_cluster_conn); fsa_cluster_conn = NULL; } #endif slist_destroy(fsa_data_t, fsa_data, fsa_message_queue, crm_info("Dropping %s: [ state=%s cause=%s origin=%s ]", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); delete_fsa_input(fsa_data); ); delete_fsa_input(msg_data); if(ipc_clients) { crm_debug("Number of connected clients: %d", g_hash_table_size(ipc_clients)); /* g_hash_table_foreach(ipc_clients, log_connected_client, NULL); */ g_hash_table_destroy(ipc_clients); } empty_uuid_cache(); crm_peer_destroy(); clear_bit_inplace(fsa_input_register, R_CCM_DATA); if(te_subsystem->client && te_subsystem->client->client_source) { crm_debug("Full destroy: TE"); G_main_del_IPC_Channel(te_subsystem->client->client_source); } else { crm_debug("Partial destroy: TE"); crmd_ipc_connection_destroy(te_subsystem->client); } crm_free(te_subsystem); if(pe_subsystem->client && pe_subsystem->client->client_source) { crm_debug("Full destroy: PE"); G_main_del_IPC_Channel(pe_subsystem->client->client_source); } else { crm_debug("Partial destroy: PE"); crmd_ipc_connection_destroy(pe_subsystem->client); } crm_free(pe_subsystem); crm_free(cib_subsystem); if(integrated_nodes) { g_hash_table_destroy(integrated_nodes); } if(finalized_nodes) { g_hash_table_destroy(finalized_nodes); } if(confirmed_nodes) { g_hash_table_destroy(confirmed_nodes); } if(reload_hash) { g_hash_table_destroy(reload_hash); } if(resources) { g_hash_table_destroy(resources); } if(voted) { g_hash_table_destroy(voted); } cib_delete(fsa_cib_conn); fsa_cib_conn = NULL; if(fsa_lrm_conn) { fsa_lrm_conn->lrm_ops->delete(fsa_lrm_conn); } + crm_free(transition_timer); crm_free(integration_timer); crm_free(finalization_timer); crm_free(election_trigger); crm_free(election_timeout); crm_free(shutdown_escalation_timer); crm_free(wait_timer); crm_free(recheck_timer); crm_free(fsa_our_dc_version); crm_free(fsa_our_uname); crm_free(fsa_our_uuid); crm_free(fsa_our_dc); crm_free(ipc_server); crm_free(max_generation_from); free_xml(max_generation_xml); crm_xml_cleanup(); } /* A_EXIT_0, A_EXIT_1 */ void do_exit(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) { int exit_code = 0; int log_level = LOG_INFO; const char *exit_type = "gracefully"; if(action & A_EXIT_1) { exit_code = 1; log_level = LOG_ERR; exit_type = "forcefully"; } verify_stopped(cur_state, LOG_ERR); do_crm_log(log_level, "Performing %s - %s exiting the CRMd", fsa_action2string(action), exit_type); if(is_set(fsa_input_register, R_IN_RECOVERY)) { crm_err("Could not recover from internal error"); exit_code = 2; } if(is_set(fsa_input_register, R_STAYDOWN)) { crm_warn("Inhibiting respawn by Heartbeat"); exit_code = 100; } free_mem(msg_data); crm_info("[%s] stopped (%d)", crm_system_name, exit_code); cl_flush_logs(); exit(exit_code); } /* A_STARTUP */ void do_startup(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) { int was_error = 0; int interval = 1; /* seconds between DC heartbeats */ crm_debug("Registering Signal Handlers"); mainloop_add_signal(SIGTERM, crm_shutdown); fsa_source = mainloop_add_trigger(G_PRIORITY_HIGH, crm_fsa_trigger, NULL); config_read = mainloop_add_trigger(G_PRIORITY_HIGH, crm_read_options, NULL); ipc_clients = g_hash_table_new(crm_str_hash, g_str_equal); crm_debug("Creating CIB and LRM objects"); fsa_cib_conn = cib_new(); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); /* set up the timers */ + crm_malloc0(transition_timer, sizeof(fsa_timer_t)); crm_malloc0(integration_timer, sizeof(fsa_timer_t)); crm_malloc0(finalization_timer, sizeof(fsa_timer_t)); crm_malloc0(election_trigger, sizeof(fsa_timer_t)); crm_malloc0(election_timeout, sizeof(fsa_timer_t)); crm_malloc0(shutdown_escalation_timer, sizeof(fsa_timer_t)); crm_malloc0(wait_timer, sizeof(fsa_timer_t)); crm_malloc0(recheck_timer, sizeof(fsa_timer_t)); interval = interval * 1000; if(election_trigger != NULL) { election_trigger->source_id = 0; election_trigger->period_ms = -1; election_trigger->fsa_input = I_DC_TIMEOUT; election_trigger->callback = crm_timer_popped; election_trigger->repeat = FALSE; } else { was_error = TRUE; } if(election_timeout != NULL) { election_timeout->source_id = 0; election_timeout->period_ms = -1; election_timeout->fsa_input = I_ELECTION_DC; election_timeout->callback = crm_timer_popped; election_timeout->repeat = FALSE; } else { was_error = TRUE; } + if(transition_timer != NULL) { + transition_timer->source_id = 0; + transition_timer->period_ms = -1; + transition_timer->fsa_input = I_PE_CALC; + transition_timer->callback = crm_timer_popped; + transition_timer->repeat = FALSE; + } else { + was_error = TRUE; + } + if(integration_timer != NULL) { integration_timer->source_id = 0; integration_timer->period_ms = -1; integration_timer->fsa_input = I_INTEGRATED; integration_timer->callback = crm_timer_popped; integration_timer->repeat = FALSE; } else { was_error = TRUE; } if(finalization_timer != NULL) { finalization_timer->source_id = 0; finalization_timer->period_ms = -1; finalization_timer->fsa_input = I_FINALIZED; finalization_timer->callback = crm_timer_popped; finalization_timer->repeat = FALSE; /* for possible enabling... a bug in the join protocol left * a slave in S_PENDING while we think its in S_NOT_DC * * raising I_FINALIZED put us into a transition loop which is * never resolved. * in this loop we continually send probes which the node * NACK's because its in S_PENDING * * if we have nodes where heartbeat is active but the * CRM is not... then this will be handled in the * integration phase */ finalization_timer->fsa_input = I_ELECTION; } else { was_error = TRUE; } if(shutdown_escalation_timer != NULL) { shutdown_escalation_timer->source_id = 0; shutdown_escalation_timer->period_ms = -1; shutdown_escalation_timer->fsa_input = I_STOP; shutdown_escalation_timer->callback = crm_timer_popped; shutdown_escalation_timer->repeat = FALSE; } else { was_error = TRUE; } if(wait_timer != NULL) { wait_timer->source_id = 0; wait_timer->period_ms = 2000; wait_timer->fsa_input = I_NULL; wait_timer->callback = crm_timer_popped; wait_timer->repeat = FALSE; } else { was_error = TRUE; } if(recheck_timer != NULL) { recheck_timer->source_id = 0; recheck_timer->period_ms = -1; recheck_timer->fsa_input = I_PE_CALC; recheck_timer->callback = crm_timer_popped; recheck_timer->repeat = FALSE; } else { was_error = TRUE; } /* set up the sub systems */ crm_malloc0(cib_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc0(te_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc0(pe_subsystem, sizeof(struct crm_subsystem_s)); if(cib_subsystem != NULL) { cib_subsystem->pid = -1; cib_subsystem->path = CRM_DAEMON_DIR; cib_subsystem->name = CRM_SYSTEM_CIB; cib_subsystem->command = CRM_DAEMON_DIR"/"CRM_SYSTEM_CIB; cib_subsystem->args = "-VVc"; cib_subsystem->flag_connected = R_CIB_CONNECTED; cib_subsystem->flag_required = R_CIB_REQUIRED; } else { was_error = TRUE; } if(te_subsystem != NULL) { te_subsystem->pid = -1; te_subsystem->path = CRM_DAEMON_DIR; te_subsystem->name = CRM_SYSTEM_TENGINE; te_subsystem->command = CRM_DAEMON_DIR"/"CRM_SYSTEM_TENGINE; te_subsystem->args = NULL; te_subsystem->flag_connected = R_TE_CONNECTED; te_subsystem->flag_required = R_TE_REQUIRED; } else { was_error = TRUE; } if(pe_subsystem != NULL) { pe_subsystem->pid = -1; pe_subsystem->path = CRM_DAEMON_DIR; pe_subsystem->name = CRM_SYSTEM_PENGINE; pe_subsystem->command = CRM_DAEMON_DIR"/"CRM_SYSTEM_PENGINE; pe_subsystem->args = NULL; pe_subsystem->flag_connected = R_PE_CONNECTED; pe_subsystem->flag_required = R_PE_REQUIRED; } else { was_error = TRUE; } if(was_error) { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } welcomed_nodes = g_hash_table_new_full( crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); integrated_nodes = g_hash_table_new_full( crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); finalized_nodes = g_hash_table_new_full( crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); confirmed_nodes = g_hash_table_new_full( crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); set_sigchld_proctrack(G_PRIORITY_HIGH,DEFAULT_MAXDISPATCHTIME); } /* A_STOP */ void do_stop(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) { register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } /* A_STARTED */ void do_started(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) { if(cur_state != S_STARTING) { crm_err("Start cancelled... %s", fsa_state2string(cur_state)); return; } else if(is_set(fsa_input_register, R_CCM_DATA) == FALSE) { crm_info("Delaying start, no membership data (%.16llx)", R_CCM_DATA); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_LRM_CONNECTED) == FALSE) { crm_info("Delaying start, LRM not connected (%.16llx)", R_LRM_CONNECTED); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { crm_info("Delaying start, CIB not connected (%.16llx)", R_CIB_CONNECTED); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_READ_CONFIG) == FALSE) { crm_info("Delaying start, Config not read (%.16llx)", R_READ_CONFIG); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_PEER_DATA) == FALSE) { HA_Message *msg = NULL; /* try reading from HA */ crm_info("Delaying start, No peer data (%.16llx)", R_PEER_DATA); crm_debug_3("Looking for a HA message"); #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { msg = fsa_cluster_conn->llc_ops->readmsg(fsa_cluster_conn, 0); } #endif if(msg != NULL) { crm_debug_3("There was a HA message"); crm_msg_del(msg); } crmd_fsa_stall(NULL); return; } crm_debug("Init server comms"); if(ipc_server == NULL) { ipc_server = crm_strdup(CRM_SYSTEM_CRMD); } if(init_server_ipc_comms(ipc_server, crmd_client_connect, default_ipc_connection_destroy)) { crm_err("Couldn't start IPC server"); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } if(stonith_reconnect == NULL) { int dummy; stonith_reconnect = mainloop_add_trigger( G_PRIORITY_LOW, te_connect_stonith, &dummy); } set_bit_inplace(fsa_input_register, R_ST_REQUIRED); mainloop_set_trigger(stonith_reconnect); crm_info("The local CRM is operational"); clear_bit_inplace(fsa_input_register, R_STARTING); register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL); } /* A_RECOVER */ void do_recover(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) { set_bit_inplace(fsa_input_register, R_IN_RECOVERY); crm_err("Action %s (%.16llx) not supported", fsa_action2string(action), action); register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } pe_cluster_option crmd_opts[] = { /* name, old-name, validate, default, description */ { "dc-version", NULL, "string", NULL, "none", NULL, "Version of Pacemaker on the cluster's DC.", "Includes the hash which identifies the exact Mercurial changeset it was built from. Used for diagnostic purposes." }, { "cluster-infrastructure", NULL, "string", NULL, "heartbeat", NULL, "The messaging stack on which Pacemaker is currently running.", "Used for informational and diagnostic purposes." }, { XML_CONFIG_ATTR_DC_DEADTIME, "dc_deadtime", "time", NULL, "20s", &check_time, "How long to wait for a response from other nodes during startup.", "The \"correct\" value will depend on the speed/load of your network and the type of switches used." }, { XML_CONFIG_ATTR_RECHECK, "cluster_recheck_interval", "time", "Zero disables polling. Positive values are an interval in seconds (unless other SI units are specified. eg. 5min)", "15min", &check_timer, "Polling interval for time based changes to options, resource parameters and constraints.", "The Cluster is primarily event driven, however the configuration can have elements that change based on time." " To ensure these changes take effect, we can optionally poll the cluster's status for changes." }, { XML_CONFIG_ATTR_ELECTION_FAIL, "election_timeout", "time", NULL, "2min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { XML_CONFIG_ATTR_FORCE_QUIT, "shutdown_escalation", "time", NULL, "20min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { "crmd-integration-timeout", NULL, "time", NULL, "3min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { "crmd-finalization-timeout", NULL, "time", NULL, "30min", &check_timer, "*** Advanced Use Only ***.", "If you need to adjust this value, it probably indicates the presence of a bug." }, + { "crmd-transition-delay", NULL, "time", NULL, "0s", &check_timer, "*** Advanced Use Only ***\nEnabling this option will slow down cluster recovery under all conditions", "Delay cluster recovery for the configured interval to allow for additional/related events to occur.\nUseful if your configuration is sensitive to the order in which ping updates arrive." }, { XML_ATTR_EXPECTED_VOTES, NULL, "integer", NULL, "2", &check_number, "The number of nodes expected to be in the cluster", "Used to calculate quorum in openais based clusters." }, }; void crmd_metadata(void) { config_metadata("CRM Daemon", "1.0", "CRM Daemon Options", "This is a fake resource that details the options that can be configured for the CRM Daemon.", crmd_opts, DIMOF(crmd_opts)); } static void verify_crmd_options(GHashTable *options) { verify_all_options(options, crmd_opts, DIMOF(crmd_opts)); } static const char * crmd_pref(GHashTable *options, const char *name) { return get_cluster_pref(options, crmd_opts, DIMOF(crmd_opts), name); } static void config_query_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { const char *value = NULL; GHashTable *config_hash = NULL; ha_time_t *now = new_ha_date(TRUE); if(rc != cib_ok) { fsa_data_t *msg_data = NULL; crm_err("Local CIB query resulted in an error: %s", cib_error2string(rc)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); if(rc == cib_bad_permissions || rc == cib_dtd_validation || rc == cib_bad_digest || rc == cib_bad_config) { crm_err("The cluster is mis-configured - shutting down and staying down"); set_bit_inplace(fsa_input_register, R_STAYDOWN); } goto bail; } crm_debug("Call %d : Parsing CIB options", call_id); config_hash = g_hash_table_new_full( crm_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); unpack_instance_attributes( output, output, XML_CIB_TAG_PROPSET, NULL, config_hash, CIB_OPTIONS_FIRST, FALSE, now); verify_crmd_options(config_hash); value = crmd_pref(config_hash, XML_CONFIG_ATTR_DC_DEADTIME); election_trigger->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, XML_CONFIG_ATTR_FORCE_QUIT); shutdown_escalation_timer->period_ms = crm_get_msec(value); crm_info("Shutdown escalation occurs after: %dms", shutdown_escalation_timer->period_ms); value = crmd_pref(config_hash, XML_CONFIG_ATTR_ELECTION_FAIL); election_timeout->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, XML_CONFIG_ATTR_RECHECK); recheck_timer->period_ms = crm_get_msec(value); crm_info("Checking for expired actions every %dms", recheck_timer->period_ms); + value = crmd_pref(config_hash, "crmd-transition-delay"); + transition_timer->period_ms = crm_get_msec(value); + value = crmd_pref(config_hash, "crmd-integration-timeout"); integration_timer->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, "crmd-finalization-timeout"); finalization_timer->period_ms = crm_get_msec(value); #if SUPPORT_COROSYNC if(is_classic_ais_cluster()) { value = crmd_pref(config_hash, XML_ATTR_EXPECTED_VOTES); crm_info("Sending expected-votes=%s to corosync", value); send_ais_text(crm_class_quorum, value, TRUE, NULL, crm_msg_ais); } #endif set_bit_inplace(fsa_input_register, R_READ_CONFIG); crm_debug_3("Triggering FSA: %s", __FUNCTION__); mainloop_set_trigger(fsa_source); g_hash_table_destroy(config_hash); bail: free_ha_date(now); } gboolean crm_read_options(gpointer user_data) { int call_id = fsa_cib_conn->cmds->query( fsa_cib_conn, XML_CIB_TAG_CRMCONFIG, NULL, cib_scope_local); add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, config_query_callback); crm_debug_2("Querying the CIB... call %d", call_id); return TRUE; } /* A_READCONFIG */ void do_read_config(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) { mainloop_set_trigger(config_read); } void crm_shutdown(int nsig) { if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) { if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_err("Escalating the shutdown"); register_fsa_input_before(C_SHUTDOWN, I_ERROR, NULL); } else { crm_info("Requesting shutdown"); set_bit_inplace(fsa_input_register, R_SHUTDOWN); register_fsa_input(C_SHUTDOWN,I_SHUTDOWN,NULL); if(shutdown_escalation_timer->period_ms < 1) { const char *value = crmd_pref(NULL, XML_CONFIG_ATTR_FORCE_QUIT); int msec = crm_get_msec(value); crm_info("Using default shutdown escalation: %dms", msec); shutdown_escalation_timer->period_ms = msec; } /* cant rely on this... */ crm_notice("Forcing shutdown in: %dms", shutdown_escalation_timer->period_ms); crm_timer_start(shutdown_escalation_timer); } } else { crm_info("exit from shutdown"); exit(LSB_EXIT_OK); } } static void default_cib_update_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { if(rc != cib_ok) { fsa_data_t *msg_data = NULL; crm_err("CIB Update failed: %s", cib_error2string(rc)); crm_log_xml_warn(output, "update:failed"); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } #if SUPPORT_HEARTBEAT static void populate_cib_nodes_ha(gboolean with_client_status) { int call_id = 0; const char *ha_node = NULL; xmlNode *cib_node_list = NULL; if(fsa_cluster_conn == NULL) { crm_debug("Not connected"); return; } /* Async get client status information in the cluster */ crm_info("Requesting the list of configured nodes"); fsa_cluster_conn->llc_ops->init_nodewalk(fsa_cluster_conn); cib_node_list = create_xml_node(NULL, XML_CIB_TAG_NODES); do { const char *ha_node_type = NULL; const char *ha_node_uuid = NULL; xmlNode *cib_new_node = NULL; ha_node = fsa_cluster_conn->llc_ops->nextnode(fsa_cluster_conn); if(ha_node == NULL) { continue; } ha_node_type = fsa_cluster_conn->llc_ops->node_type( fsa_cluster_conn, ha_node); if(safe_str_neq(NORMALNODE, ha_node_type)) { crm_debug("Node %s: skipping '%s'", ha_node, ha_node_type); continue; } ha_node_uuid = get_uuid(ha_node); if(ha_node_uuid == NULL) { crm_warn("Node %s: no uuid found", ha_node); continue; } crm_debug("Node: %s (uuid: %s)", ha_node, ha_node_uuid); cib_new_node = create_xml_node(cib_node_list, XML_CIB_TAG_NODE); crm_xml_add(cib_new_node, XML_ATTR_ID, ha_node_uuid); crm_xml_add(cib_new_node, XML_ATTR_UNAME, ha_node); crm_xml_add(cib_new_node, XML_ATTR_TYPE, ha_node_type); } while(ha_node != NULL); fsa_cluster_conn->llc_ops->end_nodewalk(fsa_cluster_conn); /* Now update the CIB with the list of nodes */ fsa_cib_update( XML_CIB_TAG_NODES, cib_node_list, cib_scope_local|cib_quorum_override, call_id, NULL); add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, default_cib_update_callback); free_xml(cib_node_list); crm_debug_2("Complete"); } #endif static void create_cib_node_definition( gpointer key, gpointer value, gpointer user_data) { crm_node_t *node = value; xmlNode *cib_nodes = user_data; xmlNode *cib_new_node = NULL; cib_new_node = create_xml_node(cib_nodes, XML_CIB_TAG_NODE); crm_xml_add(cib_new_node, XML_ATTR_ID, node->uuid); crm_xml_add(cib_new_node, XML_ATTR_UNAME, node->uname); crm_xml_add(cib_new_node, XML_ATTR_TYPE, NORMALNODE); } void populate_cib_nodes(gboolean with_client_status) { int call_id = 0; xmlNode *cib_node_list = NULL; #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { populate_cib_nodes_ha(with_client_status); return; } #endif cib_node_list = create_xml_node(NULL, XML_CIB_TAG_NODES); g_hash_table_foreach( crm_peer_cache, create_cib_node_definition, cib_node_list); fsa_cib_update( XML_CIB_TAG_NODES, cib_node_list, cib_scope_local|cib_quorum_override, call_id, NULL); add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, default_cib_update_callback); free_xml(cib_node_list); crm_debug_2("Complete"); } diff --git a/crmd/crmd_fsa.h b/crmd/crmd_fsa.h old mode 100644 new mode 100755 index 4cb517b3e7..62527cd16e --- a/crmd/crmd_fsa.h +++ b/crmd/crmd_fsa.h @@ -1,135 +1,136 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CRMD_FSA__H #define CRMD_FSA__H #include #include #include #include #include #include #include #if SUPPORT_HEARTBEAT extern ll_cluster_t *fsa_cluster_conn; #endif /* copy from struct client_child in heartbeat.h * * Plus a couple of other things */ struct crm_subsystem_s { pid_t pid; /* Process id of child process */ const char* name; /* executable name */ const char* path; /* Command location */ const char* command; /* Command with path */ const char* args; /* Command arguments */ crmd_client_t* client; /* Client connection object */ gboolean sent_kill; IPC_Channel *ipc; /* How can we communicate with it */ long long flag_connected; /* */ long long flag_required; /* */ }; typedef struct fsa_timer_s fsa_timer_t; struct fsa_timer_s { guint source_id; /* timer source id */ int period_ms; /* timer period */ enum crmd_fsa_input fsa_input; gboolean (*callback)(gpointer data); gboolean repeat; }; enum fsa_data_type { fsa_dt_none, fsa_dt_ha_msg, fsa_dt_xml, fsa_dt_lrm, }; typedef struct fsa_data_s fsa_data_t; struct fsa_data_s { int id; enum crmd_fsa_input fsa_input; enum crmd_fsa_cause fsa_cause; long long actions; const char *origin; void *data; enum fsa_data_type data_type; }; extern enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause); /* Global FSA stuff */ extern volatile gboolean do_fsa_stall; extern volatile enum crmd_fsa_state fsa_state; extern volatile long long fsa_input_register; extern volatile long long fsa_actions; extern ll_lrm_t *fsa_lrm_conn; extern cib_t *fsa_cib_conn; extern char *fsa_our_uname; extern char *fsa_our_uuid; extern char *fsa_pe_ref; /* the last invocation of the PE */ extern char *fsa_our_dc; extern char *fsa_our_dc_version; extern GListPtr fsa_message_queue; extern fsa_timer_t *election_trigger; /* */ extern fsa_timer_t *election_timeout; /* */ extern fsa_timer_t *shutdown_escalation_timer; /* */ +extern fsa_timer_t *transition_timer; extern fsa_timer_t *integration_timer; extern fsa_timer_t *finalization_timer; extern fsa_timer_t *wait_timer; extern fsa_timer_t *recheck_timer; extern crm_trigger_t *fsa_source; extern crm_trigger_t *config_read; extern struct crm_subsystem_s *cib_subsystem; extern struct crm_subsystem_s *te_subsystem; extern struct crm_subsystem_s *pe_subsystem; extern GHashTable *welcomed_nodes; extern GHashTable *integrated_nodes; extern GHashTable *finalized_nodes; extern GHashTable *confirmed_nodes; extern GHashTable *crmd_peer_state; /* these two should be moved elsewhere... */ extern void do_update_cib_nodes(gboolean overwrite, const char *caller); extern gboolean do_dc_heartbeat(gpointer data); #define AM_I_DC is_set(fsa_input_register, R_THE_DC) #define AM_I_OPERATIONAL (is_set(fsa_input_register, R_STARTING)==FALSE) extern unsigned long long saved_ccm_membership_id; extern gboolean ever_had_quorum; #include #include #endif diff --git a/crmd/fsa.c b/crmd/fsa.c index 41b543d60c..af813a61c4 100644 --- a/crmd/fsa.c +++ b/crmd/fsa.c @@ -1,706 +1,707 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *fsa_our_dc = NULL; cib_t *fsa_cib_conn = NULL; char *fsa_our_dc_version = NULL; ll_lrm_t *fsa_lrm_conn; char *fsa_our_uuid = NULL; char *fsa_our_uname = NULL; #if SUPPORT_HEARTBEAT ll_cluster_t *fsa_cluster_conn; #endif fsa_timer_t *wait_timer = NULL; fsa_timer_t *recheck_timer = NULL; fsa_timer_t *election_trigger = NULL; fsa_timer_t *election_timeout = NULL; +fsa_timer_t *transition_timer = NULL; fsa_timer_t *integration_timer = NULL; fsa_timer_t *finalization_timer = NULL; fsa_timer_t *shutdown_escalation_timer = NULL; volatile gboolean do_fsa_stall = FALSE; volatile long long fsa_input_register = 0; volatile long long fsa_actions = A_NOTHING; volatile enum crmd_fsa_state fsa_state = S_STARTING; extern uint highest_born_on; extern uint num_join_invites; extern GHashTable *welcomed_nodes; extern GHashTable *finalized_nodes; extern GHashTable *confirmed_nodes; extern GHashTable *integrated_nodes; extern void initialize_join(gboolean before); #define DOT_PREFIX "actions:trace: " #define do_dot_log(fmt, args...) do_crm_log_unlikely(LOG_DEBUG_2, fmt, ##args) long long do_state_transition(long long actions, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, fsa_data_t *msg_data); void dump_rsc_info(void); void dump_rsc_info_callback(const xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data); void ghash_print_node(gpointer key, gpointer value, gpointer user_data); void s_crmd_fsa_actions(fsa_data_t *fsa_data); void log_fsa_input(fsa_data_t *stored_msg); void init_dotfile(void); void init_dotfile(void) { do_dot_log(DOT_PREFIX"digraph \"g\" {"); do_dot_log(DOT_PREFIX" size = \"30,30\""); do_dot_log(DOT_PREFIX" graph ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" bb = \"0,0,398.922306,478.927856\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" node ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" shape = \"ellipse\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" edge ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX"// special nodes"); do_dot_log(DOT_PREFIX" \"S_PENDING\" "); do_dot_log(DOT_PREFIX" ["); do_dot_log(DOT_PREFIX" color = \"blue\""); do_dot_log(DOT_PREFIX" fontcolor = \"blue\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" \"S_TERMINATE\" "); do_dot_log(DOT_PREFIX" ["); do_dot_log(DOT_PREFIX" color = \"red\""); do_dot_log(DOT_PREFIX" fontcolor = \"red\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX"// DC only nodes"); do_dot_log(DOT_PREFIX" \"S_INTEGRATION\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_RELEASE_DC\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_IDLE\" [ fontcolor = \"green\" ]"); } static void do_fsa_action(fsa_data_t *fsa_data, long long an_action, void (*function)(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data)) { int action_log_level = LOG_DEBUG; /* The calls to fsa_action2string() is expensive, * only make it if we will use the result */ if(an_action & A_MSG_ROUTE) { action_log_level = LOG_DEBUG_2; } fsa_actions &= ~an_action; do_crm_log(action_log_level, DOT_PREFIX"\t// %s", fsa_action2string(an_action)); function(an_action, fsa_data->fsa_cause, fsa_state, fsa_data->fsa_input, fsa_data); } static long long startup_actions = A_STARTUP|A_CIB_START|A_LRM_CONNECT|A_CCM_CONNECT|A_HA_CONNECT|A_READCONFIG|A_STARTED|A_CL_JOIN_QUERY; enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause) { fsa_data_t *fsa_data = NULL; long long register_copy = fsa_input_register; long long new_actions = A_NOTHING; enum crmd_fsa_state last_state = fsa_state; crm_debug_2("FSA invoked with Cause: %s\tState: %s", fsa_cause2string(cause), fsa_state2string(fsa_state)); do_fsa_stall = FALSE; if(is_message() == FALSE && fsa_actions != A_NOTHING) { /* fake the first message so we can get into the loop */ crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_NULL; fsa_data->fsa_cause = C_FSA_INTERNAL; fsa_data->origin = __FUNCTION__; fsa_data->data_type = fsa_dt_none; fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); fsa_data = NULL; } while(is_message() && do_fsa_stall == FALSE) { crm_debug_2("Checking messages (%d remaining)", g_list_length(fsa_message_queue)); fsa_data = get_message(); CRM_CHECK(fsa_data != NULL, continue); log_fsa_input(fsa_data); /* add any actions back to the queue */ fsa_actions |= fsa_data->actions; /* get the next batch of actions */ new_actions = crmd_fsa_actions[fsa_data->fsa_input][fsa_state]; fsa_actions |= new_actions; if(fsa_data->fsa_input != I_NULL && fsa_data->fsa_input != I_ROUTER) { crm_debug("Processing %s: [ state=%s cause=%s origin=%s ]", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); } #ifdef FSA_TRACE if(new_actions != A_NOTHING) { crm_debug_2("Adding FSA actions %.16llx for %s/%s", new_actions, fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); fsa_dump_actions(new_actions, "\tFSA scheduled"); } else if(fsa_data->fsa_input != I_NULL && new_actions == A_NOTHING) { crm_debug("No action specified for input,state (%s,%s)", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); } if(fsa_data->actions != A_NOTHING) { crm_debug_2("Adding input actions %.16llx for %s/%s", new_actions, fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); fsa_dump_actions(fsa_data->actions,"\tInput scheduled"); } #endif /* logging : *before* the state is changed */ if(is_set(fsa_actions, A_ERROR)) { do_fsa_action(fsa_data, A_ERROR, do_log); } if(is_set(fsa_actions, A_WARN)) { do_fsa_action(fsa_data, A_WARN, do_log); } if(is_set(fsa_actions, A_LOG)) { do_fsa_action(fsa_data, A_LOG, do_log); } /* update state variables */ last_state = fsa_state; fsa_state = crmd_fsa_state[fsa_data->fsa_input][fsa_state]; /* * Remove certain actions during shutdown */ if(fsa_state == S_STOPPING || ((fsa_input_register & R_SHUTDOWN) == R_SHUTDOWN)) { clear_bit_inplace(fsa_actions, startup_actions); } /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != fsa_state){ fsa_actions = do_state_transition( fsa_actions, last_state, fsa_state, fsa_data); } else { do_dot_log(DOT_PREFIX"\t// FSA input: State=%s \tCause=%s" " \tInput=%s \tOrigin=%s() \tid=%d", fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_input2string(fsa_data->fsa_input), fsa_data->origin, fsa_data->id); } /* start doing things... */ s_crmd_fsa_actions(fsa_data); delete_fsa_input(fsa_data); fsa_data = NULL; } if(g_list_length(fsa_message_queue) > 0 || fsa_actions != A_NOTHING || do_fsa_stall) { crm_debug("Exiting the FSA: queue=%d, fsa_actions=0x%llx, stalled=%s", g_list_length(fsa_message_queue), fsa_actions, do_fsa_stall?"true":"false"); } else { crm_debug_2("Exiting the FSA"); } /* cleanup inputs? */ if(register_copy != fsa_input_register) { long long same = register_copy & fsa_input_register; fsa_dump_inputs(LOG_DEBUG, "Added input:", fsa_input_register ^ same); fsa_dump_inputs(LOG_DEBUG, "Removed input:", register_copy ^ same); } fsa_dump_queue(LOG_DEBUG); return fsa_state; } void s_crmd_fsa_actions(fsa_data_t *fsa_data) { /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. */ CRM_CHECK(fsa_data != NULL, return); while(fsa_actions != A_NOTHING && do_fsa_stall == FALSE) { /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(fsa_actions & A_ERROR) { do_fsa_action(fsa_data, A_ERROR, do_log); } else if(fsa_actions & A_WARN) { do_fsa_action(fsa_data, A_WARN, do_log); } else if(fsa_actions & A_LOG) { do_fsa_action(fsa_data, A_LOG, do_log); /* get out of here NOW! before anything worse happens */ } else if(fsa_actions & A_EXIT_1) { do_fsa_action(fsa_data, A_EXIT_1, do_exit); /* essential start tasks */ } else if(fsa_actions & A_STARTUP) { do_fsa_action(fsa_data, A_STARTUP, do_startup); } else if(fsa_actions & A_CIB_START) { do_fsa_action(fsa_data, A_CIB_START, do_cib_control); } else if(fsa_actions & A_HA_CONNECT) { do_fsa_action(fsa_data, A_HA_CONNECT, do_ha_control); } else if(fsa_actions & A_READCONFIG) { do_fsa_action(fsa_data, A_READCONFIG, do_read_config); /* sub-system start/connect */ } else if(fsa_actions & A_LRM_CONNECT) { do_fsa_action(fsa_data, A_LRM_CONNECT, do_lrm_control); } else if(fsa_actions & A_CCM_CONNECT) { do_fsa_action(fsa_data, A_CCM_CONNECT, do_ccm_control); } else if(fsa_actions & A_TE_START) { do_fsa_action(fsa_data, A_TE_START, do_te_control); } else if(fsa_actions & A_PE_START) { do_fsa_action(fsa_data, A_PE_START, do_pe_control); /* sub-system restart */ } else if((fsa_actions & O_CIB_RESTART) == O_CIB_RESTART) { do_fsa_action(fsa_data, O_CIB_RESTART, do_cib_control); } else if((fsa_actions & O_PE_RESTART) == O_PE_RESTART) { do_fsa_action(fsa_data, O_PE_RESTART, do_pe_control); } else if((fsa_actions & O_TE_RESTART) == O_TE_RESTART) { do_fsa_action(fsa_data, O_TE_RESTART, do_te_control); /* Timers */ /* else if(fsa_actions & O_DC_TIMER_RESTART) { do_fsa_action(fsa_data, O_DC_TIMER_RESTART, do_timer_control) */; } else if(fsa_actions & A_DC_TIMER_STOP) { do_fsa_action(fsa_data, A_DC_TIMER_STOP, do_timer_control); } else if(fsa_actions & A_INTEGRATE_TIMER_STOP) { do_fsa_action(fsa_data, A_INTEGRATE_TIMER_STOP, do_timer_control); } else if(fsa_actions & A_INTEGRATE_TIMER_START) { do_fsa_action(fsa_data, A_INTEGRATE_TIMER_START,do_timer_control); } else if(fsa_actions & A_FINALIZE_TIMER_STOP) { do_fsa_action(fsa_data, A_FINALIZE_TIMER_STOP, do_timer_control); } else if(fsa_actions & A_FINALIZE_TIMER_START) { do_fsa_action(fsa_data, A_FINALIZE_TIMER_START, do_timer_control); /* * Highest priority actions */ } else if(fsa_actions & A_MSG_ROUTE) { do_fsa_action(fsa_data, A_MSG_ROUTE, do_msg_route); } else if(fsa_actions & A_RECOVER) { do_fsa_action(fsa_data, A_RECOVER, do_recover); } else if(fsa_actions & A_CL_JOIN_RESULT) { do_fsa_action(fsa_data, A_CL_JOIN_RESULT, do_cl_join_finalize_respond); } else if(fsa_actions & A_CL_JOIN_REQUEST) { do_fsa_action(fsa_data, A_CL_JOIN_REQUEST, do_cl_join_offer_respond); } else if(fsa_actions & A_SHUTDOWN_REQ) { do_fsa_action(fsa_data, A_SHUTDOWN_REQ, do_shutdown_req); } else if(fsa_actions & A_ELECTION_VOTE) { do_fsa_action(fsa_data, A_ELECTION_VOTE, do_election_vote); } else if(fsa_actions & A_ELECTION_COUNT) { do_fsa_action(fsa_data, A_ELECTION_COUNT, do_election_count_vote); } else if(fsa_actions & A_LRM_EVENT) { do_fsa_action(fsa_data, A_LRM_EVENT, do_lrm_event); /* * High priority actions */ } else if(fsa_actions & A_STARTED) { do_fsa_action(fsa_data, A_STARTED, do_started); } else if(fsa_actions & A_CL_JOIN_QUERY) { do_fsa_action(fsa_data, A_CL_JOIN_QUERY, do_cl_join_query); } else if(fsa_actions & A_DC_TIMER_START) { do_fsa_action(fsa_data, A_DC_TIMER_START, do_timer_control); /* * Medium priority actions */ } else if(fsa_actions & A_DC_TAKEOVER) { do_fsa_action(fsa_data, A_DC_TAKEOVER, do_dc_takeover); } else if(fsa_actions & A_DC_RELEASE) { do_fsa_action(fsa_data, A_DC_RELEASE, do_dc_release); } else if(fsa_actions & A_DC_JOIN_FINAL) { do_fsa_action(fsa_data, A_DC_JOIN_FINAL, do_dc_join_final); } else if(fsa_actions & A_ELECTION_CHECK) { do_fsa_action(fsa_data, A_ELECTION_CHECK, do_election_check); } else if(fsa_actions & A_ELECTION_START) { do_fsa_action(fsa_data, A_ELECTION_START, do_election_vote); } else if(fsa_actions & A_TE_HALT) { do_fsa_action(fsa_data, A_TE_HALT, do_te_invoke); } else if(fsa_actions & A_TE_CANCEL) { do_fsa_action(fsa_data, A_TE_CANCEL, do_te_invoke); } else if(fsa_actions & A_DC_JOIN_OFFER_ALL) { do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ALL, do_dc_join_offer_all); } else if(fsa_actions & A_DC_JOIN_OFFER_ONE) { do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ONE, do_dc_join_offer_all); } else if(fsa_actions & A_DC_JOIN_PROCESS_REQ) { do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_REQ, do_dc_join_filter_offer); } else if(fsa_actions & A_DC_JOIN_PROCESS_ACK) { do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_ACK, do_dc_join_ack); /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ } else if(fsa_actions & A_DC_JOIN_FINALIZE) { do_fsa_action(fsa_data, A_DC_JOIN_FINALIZE, do_dc_join_finalize); } else if(fsa_actions & A_LRM_INVOKE) { do_fsa_action(fsa_data, A_LRM_INVOKE, do_lrm_invoke); } else if(fsa_actions & A_PE_INVOKE) { do_fsa_action(fsa_data, A_PE_INVOKE, do_pe_invoke); } else if(fsa_actions & A_TE_INVOKE) { do_fsa_action(fsa_data, A_TE_INVOKE, do_te_invoke); } else if(fsa_actions & A_CL_JOIN_ANNOUNCE) { do_fsa_action(fsa_data, A_CL_JOIN_ANNOUNCE, do_cl_join_announce); /* sub-system stop */ } else if(fsa_actions & A_DC_RELEASED) { do_fsa_action(fsa_data, A_DC_RELEASED, do_dc_release); } else if(fsa_actions & A_PE_STOP) { do_fsa_action(fsa_data, A_PE_STOP, do_pe_control); } else if(fsa_actions & A_TE_STOP) { do_fsa_action(fsa_data, A_TE_STOP, do_te_control); } else if(fsa_actions & A_SHUTDOWN) { do_fsa_action(fsa_data, A_SHUTDOWN, do_shutdown); } else if(fsa_actions & A_LRM_DISCONNECT) { do_fsa_action(fsa_data, A_LRM_DISCONNECT, do_lrm_control); } else if(fsa_actions & A_CCM_DISCONNECT) { do_fsa_action(fsa_data, A_CCM_DISCONNECT, do_ccm_control); } else if(fsa_actions & A_HA_DISCONNECT) { do_fsa_action(fsa_data, A_HA_DISCONNECT, do_ha_control); } else if(fsa_actions & A_CIB_STOP) { do_fsa_action(fsa_data, A_CIB_STOP, do_cib_control); } else if(fsa_actions & A_STOP) { do_fsa_action(fsa_data, A_STOP, do_stop); /* exit gracefully */ } else if(fsa_actions & A_EXIT_0) { do_fsa_action(fsa_data, A_EXIT_0, do_exit); /* Error checking and reporting */ } else { crm_err("Action %s (0x%llx) not supported ", fsa_action2string(fsa_actions), fsa_actions); register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, fsa_data, NULL, __FUNCTION__); } } } void log_fsa_input(fsa_data_t *stored_msg) { crm_debug_2("Processing queued input %d", stored_msg->id); if(stored_msg->fsa_cause == C_CCM_CALLBACK) { crm_debug_3("FSA processing CCM callback from %s", stored_msg->origin); } else if(stored_msg->fsa_cause == C_LRM_OP_CALLBACK) { crm_debug_3("FSA processing LRM callback from %s", stored_msg->origin); } else if(stored_msg->data == NULL) { crm_debug_3("FSA processing input from %s", stored_msg->origin); } else { ha_msg_input_t *ha_input = fsa_typed_data_adv( stored_msg, fsa_dt_ha_msg, __FUNCTION__); crm_debug_3("FSA processing XML message from %s", stored_msg->origin); crm_log_xml(LOG_MSG, "FSA message data", ha_input->xml); } } long long do_state_transition(long long actions, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, fsa_data_t *msg_data) { long long tmp = actions; gboolean clear_recovery_bit = TRUE; enum crmd_fsa_cause cause = msg_data->fsa_cause; enum crmd_fsa_input current_input = msg_data->fsa_input; const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); CRM_LOG_ASSERT(cur_state != next_state); do_dot_log(DOT_PREFIX"\t%s -> %s [ label=%s cause=%s origin=%s ]", state_from, state_to, input, fsa_cause2string(cause), msg_data->origin); crm_info("State transition %s -> %s [ input=%s cause=%s origin=%s ]", state_from, state_to, input, fsa_cause2string(cause), msg_data->origin); /* the last two clauses might cause trouble later */ if(election_timeout != NULL && next_state != S_ELECTION && cur_state != S_RELEASE_DC) { crm_timer_stop(election_timeout); /* } else { */ /* crm_timer_start(election_timeout); */ } #if 0 if((fsa_input_register & R_SHUTDOWN)){ set_bit_inplace(tmp, A_DC_TIMER_STOP); } #endif if(next_state == S_INTEGRATION) { set_bit_inplace(tmp, A_INTEGRATE_TIMER_START); } else { set_bit_inplace(tmp, A_INTEGRATE_TIMER_STOP); } if(next_state == S_FINALIZE_JOIN) { set_bit_inplace(tmp, A_FINALIZE_TIMER_START); } else { set_bit_inplace(tmp, A_FINALIZE_TIMER_STOP); } if(next_state != S_PENDING) { set_bit_inplace(tmp, A_DC_TIMER_STOP); } if(next_state != S_ELECTION) { highest_born_on = 0; } if(next_state != S_IDLE) { crm_timer_stop(recheck_timer); } if(cur_state == S_FINALIZE_JOIN && next_state == S_POLICY_ENGINE) { populate_cib_nodes(FALSE); do_update_cib_nodes(TRUE, __FUNCTION__); } switch(next_state) { case S_PENDING: fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local); /* fall through */ case S_ELECTION: crm_debug_2("Resetting our DC to NULL on transition to %s", fsa_state2string(next_state)); update_dc(NULL); break; case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we have a new DC"); set_bit_inplace(tmp, A_SHUTDOWN_REQ); } CRM_LOG_ASSERT(fsa_our_dc != NULL); if(fsa_our_dc == NULL) { crm_err("Reached S_NOT_DC without a DC" " being recorded"); } break; case S_RECOVERY: clear_recovery_bit = FALSE; break; case S_FINALIZE_JOIN: CRM_LOG_ASSERT(AM_I_DC); if(cause == C_TIMER_POPPED) { crm_warn("Progressed to state %s after %s", fsa_state2string(next_state), fsa_cause2string(cause)); } if(g_hash_table_size(welcomed_nodes) > 0) { char *msg = crm_strdup( " Welcome reply not received from"); crm_warn("%u cluster nodes failed to respond" " to the join offer.", g_hash_table_size(welcomed_nodes)); g_hash_table_foreach( welcomed_nodes, ghash_print_node, msg); crm_free(msg); } else { crm_info("All %d cluster nodes " "responded to the join offer.", g_hash_table_size(integrated_nodes)); } break; case S_POLICY_ENGINE: CRM_LOG_ASSERT(AM_I_DC); if(cause == C_TIMER_POPPED) { crm_info("Progressed to state %s after %s", fsa_state2string(next_state), fsa_cause2string(cause)); } if(g_hash_table_size(finalized_nodes) > 0) { char *msg = crm_strdup(" Confirm not received from"); crm_err("%u cluster nodes failed to confirm" " their join.", g_hash_table_size(finalized_nodes)); g_hash_table_foreach( finalized_nodes, ghash_print_node, msg); crm_free(msg); } else if(g_hash_table_size(confirmed_nodes) == crm_active_members()) { crm_info("All %u cluster nodes are" " eligible to run resources.", crm_active_members()); } else if(g_hash_table_size(confirmed_nodes) > crm_active_members()) { crm_err("We have more confirmed nodes than our membership does: %d vs. %d", g_hash_table_size(confirmed_nodes), crm_active_members()); register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); } else if(saved_ccm_membership_id != crm_peer_seq) { crm_info("Membership changed: %llu -> %llu - join restart", saved_ccm_membership_id, crm_peer_seq); register_fsa_input_before(C_FSA_INTERNAL, I_NODE_JOIN, NULL); } else { crm_warn("Only %u of %u cluster " "nodes are eligible to run resources - continue %d", g_hash_table_size(confirmed_nodes), crm_active_members(), g_hash_table_size(welcomed_nodes)); } /* initialize_join(FALSE); */ break; case S_STOPPING: case S_TERMINATE: /* possibly redundant */ set_bit_inplace(fsa_input_register, R_SHUTDOWN); break; case S_IDLE: CRM_LOG_ASSERT(AM_I_DC); dump_rsc_info(); if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we are the DC"); set_bit_inplace(tmp, A_SHUTDOWN_REQ); } if(recheck_timer->period_ms > 0) { crm_info("Starting %s", get_timer_desc(recheck_timer)); crm_timer_start(recheck_timer); } break; default: break; } if(clear_recovery_bit && next_state != S_PENDING) { tmp &= ~A_RECOVER; } else if(clear_recovery_bit == FALSE) { tmp |= A_RECOVER; } if(tmp != actions) { /* fsa_dump_actions(actions ^ tmp, "New actions"); */ actions = tmp; } return actions; } void dump_rsc_info(void) { } void ghash_print_node(gpointer key, gpointer value, gpointer user_data) { const char *text = user_data; const char *uname = key; const char *value_s = value; crm_info("%s: %s %s", text, uname, value_s); } diff --git a/crmd/fsa_matrix.h b/crmd/fsa_matrix.h index 5cd19ecb25..1dd87a0878 100644 --- a/crmd/fsa_matrix.h +++ b/crmd/fsa_matrix.h @@ -1,1230 +1,1230 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef XML_FSA_MATRIX__H #define XML_FSA_MATRIX__H /* * The state transition table. The rows are inputs, and * the columns are states. */ const enum crmd_fsa_state crmd_fsa_state [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_CIB_UPDATE */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_FINALIZE_JOIN ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RECOVERY, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, /* S_HALT ==> */ S_ELECTION, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ S_ELECTION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_ELECTION, /* S_FINALIZE_JOIN ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, /* S_HALT ==> */ S_HALT, }, /* Got an I_PE_CALC */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, - /* S_NOT_DC ==> */ S_RECOVERY, + /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, - /* S_PENDING ==> */ S_RECOVERY, + /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_FINALIZE_JOIN ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, /* S_HALT ==> */ S_HALT, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_INTEGRATION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_INTEGRATION, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, /* S_HALT ==> */ S_HALT, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RECOVERY, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_FINALIZE_JOIN ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RECOVERY, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, /* S_HALT ==> */ S_RECOVERY, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STOPPING, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, /* S_HALT ==> */ S_RELEASE_DC, }, /* Got an I_INTEGRATED */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_FINALIZE_JOIN, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_FINALIZED */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_POLICY_ENGINE, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_NODE_JOIN */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, /* S_HALT ==> */ S_HALT, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_FINALIZE_JOIN ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_NOT_DC, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, /* S_HALT ==> */ S_HALT, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_PENDING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ S_STOPPING, /* S_ELECTION ==> */ S_STOPPING, /* S_INTEGRATION ==> */ S_STOPPING, /* S_FINALIZE_JOIN ==> */ S_STOPPING, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_STOPPING, /* S_RECOVERY ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_STOPPING, /* S_HALT ==> */ S_HALT, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_FINALIZE_JOIN ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_PENDING, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, /* S_HALT ==> */ S_HALT, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_TE_SUCCESS */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_IDLE, /* S_HALT ==> */ S_HALT, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STOPPING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, /* S_HALT ==> */ S_ELECTION, }, /* Got an I_STOP */ { /* S_IDLE ==> */ S_STOPPING, /* S_ELECTION ==> */ S_STOPPING, /* S_INTEGRATION ==> */ S_STOPPING, /* S_FINALIZE_JOIN ==> */ S_STOPPING, /* S_NOT_DC ==> */ S_STOPPING, /* S_POLICY_ENGINE ==> */ S_STOPPING, /* S_RECOVERY ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_STARTING ==> */ S_STOPPING, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_STOPPING, /* S_HALT ==> */ S_STOPPING, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ S_TERMINATE, /* S_ELECTION ==> */ S_TERMINATE, /* S_INTEGRATION ==> */ S_TERMINATE, /* S_FINALIZE_JOIN ==> */ S_TERMINATE, /* S_NOT_DC ==> */ S_TERMINATE, /* S_POLICY_ENGINE ==> */ S_TERMINATE, /* S_RECOVERY ==> */ S_TERMINATE, /* S_RELEASE_DC ==> */ S_TERMINATE, /* S_STARTING ==> */ S_TERMINATE, /* S_PENDING ==> */ S_TERMINATE, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TERMINATE, /* S_HALT ==> */ S_TERMINATE, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RECOVERY, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_FINALIZE_JOIN ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, /* S_HALT ==> */ S_HALT, }, /* Got an I_PE_SUCCESS */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_JOIN_OFFER */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_PENDING, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_JOIN_REQUEST */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, /* S_HALT ==> */ S_HALT, }, /* Got an I_JOIN_RESULT */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_PENDING, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_RECOVERY, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, /* S_HALT ==> */ S_HALT, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_HALT ==> */ S_HALT, }, /* Got an I_PENDING */ { /* S_IDLE ==> */ S_PENDING, /* S_ELECTION ==> */ S_PENDING, /* S_INTEGRATION ==> */ S_PENDING, /* S_FINALIZE_JOIN ==> */ S_PENDING, /* S_NOT_DC ==> */ S_PENDING, /* S_POLICY_ENGINE ==> */ S_PENDING, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_PENDING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_PENDING, /* S_HALT ==> */ S_HALT, }, /* Got an I_HALT */ { /* S_IDLE ==> */ S_HALT, /* S_ELECTION ==> */ S_HALT, /* S_INTEGRATION ==> */ S_HALT, /* S_FINALIZE_JOIN ==> */ S_HALT, /* S_NOT_DC ==> */ S_HALT, /* S_POLICY_ENGINE ==> */ S_HALT, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_STARTING ==> */ S_STARTING, /* S_PENDING ==> */ S_HALT, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_HALT, /* S_HALT ==> */ S_HALT, }, }; /* * The action table. Each entry is a set of actions to take or-ed * together. Like the state table, the rows are inputs, and * the columns are states. */ /* NOTE: In the fsa, the actions are extracted then state is updated. */ const long long crmd_fsa_actions [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_NOTHING, /* S_INTEGRATION ==> */ A_NOTHING, /* S_FINALIZE_JOIN ==> */ A_NOTHING, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_NOTHING, /* S_STARTING ==> */ A_NOTHING, /* S_PENDING ==> */ A_NOTHING, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, /* S_HALT ==> */ A_NOTHING, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ A_ERROR, /* S_ELECTION ==> */ A_ERROR, /* S_INTEGRATION ==> */ A_ERROR, /* S_FINALIZE_JOIN ==> */ A_ERROR, /* S_NOT_DC ==> */ A_ERROR, /* S_POLICY_ENGINE ==> */ A_ERROR, /* S_RECOVERY ==> */ A_ERROR, /* S_RELEASE_DC ==> */ A_ERROR, /* S_STARTING ==> */ A_ERROR, /* S_PENDING ==> */ A_ERROR, /* S_STOPPING ==> */ A_ERROR, /* S_TERMINATE ==> */ A_ERROR, /* S_TRANSITION_ENGINE ==> */ A_ERROR, /* S_HALT ==> */ A_ERROR, }, /* Got an I_CIB_UPDATE */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_LOG, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_LOG, /* S_HALT ==> */ A_WARN, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_ELECTION_VOTE|A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_ELECTION_VOTE|A_WARN, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_TE_CANCEL|A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ A_ELECTION_VOTE, /* S_ELECTION ==> */ A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_ELECTION_VOTE, /* S_FINALIZE_JOIN ==> */ A_ELECTION_VOTE, /* S_NOT_DC ==> */ A_ELECTION_VOTE, /* S_POLICY_ENGINE ==> */ A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_ELECTION_VOTE, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_VOTE, /* S_HALT ==> */ A_ELECTION_VOTE, }, /* Got an I_PE_CALC */ { /* S_IDLE ==> */ A_PE_INVOKE, /* S_ELECTION ==> */ A_NOTHING, /* S_INTEGRATION ==> */ A_NOTHING, /* S_FINALIZE_JOIN ==> */ A_NOTHING, - /* S_NOT_DC ==> */ A_ERROR, + /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_PE_INVOKE, /* S_RECOVERY ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_NOTHING, /* S_STARTING ==> */ A_ERROR, - /* S_PENDING ==> */ A_ERROR, + /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_ERROR, /* S_TRANSITION_ENGINE ==> */ A_PE_INVOKE, /* S_HALT ==> */ A_ERROR, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ O_RELEASE, /* S_ELECTION ==> */ O_RELEASE, /* S_INTEGRATION ==> */ O_RELEASE|A_WARN, /* S_FINALIZE_JOIN ==> */ O_RELEASE|A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_WARN, /* S_RECOVERY ==> */ O_RELEASE, /* S_RELEASE_DC ==> */ O_RELEASE|A_WARN, /* S_STARTING ==> */ A_ERROR, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ A_WARN|A_ELECTION_VOTE, /* S_ELECTION ==> */ A_LOG|A_DC_TAKEOVER|A_PE_START|A_TE_START|A_DC_JOIN_OFFER_ALL|A_DC_TIMER_STOP, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE|A_DC_JOIN_OFFER_ALL, /* S_FINALIZE_JOIN ==> */ A_WARN|A_ELECTION_VOTE|A_DC_JOIN_OFFER_ALL, /* S_NOT_DC ==> */ A_LOG|A_ELECTION_VOTE, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN|A_ELECTION_VOTE, /* S_STARTING ==> */ A_LOG|A_WARN, /* S_PENDING ==> */ A_LOG|A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_HALT ==> */ A_WARN, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, /* S_ELECTION ==> */ A_ERROR|A_RECOVER|O_RELEASE, /* S_INTEGRATION ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, /* S_FINALIZE_JOIN ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, /* S_NOT_DC ==> */ A_ERROR|A_RECOVER, /* S_POLICY_ENGINE ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, /* S_RECOVERY ==> */ A_ERROR|O_RELEASE, /* S_RELEASE_DC ==> */ A_ERROR|A_RECOVER, /* S_STARTING ==> */ A_ERROR|A_RECOVER, /* S_PENDING ==> */ A_ERROR|A_RECOVER, /* S_STOPPING ==> */ A_ERROR|A_EXIT_1, /* S_TERMINATE ==> */ A_ERROR|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, /* S_HALT ==> */ A_ERROR|A_RECOVER|O_RELEASE|A_ELECTION_START, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN|A_DC_JOIN_OFFER_ALL, /* S_FINALIZE_JOIN ==> */ A_WARN|A_DC_JOIN_OFFER_ALL, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN|A_DC_JOIN_OFFER_ALL|A_TE_CANCEL, /* S_RECOVERY ==> */ A_WARN|O_RELEASE, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_WARN|O_TE_RESTART|A_RECOVER, /* S_HALT ==> */ A_WARN, }, /* Got an I_INTEGRATED */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_DC_JOIN_FINALIZE, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, /* S_HALT ==> */ A_WARN, }, /* Got an I_FINALIZED */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_DC_JOIN_FINAL|A_TE_CANCEL, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, /* S_HALT ==> */ A_WARN, }, /* Got an I_NODE_JOIN */ { /* S_IDLE ==> */ A_TE_HALT|A_DC_JOIN_OFFER_ONE, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_DC_JOIN_OFFER_ONE, /* S_FINALIZE_JOIN ==> */ A_DC_JOIN_OFFER_ONE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_DC_JOIN_OFFER_ONE, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_TE_HALT|A_DC_JOIN_OFFER_ONE, /* S_HALT ==> */ A_WARN, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ A_WARN|O_RELEASE, /* S_ELECTION ==> */ A_ERROR|A_ELECTION_START|A_DC_TIMER_STOP, /* S_INTEGRATION ==> */ A_ERROR|O_RELEASE, /* S_FINALIZE_JOIN ==> */ A_ERROR|O_RELEASE, /* S_NOT_DC ==> */ A_LOG, /* S_POLICY_ENGINE ==> */ A_ERROR|O_RELEASE, /* S_RECOVERY ==> */ A_ERROR|O_RELEASE, /* S_RELEASE_DC ==> */ A_ERROR|O_RELEASE, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_LOG|A_DC_TIMER_STOP, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_ERROR|O_RELEASE, /* S_HALT ==> */ A_WARN, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_WARN|A_SHUTDOWN_REQ, /* S_RELEASE_DC ==> */ A_NOTHING, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_LOG|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_LOG|A_DC_JOIN_OFFER_ALL, /* S_FINALIZE_JOIN ==> */ A_LOG|A_DC_JOIN_FINALIZE, /* S_NOT_DC ==> */ A_LOG|A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_PE_INVOKE, /* S_RECOVERY ==> */ A_LOG|A_RECOVER|O_RELEASE, /* S_RELEASE_DC ==> */ A_LOG|O_RELEASE, /* S_STARTING ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG|A_TE_INVOKE, /* S_HALT ==> */ A_WARN, }, /* Got an I_TE_SUCCESS */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_ERROR, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_RECOVER|A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_ERROR, /* S_PENDING ==> */ A_ERROR, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_LOG, /* S_HALT ==> */ A_WARN, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ A_MSG_ROUTE, /* S_ELECTION ==> */ A_MSG_ROUTE, /* S_INTEGRATION ==> */ A_MSG_ROUTE, /* S_FINALIZE_JOIN ==> */ A_MSG_ROUTE, /* S_NOT_DC ==> */ A_MSG_ROUTE, /* S_POLICY_ENGINE ==> */ A_MSG_ROUTE, /* S_RECOVERY ==> */ A_MSG_ROUTE, /* S_RELEASE_DC ==> */ A_MSG_ROUTE, /* S_STARTING ==> */ A_MSG_ROUTE, /* S_PENDING ==> */ A_MSG_ROUTE, /* S_STOPPING ==> */ A_MSG_ROUTE, /* S_TERMINATE ==> */ A_MSG_ROUTE, /* S_TRANSITION_ENGINE ==> */ A_MSG_ROUTE, /* S_HALT ==> */ A_WARN|A_MSG_ROUTE, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ A_LOG|A_SHUTDOWN_REQ, /* S_ELECTION ==> */ A_LOG|A_SHUTDOWN_REQ|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_LOG|A_SHUTDOWN_REQ, /* S_FINALIZE_JOIN ==> */ A_LOG|A_SHUTDOWN_REQ, /* S_NOT_DC ==> */ A_SHUTDOWN_REQ, /* S_POLICY_ENGINE ==> */ A_LOG|A_SHUTDOWN_REQ, /* S_RECOVERY ==> */ A_WARN|O_EXIT|O_RELEASE, /* S_RELEASE_DC ==> */ A_WARN|A_SHUTDOWN_REQ, /* S_STARTING ==> */ A_WARN|O_EXIT, /* S_PENDING ==> */ A_SHUTDOWN_REQ, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_SHUTDOWN_REQ, /* S_HALT ==> */ A_WARN|A_ELECTION_START|A_SHUTDOWN_REQ, }, /* Got an I_STOP */ { /* S_IDLE ==> */ A_ERROR|O_RELEASE|O_EXIT, /* S_ELECTION ==> */ O_RELEASE|O_EXIT, /* S_INTEGRATION ==> */ A_WARN|O_RELEASE|O_EXIT, /* S_FINALIZE_JOIN ==> */ A_ERROR|O_RELEASE|O_EXIT, /* S_NOT_DC ==> */ O_EXIT, /* S_POLICY_ENGINE ==> */ A_WARN|O_RELEASE|O_EXIT, /* S_RECOVERY ==> */ A_ERROR|O_RELEASE|O_EXIT, /* S_RELEASE_DC ==> */ A_ERROR|O_RELEASE|O_EXIT, /* S_STARTING ==> */ O_EXIT, /* S_PENDING ==> */ O_EXIT, /* S_STOPPING ==> */ O_EXIT, /* S_TERMINATE ==> */ A_ERROR|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_LOG|O_RELEASE|O_EXIT, /* S_HALT ==> */ O_RELEASE|O_EXIT|A_WARN, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ A_ERROR|O_EXIT, /* S_ELECTION ==> */ A_ERROR|O_EXIT, /* S_INTEGRATION ==> */ A_ERROR|O_EXIT, /* S_FINALIZE_JOIN ==> */ A_ERROR|O_EXIT, /* S_NOT_DC ==> */ A_ERROR|O_EXIT, /* S_POLICY_ENGINE ==> */ A_ERROR|O_EXIT, /* S_RECOVERY ==> */ A_ERROR|O_EXIT, /* S_RELEASE_DC ==> */ A_ERROR|O_EXIT, /* S_STARTING ==> */ O_EXIT, /* S_PENDING ==> */ A_ERROR|O_EXIT, /* S_STOPPING ==> */ O_EXIT, /* S_TERMINATE ==> */ O_EXIT, /* S_TRANSITION_ENGINE ==> */ A_ERROR|O_EXIT, /* S_HALT ==> */ A_ERROR|O_EXIT, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_LOG|A_STARTUP|A_CIB_START|A_LRM_CONNECT|A_CCM_CONNECT|A_HA_CONNECT|A_READCONFIG|A_STARTED, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, /* S_HALT ==> */ A_WARN, }, /* Got an I_PE_SUCCESS */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_TE_INVOKE, /* S_RECOVERY ==> */ A_RECOVER|A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_ERROR, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_ERROR, /* S_TERMINATE ==> */ A_ERROR, /* S_TRANSITION_ENGINE ==> */ A_LOG, /* S_HALT ==> */ A_WARN, }, /* Got an I_JOIN_OFFER */ { /* S_IDLE ==> */ A_WARN|A_CL_JOIN_REQUEST, /* S_ELECTION ==> */ A_WARN|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_CL_JOIN_REQUEST, /* S_FINALIZE_JOIN ==> */ A_CL_JOIN_REQUEST, /* S_NOT_DC ==> */ A_CL_JOIN_REQUEST|A_DC_TIMER_STOP, /* S_POLICY_ENGINE ==> */ A_WARN|A_CL_JOIN_REQUEST, /* S_RECOVERY ==> */ A_WARN|A_CL_JOIN_REQUEST|A_DC_TIMER_STOP, /* S_RELEASE_DC ==> */ A_WARN|A_CL_JOIN_REQUEST|A_DC_TIMER_STOP, /* S_STARTING ==> */ A_LOG, /* S_PENDING ==> */ A_CL_JOIN_REQUEST|A_DC_TIMER_STOP, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_CL_JOIN_REQUEST, /* S_HALT ==> */ A_WARN, }, /* Got an I_JOIN_REQUEST */ { /* S_IDLE ==> */ A_DC_JOIN_OFFER_ONE, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_DC_JOIN_PROCESS_REQ, /* S_FINALIZE_JOIN ==> */ A_DC_JOIN_OFFER_ONE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_DC_JOIN_OFFER_ONE, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_DC_JOIN_OFFER_ONE, /* S_HALT ==> */ A_WARN, }, /* Got an I_JOIN_RESULT */ { /* S_IDLE ==> */ A_ERROR|A_TE_HALT|A_DC_JOIN_OFFER_ALL, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_LOG, /* S_FINALIZE_JOIN ==> */ A_CL_JOIN_RESULT|A_DC_JOIN_PROCESS_ACK, /* S_NOT_DC ==> */ A_ERROR|A_CL_JOIN_ANNOUNCE, /* S_POLICY_ENGINE ==> */ A_ERROR|A_TE_HALT|A_DC_JOIN_OFFER_ALL, /* S_RECOVERY ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_ERROR, /* S_PENDING ==> */ A_CL_JOIN_RESULT, /* S_STOPPING ==> */ A_ERROR, /* S_TERMINATE ==> */ A_ERROR, /* S_TRANSITION_ENGINE ==> */ A_ERROR|A_TE_HALT|A_DC_JOIN_OFFER_ALL, /* S_HALT ==> */ A_WARN, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_LOG, /* S_FINALIZE_JOIN ==> */ A_LOG, /* S_NOT_DC ==> */ A_LOG, /* S_POLICY_ENGINE ==> */ A_LOG, /* S_RECOVERY ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG, /* S_HALT ==> */ A_WARN, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ A_ERROR, /* S_ELECTION ==> */ A_WARN|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_ERROR, /* S_FINALIZE_JOIN ==> */ A_ERROR, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_ERROR, /* S_RECOVERY ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_LOG, /* S_STARTING ==> */ A_LOG, /* S_PENDING ==> */ A_LOG|A_CL_JOIN_ANNOUNCE, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_ERROR, /* S_HALT ==> */ A_WARN, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ A_LRM_EVENT, /* S_ELECTION ==> */ A_LRM_EVENT, /* S_INTEGRATION ==> */ A_LRM_EVENT, /* S_FINALIZE_JOIN ==> */ A_LRM_EVENT, /* S_NOT_DC ==> */ A_LRM_EVENT, /* S_POLICY_ENGINE ==> */ A_LRM_EVENT, /* S_RECOVERY ==> */ A_LRM_EVENT, /* S_RELEASE_DC ==> */ A_LRM_EVENT, /* S_STARTING ==> */ A_LRM_EVENT, /* S_PENDING ==> */ A_LRM_EVENT, /* S_STOPPING ==> */ A_LRM_EVENT, /* S_TERMINATE ==> */ A_LRM_EVENT, /* S_TRANSITION_ENGINE ==> */ A_LRM_EVENT, /* S_HALT ==> */ A_WARN, }, /* For everyone ending up in S_PENDING, (re)start the DC timer and wait for I_JOIN_OFFER or I_NOT_DC */ /* Got an I_PENDING */ { /* S_IDLE ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_ELECTION ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_INTEGRATION ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_FINALIZE_JOIN ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_NOT_DC ==> */ A_LOG|O_DC_TIMER_RESTART, /* S_POLICY_ENGINE ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN|O_DC_TIMER_RESTART, /* S_STARTING ==> */ A_LOG|A_DC_TIMER_START|A_CL_JOIN_QUERY, /* S_PENDING ==> */ A_LOG|O_DC_TIMER_RESTART, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|O_DC_TIMER_RESTART, /* S_HALT ==> */ A_WARN, }, /* Got an I_HALT */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_STARTING ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, /* S_HALT ==> */ A_WARN, }, }; #endif diff --git a/crmd/te_actions.c b/crmd/te_actions.c index f728b740cc..840a1ffa52 100644 --- a/crmd/te_actions.c +++ b/crmd/te_actions.c @@ -1,517 +1,521 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include char *te_uuid = NULL; void send_rsc_command(crm_action_t *action); static void te_start_action_timer(crm_graph_t *graph, crm_action_t *action) { crm_malloc0(action->timer, sizeof(crm_action_timer_t)); action->timer->timeout = action->timeout; action->timer->reason = timeout_action; action->timer->action = action; action->timer->source_id = g_timeout_add( action->timer->timeout + graph->network_delay, action_timer_callback, (void*)action->timer); CRM_ASSERT(action->timer->source_id != 0); } static gboolean te_pseudo_action(crm_graph_t *graph, crm_action_t *pseudo) { crm_info("Pseudo action %d fired and confirmed", pseudo->id); pseudo->confirmed = TRUE; update_graph(graph, pseudo); trigger_graph(); return TRUE; } void send_stonith_update(crm_action_t *action, const char *target, const char *uuid) { enum cib_errors rc = cib_ok; /* zero out the node-status & remove all LRM status info */ xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); CRM_CHECK(target != NULL, return); CRM_CHECK(uuid != NULL, return); crm_xml_add(node_state, XML_ATTR_UUID, uuid); crm_xml_add(node_state, XML_ATTR_UNAME, target); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_ATTR_ORIGIN, __FUNCTION__); rc = fsa_cib_conn->cmds->update( fsa_cib_conn, XML_CIB_TAG_STATUS, node_state, cib_quorum_override|cib_scope_local|cib_can_create); /* Delay processing the trigger until the update completes */ crm_info("Sending fencing update %d for %s", rc, target); add_cib_op_callback(fsa_cib_conn, rc, FALSE, crm_strdup(target), cib_fencing_updated); /* Make sure it sticks */ /* fsa_cib_conn->cmds->bump_epoch(fsa_cib_conn, cib_quorum_override|cib_scope_local); */ erase_status_tag(target, XML_CIB_TAG_LRM, cib_scope_local); erase_status_tag(target, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local); free_xml(node_state); /* Make sure the membership cache is accurate */ crm_update_peer(0, 0, 0, -1, crm_proc_none, uuid, target, NULL, CRM_NODE_LOST); return; } static gboolean te_fence_node(crm_graph_t *graph, crm_action_t *action) { int rc = 0; const char *id = NULL; const char *uuid = NULL; const char *target = NULL; const char *type = NULL; gboolean invalid_action = FALSE; id = ID(action->xml); target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); type = crm_meta_value(action->params, "stonith_action"); CRM_CHECK(id != NULL, invalid_action = TRUE); CRM_CHECK(uuid != NULL, invalid_action = TRUE); CRM_CHECK(type != NULL, invalid_action = TRUE); CRM_CHECK(target != NULL, invalid_action = TRUE); if(invalid_action) { crm_log_xml_warn(action->xml, "BadAction"); return FALSE; } te_log_action(LOG_INFO, "Executing %s fencing operation (%s) on %s (timeout=%d)", type, id, target, transition_graph->stonith_timeout); /* Passing NULL means block until we can connect... */ te_connect_stonith(NULL); rc = stonith_api->cmds->fence( stonith_api, 0, target, type, transition_graph->stonith_timeout/1000); stonith_api->cmds->register_callback( stonith_api, rc, transition_graph->stonith_timeout/1000, FALSE, generate_transition_key(transition_graph->id, action->id, 0, te_uuid), "tengine_stonith_callback", tengine_stonith_callback); return TRUE; } static int get_target_rc(crm_action_t *action) { const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC); if(target_rc_s != NULL) { return crm_parse_int(target_rc_s, "0"); } return 0; } static gboolean te_crm_command(crm_graph_t *graph, crm_action_t *action) { char *counter = NULL; xmlNode *cmd = NULL; gboolean is_local = FALSE; const char *id = NULL; const char *task = NULL; const char *value = NULL; const char *on_node = NULL; gboolean rc = TRUE; gboolean no_wait = FALSE; id = ID(action->xml); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", crm_str(id), crm_str(task)); return FALSE); te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s%s%s", crm_str(id), crm_str(task), on_node, is_local?" (local)":"", no_wait?" - no waiting":""); if(safe_str_eq(on_node, fsa_our_uname)) { is_local = TRUE; } value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT); if(crm_is_true(value)) { no_wait = TRUE; } if(is_local && safe_str_eq(task, CRM_OP_SHUTDOWN)) { /* defer until everything else completes */ te_log_action(LOG_INFO, "crm-event (%s) is a local shutdown", crm_str(id)); graph->completion_action = tg_shutdown; graph->abort_reason = "local shutdown"; action->confirmed = TRUE; update_graph(graph, action); trigger_graph(); return TRUE; } cmd = create_request(task, action->xml, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key( transition_graph->id, action->id, get_target_rc(action), te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); rc = send_cluster_message(on_node, crm_msg_crmd, cmd, TRUE); crm_free(counter); free_xml(cmd); if(rc == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(no_wait) { action->confirmed = TRUE; update_graph(graph, action); trigger_graph(); } else { if(action->timeout <= 0) { crm_err("Action %d: %s on %s had an invalid timeout (%dms). Using %dms instead", action->id, task, on_node, action->timeout, graph->network_delay); action->timeout = graph->network_delay; } te_start_action_timer(graph, action); } return TRUE; } gboolean cib_action_update(crm_action_t *action, int status, int op_rc) { lrm_op_t *op = NULL; xmlNode *state = NULL; xmlNode *rsc = NULL; xmlNode *xml_op = NULL; xmlNode *action_rsc = NULL; enum cib_errors rc = cib_ok; const char *name = NULL; const char *value = NULL; const char *rsc_id = NULL; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override|cib_scope_local; int target_rc = get_target_rc(action); if(status == LRM_OP_PENDING) { crm_debug("%s %d: Recording pending operation %s on %s", crm_element_name(action->xml), action->id, task_uuid, target); } else { crm_warn("%s %d: %s on %s timed out", crm_element_name(action->xml), action->id, task_uuid, target); } action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE); if(action_rsc == NULL) { return FALSE; } rsc_id = ID(action_rsc); CRM_CHECK(rsc_id != NULL, crm_log_xml_err(action->xml, "Bad:action"); return FALSE); /* update the CIB */ 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); crm_xml_add(rsc, XML_ATTR_ID, target_uuid); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); name = XML_ATTR_TYPE; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_CLASS; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_PROVIDER; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); op = convert_graph_action(NULL, action, status, op_rc); op->call_id = -1; op->user_data = generate_transition_key( transition_graph->id, action->id, target_rc, te_uuid); xml_op = create_operation_update( rsc, op, CRM_FEATURE_SET, target_rc, __FUNCTION__, LOG_INFO); free_lrm_op(op); 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); rc = fsa_cib_conn->cmds->update( fsa_cib_conn, XML_CIB_TAG_STATUS, state, call_options); crm_debug_2("Updating CIB with %s action %d: %s on %s (call_id=%d)", op_status2text(status), action->id, task_uuid, target, rc); add_cib_op_callback(fsa_cib_conn, rc, FALSE, NULL, cib_action_updated); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } static gboolean te_rsc_command(crm_graph_t *graph, crm_action_t *action) { /* 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 */ xmlNode *cmd = NULL; xmlNode *rsc_op = NULL; gboolean rc = TRUE; gboolean no_wait = FALSE; gboolean is_local = FALSE; char *counter = NULL; const char *task = NULL; const char *value = NULL; const char *on_node = NULL; const char *task_uuid = NULL; CRM_ASSERT(action != NULL); CRM_ASSERT(action->xml != NULL); action->executed = FALSE; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", ID(action->xml), crm_str(task)); return FALSE); rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key( transition_graph->id, action->id, get_target_rc(action), te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); if(safe_str_eq(on_node, fsa_our_uname)) { is_local = TRUE; } value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT); if(crm_is_true(value)) { no_wait = TRUE; } crm_info("Initiating action %d: %s %s on %s%s%s", action->id, task, task_uuid, on_node, is_local?" (local)":"", no_wait?" - no waiting":""); cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); if(is_local) { /* shortcut local resource commands */ ha_msg_input_t data = { .msg = cmd, .xml = rsc_op, }; fsa_data_t msg = { .id = 0, .data = &data, .data_type = fsa_dt_ha_msg, .fsa_input = I_NULL, .fsa_cause = C_FSA_INTERNAL, .actions = A_LRM_INVOKE, .origin = __FUNCTION__, }; do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, fsa_state, I_NULL, &msg); } else { rc = send_cluster_message(on_node, crm_msg_lrmd, cmd, TRUE); } crm_free(counter); free_xml(cmd); action->executed = TRUE; if(rc == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(no_wait) { action->confirmed = TRUE; update_graph(transition_graph, action); trigger_graph(); } else { if(action->timeout <= 0) { crm_err("Action %d: %s %s on %s had an invalid timeout (%dms). Using %dms instead", action->id, task, task_uuid, on_node, action->timeout, graph->network_delay); action->timeout = graph->network_delay; } te_start_action_timer(graph, action); } value = crm_meta_value(action->params, XML_OP_ATTR_PENDING); if(crm_is_true(value)) { /* write a "pending" entry to the CIB, inhibit notification */ crm_info("Recording pending op %s in the CIB", task_uuid); cib_action_update(action, LRM_OP_PENDING, EXECRA_STATUS_UNKNOWN); } return TRUE; } crm_graph_functions_t te_graph_fns = { te_pseudo_action, te_rsc_command, te_crm_command, te_fence_node }; void notify_crmd(crm_graph_t *graph) { int log_level = LOG_DEBUG; const char *type = "unknown"; enum crmd_fsa_input event = I_NULL; crm_debug("Processing transition completion in state %s", fsa_state2string(fsa_state)); CRM_CHECK(graph->complete, graph->complete = TRUE); switch(graph->completion_action) { case tg_stop: type = "stop"; /* fall through */ case tg_done: type = "done"; log_level = LOG_INFO; if(fsa_state == S_TRANSITION_ENGINE) { event = I_TE_SUCCESS; } break; case tg_restart: type = "restart"; if(fsa_state == S_TRANSITION_ENGINE) { - event = I_PE_CALC; + if(transition_timer->period_ms > 0) { + crm_timer_start(transition_timer); + } else { + event = I_PE_CALC; + } } else if(fsa_state == S_POLICY_ENGINE) { register_fsa_action(A_PE_INVOKE); } break; case tg_shutdown: type = "shutdown"; if(is_set(fsa_input_register, R_SHUTDOWN)) { event = I_STOP; } else { crm_err("We didn't ask to be shut down, yet our" " PE is telling us too."); event = I_TERMINATE; } } te_log_action(log_level, "Transition %d status: %s - %s", graph->id, type, crm_str(graph->abort_reason)); graph->abort_reason = NULL; graph->completion_action = tg_done; clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(event != I_NULL) { register_fsa_input(C_FSA_INTERNAL, event, NULL); } else if(fsa_source) { mainloop_set_trigger(fsa_source); } } diff --git a/crmd/te_utils.c b/crmd/te_utils.c index c9d9de7704..dd9ea8136e 100644 --- a/crmd/te_utils.c +++ b/crmd/te_utils.c @@ -1,405 +1,409 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include GCHSource *stonith_src = NULL; crm_trigger_t *stonith_reconnect = NULL; static gboolean fail_incompletable_stonith(crm_graph_t *graph) { GListPtr lpc = NULL; const char *task = NULL; xmlNode *last_action = NULL; if(graph == NULL) { return FALSE; } for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { GListPtr lpc2 = NULL; synapse_t *synapse = (synapse_t*)lpc->data; if (synapse->confirmed) { continue; } for(lpc2 = synapse->actions; lpc2 != NULL; lpc2 = lpc2->next) { crm_action_t *action = (crm_action_t*)lpc2->data; if(action->type != action_type_crm || action->confirmed) { continue; } task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); if(task && safe_str_eq(task, CRM_OP_FENCE)) { action->failed = TRUE; last_action = action->xml; update_graph(graph, action); crm_notice("Failing action %d (%s): STONITHd terminated", action->id, ID(action->xml)); } } } if(last_action != NULL) { crm_warn("STONITHd failure resulted in un-runnable actions"); abort_transition(INFINITY, tg_restart, "Stonith failure", last_action); return TRUE; } return FALSE; } static void tengine_stonith_connection_destroy(stonith_t *st, const char *event, xmlNode *msg) { if(is_set(fsa_input_register, R_ST_REQUIRED)) { crm_crit("Fencing daemon connection failed"); mainloop_set_trigger(stonith_reconnect); } else { crm_info("Fencing daemon disconnected"); } /* cbchan will be garbage at this point, arrange for it to be reset */ stonith_api->state = stonith_disconnected; if(AM_I_DC) { fail_incompletable_stonith(transition_graph); trigger_graph(); } } /* */ #ifdef SUPPORT_CMAN # include # include "../lib/common/stack.h" #endif static void tengine_stonith_notify(stonith_t *st, const char *event, xmlNode *msg) { int rc = -99; const char *origin = NULL; const char *target = NULL; const char *executioner = NULL; xmlNode *action = get_xpath_object("//st-data", msg, LOG_ERR); if(action == NULL) { crm_log_xml(LOG_ERR, "Notify data not found", msg); return; } crm_log_xml(LOG_DEBUG, "stonith_notify", msg); crm_element_value_int(msg, F_STONITH_RC, &rc); origin = crm_element_value(action, F_STONITH_ORIGIN); target = crm_element_value(action, F_STONITH_TARGET); executioner = crm_element_value(action, F_STONITH_DELEGATE); if(rc == stonith_ok && crm_str_eq(target, fsa_our_uname, TRUE)) { crm_err("We were alegedly just fenced by %s for %s!", executioner, origin); register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__); } else if(rc == stonith_ok) { crm_info("Peer %s was terminated (%s) by %s for %s (ref=%s): %s", target, crm_element_value(action, F_STONITH_OPERATION), executioner, origin, crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc)); } else { crm_err("Peer %s could not be terminated (%s) by %s for %s (ref=%s): %s", target, crm_element_value(action, F_STONITH_OPERATION), executioner?executioner:"", origin, crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc)); } #ifdef SUPPORT_CMAN if(rc == stonith_ok && is_cman_cluster()) { int local_rc = 0; FILE *confirm = NULL; char *target_copy = crm_strdup(target); /* In case fenced hasn't noticed yet */ local_rc = fenced_external(target_copy); if(local_rc != 0) { crm_err("Could not notify CMAN that '%s' is now fenced: %d", target, local_rc); } else { crm_notice("Notified CMAN that '%s' is now fenced", target); } /* In case fenced is already trying to shoot it */ confirm = fopen("/var/run/cluster/fenced_override", "w"); if(confirm) { local_rc = fprintf(confirm, "%s\n", target_copy); if(local_rc < strlen(target_copy)) { crm_err("Confirmation of CMAN fencing event for '%s' failed: %d", target, local_rc); } else { crm_notice("Confirmed CMAN fencing event for '%s'", target); } fflush(confirm); fclose(confirm); } } #endif if(rc == stonith_ok && safe_str_eq(target, origin)) { if(fsa_our_dc == NULL || safe_str_eq(fsa_our_dc, target)) { const char *uuid = get_uuid(target); crm_notice("Target was our leader %s/%s (recorded leader: %s)", target, uuid, fsa_our_dc?fsa_our_dc:""); /* There's no need for everyone to update the cib. * Have the node that performed the op do the update too. * In the unlikely event that both die, the DC would be * shot a second time which is not ideal but safe. */ if(safe_str_eq(executioner, fsa_our_uname)) { send_stonith_update(NULL, target, uuid); } } } } gboolean te_connect_stonith(gpointer user_data) { int lpc = 0; int rc = stonith_ok; if(stonith_api == NULL) { stonith_api = stonith_api_new(); } if(stonith_api->state != stonith_disconnected) { crm_debug_2("Still connected"); return TRUE; } for(lpc = 0; lpc < 30; lpc++) { crm_info("Attempting connection to fencing daemon..."); sleep(1); rc = stonith_api->cmds->connect(stonith_api, crm_system_name, NULL); if(rc == stonith_ok) { break; } if(user_data != NULL) { crm_err("Sign-in failed: triggered a retry"); mainloop_set_trigger(stonith_reconnect); return TRUE; } crm_err("Sign-in failed: pausing and trying again in 2s..."); sleep(1); } CRM_CHECK(rc == stonith_ok, return TRUE); /* If not, we failed 30 times... just get out */ stonith_api->cmds->register_notification( stonith_api, T_STONITH_NOTIFY_DISCONNECT, tengine_stonith_connection_destroy); stonith_api->cmds->register_notification( stonith_api, STONITH_OP_FENCE, tengine_stonith_notify); crm_info("Connected"); return TRUE; } gboolean stop_te_timer(crm_action_timer_t *timer) { const char *timer_desc = "action timer"; if(timer == NULL) { return FALSE; } if(timer->reason == timeout_abort) { timer_desc = "global timer"; crm_debug_2("Stopping %s", timer_desc); } if(timer->source_id != 0) { crm_debug_2("Stopping %s", timer_desc); g_source_remove(timer->source_id); timer->source_id = 0; } else { crm_debug_2("%s was already stopped", timer_desc); return FALSE; } return TRUE; } gboolean te_graph_trigger(gpointer user_data) { enum transition_status graph_rc = -1; if(transition_graph == NULL) { crm_debug("Nothing to do"); return TRUE; } crm_debug_2("Invoking graph %d in state %s", transition_graph->id, fsa_state2string(fsa_state)); switch(fsa_state) { case S_STARTING: case S_PENDING: case S_NOT_DC: case S_HALT: case S_ILLEGAL: case S_STOPPING: case S_TERMINATE: return TRUE; break; default: break; } if(transition_graph->complete == FALSE) { graph_rc = run_graph(transition_graph); print_graph(LOG_DEBUG_3, transition_graph); if(graph_rc == transition_active) { crm_debug_3("Transition not yet complete"); return TRUE; } else if(graph_rc == transition_pending) { crm_debug_3("Transition not yet complete - no actions fired"); return TRUE; } if(graph_rc != transition_complete) { crm_err("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_WARNING, transition_graph); } } crm_info("Transition %d is now complete", transition_graph->id); transition_graph->complete = TRUE; notify_crmd(transition_graph); return TRUE; } void trigger_graph_processing(const char *fn, int line) { mainloop_set_trigger(transition_trigger); crm_debug_2("%s:%d - Triggered graph processing", fn, line); } void abort_transition_graph( int abort_priority, enum transition_action abort_action, const char *abort_text, xmlNode *reason, const char *fn, int line) { int log_level = LOG_INFO; const char *magic = NULL; CRM_CHECK(transition_graph != NULL, return); if(reason) { int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; xmlNode *diff = get_xpath_object("//"F_CIB_UPDATE_RESULT"//diff", reason, LOG_DEBUG_2); magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC); if(diff) { cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s, cib=%d.%d.%d) : %s", fn, line, transition_graph->complete, TYPE(reason), ID(reason), magic?magic:"NA", diff_add_admin_epoch,diff_add_epoch,diff_add_updates, abort_text); } else { do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s) : %s", fn, line, transition_graph->complete, TYPE(reason), ID(reason), magic?magic:"NA", abort_text); } } else { do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d) : %s", fn, line, transition_graph->complete, abort_text); } switch(fsa_state) { case S_STARTING: case S_PENDING: case S_NOT_DC: case S_HALT: case S_ILLEGAL: case S_STOPPING: case S_TERMINATE: do_crm_log(log_level, "Abort suppressed: state=%s (complete=%d)", fsa_state2string(fsa_state), transition_graph->complete); return; default: break; } if(magic == NULL && reason != NULL) { crm_log_xml(log_level+1, "Cause", reason); } /* Make sure any queued calculations are discarded ASAP */ crm_free(fsa_pe_ref); fsa_pe_ref = NULL; if(transition_graph->complete) { - register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL); + if(transition_timer->period_ms > 0) { + crm_timer_start(transition_timer); + } else { + register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL); + } return; } update_abort_priority( transition_graph, abort_priority, abort_action, abort_text); mainloop_set_trigger(transition_trigger); } diff --git a/crmd/tengine.h b/crmd/tengine.h old mode 100644 new mode 100755 index 9e823977dc..33f94fd867 --- a/crmd/tengine.h +++ b/crmd/tengine.h @@ -1,75 +1,74 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TENGINE__H #define TENGINE__H #include #include #include extern stonith_t *stonith_api; extern void send_stonith_update(crm_action_t *stonith_action, const char *target, const char *uuid); /* tengine */ extern crm_action_t *match_down_event( int rc, const char *target, const char *filter); extern crm_action_t *get_cancel_action(const char *id, const char *node); extern gboolean cib_action_update(crm_action_t *action, int status, int op_rc); extern gboolean fail_incompletable_actions(crm_graph_t *graph, const char *down_node); extern gboolean process_graph_event(xmlNode *event, const char *event_node); /* utils */ extern crm_action_t *get_action(int id, gboolean confirmed); extern gboolean start_global_timer(crm_action_timer_t *timer, int timeout); extern gboolean stop_te_timer(crm_action_timer_t *timer); extern const char *get_rsc_state(const char *task, op_status_t status); /* unpack */ extern gboolean process_te_message(xmlNode * msg, xmlNode *xml_data); extern crm_graph_t *transition_graph; extern crm_trigger_t *transition_trigger; extern char *te_uuid; extern void notify_crmd(crm_graph_t *graph); #include extern void trigger_graph_processing(const char *fn, int line); extern void abort_transition_graph( int abort_priority, enum transition_action abort_action, const char *abort_text, xmlNode *reason, const char *fn, int line); #define trigger_graph() trigger_graph_processing(__FUNCTION__, __LINE__) #define abort_transition(pri, action, text, reason) \ abort_transition_graph(pri, action, text, reason,__FUNCTION__,__LINE__); extern gboolean te_connect_stonith(gpointer user_data); extern GCHSource *stonith_src; extern crm_trigger_t *transition_trigger; extern crm_trigger_t *stonith_reconnect; -extern crm_action_timer_t *transition_timer; extern char *failed_stop_offset; extern char *failed_start_offset; extern int active_timeout; extern int stonith_op_active; #endif diff --git a/crmd/utils.c b/crmd/utils.c index 0ff35686be..b8e7cc252e 100644 --- a/crmd/utils.c +++ b/crmd/utils.c @@ -1,1300 +1,1302 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <../tools/attrd.h> /* A_DC_TIMER_STOP, A_DC_TIMER_START, * A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START * A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START */ void 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; 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 */ register_fsa_input(cause, I_ELECTION, NULL); } } 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); */ } } const char * get_timer_desc(fsa_timer_t *timer) { if(timer == election_trigger) { return "Election Trigger"; } else if(timer == election_timeout) { return "Election Timeout"; } else if(timer == shutdown_escalation_timer) { return "Shutdown Escalation"; } else if(timer == integration_timer) { return "Integration Timer"; } else if(timer == finalization_timer) { return "Finalization Timer"; + } else if(timer == transition_timer) { + return "New Transition Timer"; + } else if(timer == wait_timer) { return "Wait Timer"; } else if(timer == recheck_timer) { return "PEngine Recheck Timer"; } return "Unknown Timer"; } gboolean crm_timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; if(timer == wait_timer || timer == recheck_timer + || timer == transition_timer || timer == finalization_timer || timer == election_trigger) { - crm_info("%s (%s) just popped! (%dms)", + crm_info("%s (%s) just popped (%dms)", get_timer_desc(timer), fsa_input2string(timer->fsa_input), timer->period_ms); } else { - crm_err("%s (%s) just popped! (%dms)", - get_timer_desc(timer), - fsa_input2string(timer->fsa_input), timer->period_ms); + crm_err("%s (%s) just popped in state %s! (%dms)", + get_timer_desc(timer), fsa_input2string(timer->fsa_input), + fsa_state2string(fsa_state), timer->period_ms); } if(timer->repeat == FALSE) { crm_timer_stop(timer); /* make it _not_ go off again */ } if(timer->fsa_input == I_INTEGRATED) { crm_info("Welcomed: %d, Integrated: %d", g_hash_table_size(welcomed_nodes), g_hash_table_size(integrated_nodes)); if(g_hash_table_size(welcomed_nodes) == 0) { /* If we don't even have ourself, start again */ register_fsa_error_adv( C_FSA_INTERNAL, I_ELECTION, NULL, NULL, __FUNCTION__); } else { register_fsa_input_before( C_TIMER_POPPED, timer->fsa_input, NULL); } - } else if(timer->fsa_input == I_PE_CALC - && fsa_state != S_IDLE) { + } else if(timer == recheck_timer && fsa_state != S_IDLE) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); - } else if(timer->fsa_input == I_FINALIZED - && fsa_state != S_FINALIZE_JOIN) { + } else if(timer == finalization_timer && fsa_state != S_FINALIZE_JOIN) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); } else if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } crm_debug_3("Triggering FSA: %s", __FUNCTION__); mainloop_set_trigger(fsa_source); return TRUE; } gboolean crm_timer_start(fsa_timer_t *timer) { const char *timer_desc = get_timer_desc(timer); if(timer->source_id == 0 && timer->period_ms > 0) { timer->source_id = g_timeout_add( timer->period_ms, timer->callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); 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 = get_timer_desc(timer); if(timer == NULL) { crm_err("Attempted to stop NULL timer"); return FALSE; } else if(timer->source_id != 0) { crm_debug_2("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); timer->source_id = 0; } else { crm_debug_2("%s (%s:%dms) already stopped", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); return FALSE; } return TRUE; } const char * fsa_input2string(enum crmd_fsa_input input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; break; case I_CIB_OP: inputAsText = "I_CIB_OP (unused)"; 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_DC_JOIN_FINAL: actionAsText = "A_DC_JOIN_FINAL"; 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_ELECTION_CHECK: actionAsText = "A_ELECTION_CHECK"; 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 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_HALT: actionAsText = "A_TE_HALT"; 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; /* Composite actions */ case A_DC_TIMER_START|A_CL_JOIN_QUERY: actionAsText = "A_DC_TIMER_START|A_CL_JOIN_QUERY"; 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_unlikely(log_level, "%s %.16llx (R_THE_DC)", text, R_THE_DC); } if(is_set(input_register, R_STARTING)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_STARTING)", text, R_STARTING); } if(is_set(input_register, R_SHUTDOWN)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN); } if(is_set(input_register, R_STAYDOWN)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN); } if(is_set(input_register, R_JOIN_OK)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK); } if(is_set(input_register, R_READ_CONFIG)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_READ_CONFIG)", text, R_READ_CONFIG); } if(is_set(input_register, R_INVOKE_PE)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE); } if(is_set(input_register, R_CIB_CONNECTED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if(is_set(input_register, R_PE_CONNECTED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if(is_set(input_register, R_TE_CONNECTED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if(is_set(input_register, R_LRM_CONNECTED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } if(is_set(input_register, R_CIB_REQUIRED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); } if(is_set(input_register, R_PE_REQUIRED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED); } if(is_set(input_register, R_TE_REQUIRED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED); } if(is_set(input_register, R_REQ_PEND)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND); } if(is_set(input_register, R_PE_PEND)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_PE_PEND)", text, R_PE_PEND); } if(is_set(input_register, R_TE_PEND)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_TE_PEND)", text, R_TE_PEND); } if(is_set(input_register, R_RESP_PEND)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND); } if(is_set(input_register, R_CIB_DONE)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE); } if(is_set(input_register, R_HAVE_CIB)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB); } if(is_set(input_register, R_CIB_ASKED)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED); } if(is_set(input_register, R_CCM_DATA)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA); } if(is_set(input_register, R_PEER_DATA)) { do_crm_log_unlikely(log_level, "%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA); } if(is_set(input_register, R_IN_RECOVERY)) { do_crm_log_unlikely(log_level, "%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_unlikely(log_level, "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if(is_set(action, A_DC_TIMER_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if(is_set(action, A_FINALIZE_TIMER_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if(is_set(action, A_FINALIZE_TIMER_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_ELECTION_CHECK)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_ELECTION_CHECK) %s", A_ELECTION_CHECK, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if(is_set(action, A_CL_JOIN_REQUEST)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if(is_set(action, A_CL_JOIN_RESULT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if(is_set(action, A_DC_JOIN_OFFER_ALL)) { do_crm_log_unlikely(log_level, "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_unlikely(log_level, "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_unlikely(log_level, "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_unlikely(log_level, "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_unlikely(log_level, "Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_RECOVER)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CIB_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_PE_INVOKE)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { do_crm_log_unlikely(log_level, "Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { do_crm_log_unlikely(log_level, "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. */ xmlNode *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug_3("Creating node entry for %s", uname); set_uuid(tmp1, XML_ATTR_UUID, uname); crm_xml_add(tmp1, XML_ATTR_UNAME, uname); crm_xml_add(tmp1, XML_ATTR_TYPE, type); fsa_cib_anon_update(XML_CIB_TAG_NODES, tmp1, cib_scope_local|cib_quorum_override|cib_can_create); free_xml(tmp1); } xmlNode* create_node_state( const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, gboolean clear_shutdown, const char *src) { xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug_2("%s Creating node state entry for %s", src, uname); set_uuid(node_state, XML_ATTR_UUID, uname); if(crm_element_value(node_state, XML_ATTR_UUID) == NULL) { crm_debug("Node %s is not a cluster member", uname); free_xml(node_state); return NULL; } 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, XML_ATTR_ORIGIN, src); if(clear_shutdown) { crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN, "0"); } crm_log_xml_debug_3(node_state, "created"); return node_state; } extern GHashTable *ipc_clients; void process_client_disconnect(crmd_client_t *curr_client) { struct crm_subsystem_s *the_subsystem = NULL; CRM_CHECK(curr_client != NULL, return); crm_debug_2("received HUP from %s", curr_client->table_key); if (curr_client->sub_sys == NULL) { crm_debug_2("Client hadn't registered with us yet"); } else if (strcasecmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcasecmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcasecmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { the_subsystem->ipc = NULL; the_subsystem->client = NULL; crm_info("Received HUP from %s:[%d]", the_subsystem->name, the_subsystem->pid); } else { /* else that was a transient client */ crm_debug_2("Received HUP from transient client"); } if (curr_client->table_key != NULL) { /* * Key is destroyed below as: * curr_client->table_key * Value is cleaned up by: * crmd_ipc_connection_destroy * which will also call: * G_main_del_IPC_Channel */ g_hash_table_remove(ipc_clients, curr_client->table_key); } } gboolean update_dc(xmlNode *msg) { char *last_dc = fsa_our_dc; const char *dc_version = NULL; const char *welcome_from = NULL; if(msg != NULL) { gboolean invalid = FALSE; dc_version = crm_element_value(msg, F_CRM_VERSION); welcome_from = crm_element_value(msg, F_CRM_HOST_FROM); CRM_CHECK(dc_version != NULL, return FALSE); CRM_CHECK(welcome_from != NULL, return FALSE); if(AM_I_DC && safe_str_neq(welcome_from, fsa_our_uname)) { invalid = TRUE; } else if(fsa_our_dc && safe_str_neq(welcome_from, fsa_our_dc)) { invalid = TRUE; } if(invalid) { CRM_CHECK(fsa_our_dc != NULL, crm_err("We have no DC")); if(AM_I_DC) { crm_err("Not updating DC to %s (%s): we are also a DC", welcome_from, dc_version); } else { crm_warn("New DC %s is not %s", welcome_from, fsa_our_dc); } register_fsa_action(A_CL_JOIN_QUERY|A_DC_TIMER_START); return FALSE; } } crm_free(fsa_our_dc_version); fsa_our_dc_version = NULL; fsa_our_dc = NULL; /* Free'd as last_dc */ if(welcome_from != NULL) { fsa_our_dc = crm_strdup(welcome_from); } if(dc_version != NULL) { fsa_our_dc_version = crm_strdup(dc_version); } if(safe_str_eq(fsa_our_dc, last_dc)) { /* do nothing */ } else if(fsa_our_dc != NULL) { crm_info("Set DC to %s (%s)", crm_str(fsa_our_dc), crm_str(fsa_our_dc_version)); } else if(last_dc != NULL) { crm_info("Unset DC %s", crm_str(last_dc)); } crm_free(last_dc); return TRUE; } #define STATUS_PATH_MAX 512 static void erase_xpath_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { char *xpath = user_data; do_crm_log(rc==0?LOG_INFO:LOG_NOTICE, "Deletion of \"%s\": %s (rc=%d)", xpath, cib_error2string(rc), rc); crm_free(xpath); } void erase_status_tag(const char *uname, const char *tag, int options) { int rc = cib_ok; char xpath[STATUS_PATH_MAX]; int cib_opts = cib_quorum_override|cib_xpath|options; if(fsa_cib_conn && uname) { snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", uname, tag); rc = fsa_cib_conn->cmds->delete(fsa_cib_conn, xpath, NULL, cib_opts); add_cib_op_callback(fsa_cib_conn, rc, FALSE, crm_strdup(xpath), erase_xpath_callback); } } static IPC_Channel *attrd = NULL; static gboolean attrd_dispatch(IPC_Channel *client, gpointer user_data) { xmlNode *msg = NULL; gboolean stay_connected = TRUE; while(IPC_ISRCONN(client)) { if(client->ops->is_message_pending(client) == 0) { break; } msg = xmlfromIPC(client, MAX_IPC_DELAY); if (msg != NULL) { crm_log_xml_err(msg, "attrd:msg"); free_xml(msg); } } if (client->ch_status != IPC_CONNECT) { stay_connected = FALSE; } return stay_connected; } static void attrd_connection_destroy(gpointer user_data) { crm_err("Lost connection to attrd"); attrd = NULL; return; } void update_attrd(const char *host, const char *name, const char *value, const char *user_name) { int retries = 5; gboolean rc = FALSE; retry: if(attrd == NULL) { crm_info("Connecting to attrd..."); attrd = init_client_ipc_comms_nodispatch(T_ATTRD); if(attrd) { G_main_add_IPC_Channel( G_PRIORITY_LOW, attrd, FALSE, attrd_dispatch, NULL, attrd_connection_destroy); } } if(attrd != NULL) { rc = attrd_update_delegate(attrd, 'U', host, name, value, XML_CIB_TAG_STATUS, NULL, NULL, user_name); } else { crm_warn("Could not connect to %s", T_ATTRD); } if(rc == FALSE) { crm_err("Could not send %s %s", T_ATTRD, name?"update":"refresh"); attrd = NULL; if(retries > 0) { retries--; sleep(1); goto retry; } } }