diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index 7d7fe507a9..069db0d487 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,1103 +1,1103 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /* for access */ #include #include #include #include #include #include #include #include #include #include char *make_stop_id(const char *rsc, int call_id); void ghash_print_pending(gpointer key, gpointer value, gpointer user_data); gboolean stop_all_resources(void); gboolean resource_stopped(gpointer key, gpointer value, gpointer user_data); gboolean build_operation_update( crm_data_t *rsc_list, lrm_op_t *op, const char *src, int lpc); gboolean build_active_RAs(crm_data_t *rsc_list); void do_update_resource(lrm_op_t *op); enum crmd_fsa_input do_lrm_rsc_op( lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg); enum crmd_fsa_input do_fake_lrm_op(gpointer data); void stop_recurring_action( gpointer key, gpointer value, gpointer user_data); gboolean remove_recurring_action( gpointer key, gpointer value, gpointer user_data); void free_recurring_op(gpointer value); GHashTable *xml2list(crm_data_t *parent); GHashTable *monitors = NULL; GHashTable *resources = NULL; GHashTable *resources_confirmed = NULL; GHashTable *shutdown_ops = NULL; int num_lrm_register_fails = 0; int max_lrm_register_fails = 30; const char *rsc_path[] = { /* XML_GRAPH_TAG_RSC_OP, */ XML_CIB_TAG_RESOURCE, "instance_attributes", "rsc_parameters" }; enum crmd_rscstate { crmd_rscstate_NULL, crmd_rscstate_START, crmd_rscstate_START_PENDING, crmd_rscstate_START_OK, crmd_rscstate_START_FAIL, crmd_rscstate_STOP, crmd_rscstate_STOP_PENDING, crmd_rscstate_STOP_OK, crmd_rscstate_STOP_FAIL, crmd_rscstate_MON, crmd_rscstate_MON_PENDING, crmd_rscstate_MON_OK, crmd_rscstate_MON_FAIL, crmd_rscstate_GENERIC_PENDING, crmd_rscstate_GENERIC_OK, crmd_rscstate_GENERIC_FAIL }; void free_lrm_op(lrm_op_t *op); const char *crmd_rscstate2string(enum crmd_rscstate state); const char * crmd_rscstate2string(enum crmd_rscstate state) { switch(state) { case crmd_rscstate_NULL: return NULL; case crmd_rscstate_START: - return CRMD_RSCSTATE_START; + return CRMD_ACTION_START; case crmd_rscstate_START_PENDING: - return CRMD_RSCSTATE_START_PENDING; + return CRMD_ACTION_START_PENDING; case crmd_rscstate_START_OK: - return CRMD_RSCSTATE_START_OK; + return CRMD_ACTION_STARTED; case crmd_rscstate_START_FAIL: - return CRMD_RSCSTATE_START_FAIL; + return CRMD_ACTION_START_FAIL; case crmd_rscstate_STOP: - return CRMD_RSCSTATE_STOP; + return CRMD_ACTION_STOP; case crmd_rscstate_STOP_PENDING: - return CRMD_RSCSTATE_STOP_PENDING; + return CRMD_ACTION_STOP_PENDING; case crmd_rscstate_STOP_OK: - return CRMD_RSCSTATE_STOP_OK; + return CRMD_ACTION_STOPPED; case crmd_rscstate_STOP_FAIL: - return CRMD_RSCSTATE_STOP_FAIL; + return CRMD_ACTION_STOP_FAIL; case crmd_rscstate_MON: - return CRMD_RSCSTATE_MON; + return CRMD_ACTION_MON; case crmd_rscstate_MON_PENDING: - return CRMD_RSCSTATE_MON_PENDING; + return CRMD_ACTION_MON_PENDING; case crmd_rscstate_MON_OK: - return CRMD_RSCSTATE_MON_OK; + return CRMD_ACTION_MON_OK; case crmd_rscstate_MON_FAIL: - return CRMD_RSCSTATE_MON_FAIL; + return CRMD_ACTION_MON_FAIL; case crmd_rscstate_GENERIC_PENDING: - return CRMD_RSCSTATE_GENERIC_PENDING; + return CRMD_ACTION_GENERIC_PENDING; case crmd_rscstate_GENERIC_OK: - return CRMD_RSCSTATE_GENERIC_OK; + return CRMD_ACTION_GENERIC_OK; case crmd_rscstate_GENERIC_FAIL: - return CRMD_RSCSTATE_GENERIC_FAIL; + return CRMD_ACTION_GENERIC_FAIL; } return ""; } /* A_LRM_CONNECT */ enum crmd_fsa_input do_lrm_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) { int ret = HA_OK; if(action & A_LRM_DISCONNECT) { if(fsa_lrm_conn) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); } /* TODO: Clean up the hashtable */ } if(action & A_LRM_CONNECT) { crm_trace("LRM: connect..."); ret = HA_OK; monitors = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, free_recurring_op); resources = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); resources_confirmed = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); shutdown_ops = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); if(NULL == fsa_lrm_conn) { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); ret = HA_FAIL; } if(ret == HA_OK) { crm_trace("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon( fsa_lrm_conn, CRM_SYSTEM_CRMD); } if(ret != HA_OK) { if(++num_lrm_register_fails < max_lrm_register_fails) { crm_warn("Failed to sign on to the LRM %d" " (%d max) times", num_lrm_register_fails, max_lrm_register_fails); crm_timer_start(wait_timer); crmd_fsa_stall(NULL); return I_NULL; } } if(ret == HA_OK) { crm_trace("LRM: set_lrm_callback..."); ret = fsa_lrm_conn->lrm_ops->set_lrm_callback( fsa_lrm_conn, lrm_op_callback); if(ret != HA_OK) { crm_err("Failed to set LRM callbacks"); } } if(ret != HA_OK) { crm_err("Failed to sign on to the LRM %d" " (max) times", num_lrm_register_fails); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return I_NULL; } /* TODO: create a destroy handler that causes * some recovery to happen */ G_main_add_IPC_Channel(G_PRIORITY_LOW, fsa_lrm_conn->lrm_ops->ipcchan(fsa_lrm_conn), FALSE, lrm_dispatch, fsa_lrm_conn, default_ipc_connection_destroy); set_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return I_NULL; } gboolean stop_all_resources(void) { GListPtr lrm_list = NULL; crm_info("Makeing sure all active resources are stopped before exit"); if(fsa_lrm_conn == NULL) { return TRUE; } else if(is_set(fsa_input_register, R_SENT_RSC_STOP)) { crm_debug("Already sent stop operation"); return TRUE; } lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( rsc_id, char, lrm_list, lpc, - do_lrm_rsc_op(NULL, rsc_id, CRMD_RSCSTATE_STOP, NULL); + do_lrm_rsc_op(NULL, rsc_id, CRMD_ACTION_STOP, NULL); ); set_bit_inplace(fsa_input_register, R_SENT_RSC_STOP); if(g_hash_table_size(shutdown_ops) == 0) { register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } else { crm_info("Waiting for %d pending stop operations " " to complete before exiting", g_hash_table_size(shutdown_ops)); } return TRUE; } gboolean build_operation_update( crm_data_t *xml_rsc, lrm_op_t *op, const char *src, int lpc) { int len = 0; char *tmp = NULL; char *fail_state = NULL; crm_data_t *xml_op = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return FALSE; } crm_info("%s: Updating resouce %s after %s %s op", src, op->rsc_id, op_status2text(op->op_status), op->op_type); if(op->op_status == LRM_OP_CANCELLED) { crm_debug("Ignoring cancelled op"); return TRUE; } xml_op = create_xml_node(xml_rsc, XML_LRM_TAG_RSC_OP); if(op->interval <= 0 - ||safe_str_eq(op->op_type, CRMD_RSCSTATE_START) - || safe_str_eq(op->op_type, CRMD_RSCSTATE_STOP)) { + ||safe_str_eq(op->op_type, CRMD_ACTION_START) + || safe_str_eq(op->op_type, CRMD_ACTION_STOP)) { set_xml_property_copy(xml_op, XML_ATTR_ID, op->op_type); } else { char *op_id = generate_op_key( op->rsc_id, op->op_type, op->interval); set_xml_property_copy(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); } set_xml_property_copy(xml_rsc, XML_LRM_ATTR_LASTOP, op->op_type); set_xml_property_copy(xml_op, XML_LRM_ATTR_TASK, op->op_type); set_xml_property_copy(xml_op, "origin", src); /* Handle recurring ops - infer last op_status */ if(op->op_status == LRM_OP_PENDING && op->interval > 0) { if(op->rc == 0) { crm_debug("Mapping pending operation to DONE"); op->op_status = LRM_OP_DONE; } else { crm_debug("Mapping pending operation to ERROR"); op->op_status = LRM_OP_ERROR; } } switch(op->op_status) { case LRM_OP_PENDING: break; case LRM_OP_CANCELLED: crm_err("What to do here"); break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_debug("Resource action %s/%s failed: %d", op->rsc_id, op->op_type, op->op_status); len = strlen(op->op_type); len += strlen("_failed_"); crm_malloc0(fail_state, sizeof(char)*len); if(fail_state != NULL) { sprintf(fail_state, "%s_failed", op->op_type); } set_xml_property_copy( xml_op, XML_LRM_ATTR_RSCSTATE, fail_state); if(lpc == 0) { set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RSCSTATE, fail_state); } crm_free(fail_state); break; case LRM_OP_DONE: set_xml_property_copy( xml_op, XML_LRM_ATTR_RSCSTATE, op->user_data); if(lpc == 0) { set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RSCSTATE, op->user_data); } break; } tmp = crm_itoa(op->call_id); set_xml_property_copy(xml_op, XML_LRM_ATTR_CALLID, tmp); crm_free(tmp); /* set these on 'xml_rsc' too to make life easy for the TE */ tmp = crm_itoa(op->rc); set_xml_property_copy(xml_op, XML_LRM_ATTR_RC, tmp); set_xml_property_copy(xml_rsc, XML_LRM_ATTR_RC, tmp); crm_free(tmp); tmp = crm_itoa(op->op_status); set_xml_property_copy(xml_op, XML_LRM_ATTR_OPSTATUS, tmp); set_xml_property_copy(xml_rsc, XML_LRM_ATTR_OPSTATUS, tmp); crm_free(tmp); set_node_tstamp(xml_op); return TRUE; } gboolean build_active_RAs(crm_data_t *rsc_list) { GList *op_list = NULL; GList *lrm_list = NULL; gboolean found_op = FALSE; state_flag_t cur_state = 0; if(fsa_lrm_conn == NULL) { return FALSE; } lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( rid, char, lrm_list, lpc, lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); crm_data_t *xml_rsc = create_xml_node( rsc_list, XML_LRM_TAG_RESOURCE); int max_call_id = -1; crm_info("Processing lrm_rsc_t entry %s", rid); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); continue; } set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_verbose("\tcurrent state:%s", cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, crm_info("Processing op %s for %s (status=%d, rc=%d)", op->op_type, the_rsc->id, op->op_status, op->rc); if(max_call_id < op->call_id) { build_operation_update(xml_rsc, op, __FUNCTION__, llpc); } else if(max_call_id > op->call_id) { crm_err("Bad call_id in list=%d. Previous call_id=%d", op->call_id, max_call_id); } else { crm_debug("Skipping duplicate entry for call_id=%d", op->call_id); } found_op = TRUE; ); if(found_op == FALSE) { crm_err("Could not properly determin last op" " for %s from %d entries", the_rsc->id, g_list_length(op_list)); } g_list_free(op_list); ); g_list_free(lrm_list); return TRUE; } crm_data_t* do_lrm_query(gboolean is_replace) { crm_data_t *xml_result= NULL; crm_data_t *xml_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_data_t *xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); crm_data_t *rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES); /* Build a list of active (not always running) resources */ build_active_RAs(rsc_list); if(is_replace) { set_xml_property_copy( xml_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); } set_uuid(fsa_cluster_conn, xml_state, XML_ATTR_UUID, fsa_our_uname); set_xml_property_copy(xml_state, XML_ATTR_UNAME, fsa_our_uname); xml_result = create_cib_fragment(xml_state, NULL); crm_xml_devel(xml_state, "Current state of the LRM"); return xml_result; } /* A_LRM_INVOKE */ enum crmd_fsa_input do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { const char *crm_op = NULL; const char *operation = NULL; enum crmd_fsa_input next_input = I_NULL; ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); crm_op = cl_get_string(input->msg, F_CRM_TASK); operation = get_xml_attr_nested( input->xml, rsc_path, DIMOF(rsc_path) -3, XML_LRM_ATTR_TASK, FALSE); if(crm_op != NULL && safe_str_eq(crm_op, "lrm_query")) { crm_data_t *data = do_lrm_query(FALSE); HA_Message *reply = create_reply(input->msg, data); if(relay_message(reply, TRUE) == FALSE) { crm_err("Unable to route reply"); crm_log_message(LOG_ERR, reply); crm_msg_del(reply); } free_xml(data); } else if(operation != NULL) { char rid[64]; lrm_rsc_t *rsc = NULL; const char *id_from_cib = NULL; if(cur_state == S_STOPPING || cur_state == S_TERMINATE) { /* we will have already scheduled a stop */ crm_debug("Ignoring LRM operation while in state %s", fsa_state2string(cur_state)); } id_from_cib = get_xml_attr_nested( input->xml, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_ID, TRUE); if(id_from_cib == NULL) { crm_err("No value for %s in message at level %d.", XML_ATTR_ID, DIMOF(rsc_path) -2); return I_NULL; } /* only the first 16 chars are used by the LRM */ strncpy(rid, id_from_cib, 64); rid[63] = 0; rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); next_input = do_lrm_rsc_op(rsc, rid, operation, input->xml); } else { crm_err("Operation was neither a lrm_query, nor a rsc op. %s", crm_str(crm_op)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } return next_input; } struct recurring_op_s { char *rsc_id; int call_id; }; enum crmd_fsa_input do_lrm_rsc_op( lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg) { int call_id = 0; char *op_id = NULL; lrm_op_t* op = NULL; const char *type = NULL; const char *class = NULL; const char *provider = NULL; GHashTable *params = NULL; fsa_data_t *msg_data = NULL; CRM_DEV_ASSERT(rid != NULL); if(rsc != NULL) { class = rsc->class; type = rsc->type; } else if(msg != NULL) { class = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_AGENT_ATTR_CLASS, TRUE); type = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_TYPE, TRUE); provider = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_AGENT_ATTR_PROVIDER, FALSE); } - if(safe_str_neq(operation, CRMD_RSCSTATE_STOP)) { + if(safe_str_neq(operation, CRMD_ACTION_STOP)) { if(fsa_state == S_STARTING || fsa_state == S_STOPPING || fsa_state == S_TERMINATE) { crm_err("Discarding attempt to perform action %s on %s" " while in state %s", operation, rid, fsa_state2string(fsa_state)); return I_NULL; } else if(AM_I_DC == FALSE && fsa_state != S_NOT_DC) { crm_warn("Discarding attempt to perform action %s on %s" " in state %s", operation, rid, fsa_state2string(fsa_state)); return I_NULL; } } if(rsc == NULL) { /* check if its already there */ rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); } if(rsc == NULL) { /* add it to the list */ crm_verbose("adding rsc %s before operation", rid); if(msg != NULL) { params = xml2list(msg); } else { - CRM_DEV_ASSERT(safe_str_eq(CRMD_RSCSTATE_STOP, operation)); + CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); } fsa_lrm_conn->lrm_ops->add_rsc( fsa_lrm_conn, rid, class, type, provider, params); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); } if(rsc == NULL) { crm_err("Could not add resource %s to LRM", rid); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); return I_NULL; } /* stop the monitor before stopping the resource */ - if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) { + if(safe_str_eq(operation, CRMD_ACTION_STOP)) { g_hash_table_foreach(monitors, stop_recurring_action, rsc); g_hash_table_foreach_remove( monitors, remove_recurring_action, rsc); } /* now do the op */ crm_info("Performing op %s on %s", operation, rid); crm_malloc0(op, sizeof(lrm_op_t)); op->op_type = crm_strdup(operation); op->op_status = LRM_OP_PENDING; op->user_data = NULL; if(params == NULL) { if(msg != NULL) { params = xml2list(msg); } else { CRM_DEV_ASSERT(safe_str_eq( - CRMD_RSCSTATE_STOP, operation)); + CRMD_ACTION_STOP, operation)); } } op->params = params; op->interval = crm_get_msec(g_hash_table_lookup(op->params,"interval")); op->timeout = crm_get_msec(g_hash_table_lookup(op->params, "timeout")); op->start_delay = crm_get_msec( g_hash_table_lookup(op->params,"start_delay")); /* sanity */ if(op->interval < 0) { op->interval = 0; } if(op->timeout < 0) { op->timeout = 0; } if(op->start_delay < 0) { op->start_delay = 0; } if(g_hash_table_lookup(op->params, "timeout") != NULL) { char *timeout_ms = crm_itoa(op->timeout); g_hash_table_replace( op->params, crm_strdup("timeout"), timeout_ms); } if(g_hash_table_lookup(op->params, "interval") != NULL) { char *interval_ms = crm_itoa(op->interval); g_hash_table_replace( op->params, crm_strdup("interval"), interval_ms); } if(g_hash_table_lookup(op->params, "start_delay") != NULL) { char *delay_ms = crm_itoa(op->start_delay); g_hash_table_replace( op->params, crm_strdup("start_delay"), delay_ms); } if(op->interval > 0) { struct recurring_op_s *existing_op = NULL; op_id = generate_op_key(rsc->id, op->op_type, op->interval); existing_op = g_hash_table_lookup(monitors, op_id); if(existing_op != NULL) { crm_debug("Cancelling previous invocation of" " %s on %s (%d)", crm_str(op_id), rsc->id,existing_op->call_id); /*cancel it so we can then restart it without conflict*/ rsc->ops->cancel_op(rsc, existing_op->call_id); g_hash_table_remove(monitors, op_id); } } op->app_name = crm_strdup(CRM_SYSTEM_CRMD); - if(safe_str_eq(operation, CRMD_RSCSTATE_MON)) { + if(safe_str_eq(operation, CRMD_ACTION_MON)) { op->target_rc = CHANGED; } else { op->target_rc = EVERYTIME; } - if(safe_str_eq(CRMD_RSCSTATE_START, operation)) { - op->user_data = crm_strdup(CRMD_RSCSTATE_START_OK); + if(safe_str_eq(CRMD_ACTION_START, operation)) { + op->user_data = crm_strdup(CRMD_ACTION_STARTED); - } else if(safe_str_eq(CRMD_RSCSTATE_STOP, operation)) { - op->user_data = crm_strdup(CRMD_RSCSTATE_STOP_OK); + } else if(safe_str_eq(CRMD_ACTION_STOP, operation)) { + op->user_data = crm_strdup(CRMD_ACTION_STOPPED); - } else if(safe_str_eq(CRMD_RSCSTATE_MON, operation)) { + } else if(safe_str_eq(CRMD_ACTION_MON, operation)) { const char *last_op = g_hash_table_lookup(resources, rsc->id); - op->user_data = crm_strdup(CRMD_RSCSTATE_MON_OK); - if(safe_str_eq(last_op, CRMD_RSCSTATE_STOP)) { + op->user_data = crm_strdup(CRMD_ACTION_MON_OK); + if(safe_str_eq(last_op, CRMD_ACTION_STOP)) { crm_err("Attempting to schedule %s _after_ a stop.", op_id); free_lrm_op(op); crm_free(op_id); return I_NULL; } } else { crm_warn("Using status \"%s\" for op \"%s\"" "... this is still in the experimental stage.", - CRMD_RSCSTATE_GENERIC_OK, operation); - op->user_data = crm_strdup(CRMD_RSCSTATE_GENERIC_OK); + CRMD_ACTION_GENERIC_OK, operation); + op->user_data = crm_strdup(CRMD_ACTION_GENERIC_OK); } g_hash_table_replace( resources, crm_strdup(rsc->id), crm_strdup(operation)); op->user_data_len = 1+strlen(op->user_data); call_id = rsc->ops->perform_op(rsc, op); if(call_id <= 0) { crm_err("Operation %s on %s failed: %d", operation, rid, call_id); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } else if(op->interval > 0) { struct recurring_op_s *op = NULL; crm_malloc0(op, sizeof(struct recurring_op_s)); crm_debug("Adding recurring %s op for %s (%d)", op_id, rsc->id, call_id); op->call_id = call_id; op->rsc_id = crm_strdup(rsc->id); g_hash_table_insert(monitors, op_id, op); op_id = NULL; } else { /* record all non-recurring operations so we can wait * for them to complete during shutdown */ char *call_id_s = make_stop_id(rsc->id, call_id); g_hash_table_replace( shutdown_ops, call_id_s, crm_strdup(rsc->id)); crm_debug("Recording pending op: %s", call_id_s); } crm_free(op_id); free_lrm_op(op); return I_NULL; } void stop_recurring_action(gpointer key, gpointer value, gpointer user_data) { lrm_rsc_t *rsc = user_data; struct recurring_op_s *op = (struct recurring_op_s*)value; if(safe_str_eq(op->rsc_id, rsc->id)) { if(op->call_id > 0) { crm_debug("Stopping recurring op %d for %s (%s)", op->call_id, rsc->id, (char*)key); rsc->ops->cancel_op(rsc, op->call_id); } else { crm_err("Invalid call_id %d for %s", op->call_id, rsc->id); /* TODO: we probably need to look up the LRM to find it */ } } } gboolean remove_recurring_action(gpointer key, gpointer value, gpointer user_data) { lrm_rsc_t *rsc = user_data; struct recurring_op_s *op = (struct recurring_op_s*)value; if(safe_str_eq(op->rsc_id, rsc->id)) { return TRUE; } return FALSE; } void free_recurring_op(gpointer value) { struct recurring_op_s *op = (struct recurring_op_s*)value; crm_free(op->rsc_id); crm_free(op); } void free_lrm_op(lrm_op_t *op) { g_hash_table_destroy(op->params); crm_free(op->user_data); crm_free(op->op_type); crm_free(op->app_name); crm_free(op); } GHashTable * xml2list(crm_data_t *parent) { crm_data_t *nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); CRM_DEV_ASSERT(parent != NULL); if(parent != NULL) { nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); if(nvpair_list == NULL) { crm_debug("No attributes in %s", crm_element_name(parent)); crm_xml_verbose(parent,"No attributes for resource op"); } } xml_child_iter( nvpair_list, node_iter, XML_CIB_TAG_NVPAIR, const char *key = crm_element_value( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value( node_iter, XML_NVPAIR_ATTR_VALUE); crm_verbose("Added %s=%s", key, value); g_hash_table_insert( nvpair_hash, crm_strdup(key), crm_strdup(value)); ); return nvpair_hash; } void do_update_resource(lrm_op_t* op) { /* */ crm_data_t *update, *iter; crm_data_t *fragment; int rc = cib_ok; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return; } update = create_xml_node(NULL, XML_CIB_TAG_STATE); set_uuid(fsa_cluster_conn, update, XML_ATTR_UUID, fsa_our_uname); set_xml_property_copy(update, XML_ATTR_UNAME, fsa_our_uname); iter = create_xml_node(update, XML_CIB_TAG_LRM); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCE); set_xml_property_copy(iter, XML_ATTR_ID, op->rsc_id); build_operation_update(iter, op, __FUNCTION__, 0); fragment = create_cib_fragment(update, NULL); /* make it an asyncronous call and be done with it * * Best case: * the resource state will be discovered during * the next signup or election. * * Bad case: * we are shutting down and there is no DC at the time, * but then why were we shutting down then anyway? * (probably because of an internal error) * * Worst case: * we get shot for having resources "running" when the really weren't * * the alternative however means blocking here for too long, which * isnt acceptable */ rc = fsa_cib_conn->cmds->modify( fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, cib_quorum_override); if(rc > 0) { /* the return code is a call number, not an error code */ crm_devel("Sent resource state update message: %d", rc); } else { crm_err("Resource state update failed: %s", cib_error2string(rc)); CRM_DEV_ASSERT(rc == cib_ok); } free_xml(fragment); free_xml(update); } enum crmd_fsa_input do_lrm_event(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) { lrm_op_t* op = NULL; const char *last_op = NULL; if(msg_data->fsa_cause != C_LRM_OP_CALLBACK) { register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); return I_NULL; } op = fsa_typed_data(fsa_dt_lrm); CRM_DEV_ASSERT(op != NULL); CRM_DEV_ASSERT(op != NULL && op->rsc_id != NULL); if(crm_assert_failed) { return I_NULL; } if(op->op_status == LRM_OP_DONE && op->rc != EXECRA_OK) { crm_warn("Mapping operation %d status with a rc=%d" " to status %d", op->op_status, op->rc, LRM_OP_ERROR); op->op_status = LRM_OP_ERROR; } switch(op->op_status) { case LRM_OP_PENDING: /* this really shouldnt happen */ crm_err("LRM operation (%d) %s on %s %s: %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status), execra_code2string(op->rc)); break; case LRM_OP_ERROR: crm_err("LRM operation (%d) %s on %s %s: %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status), execra_code2string(op->rc)); crm_debug("Result: %s", op->output); break; case LRM_OP_CANCELLED: crm_warn("LRM operation (%d) %s on %s %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status)); return I_NULL; break; case LRM_OP_TIMEOUT: last_op = g_hash_table_lookup( resources_confirmed, crm_strdup(op->rsc_id)); - if(safe_str_eq(last_op, CRMD_RSCSTATE_STOP) - && safe_str_eq(op->op_type, CRMD_RSCSTATE_MON)) { + if(safe_str_eq(last_op, CRMD_ACTION_STOP) + && safe_str_eq(op->op_type, CRMD_ACTION_MON)) { crm_err("LRM sent a timed out %s operation" " _after_ a confirmed stop", op->op_type); return I_NULL; } crm_err("LRM operation (%d) %s on %s %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status)); break; case LRM_OP_NOTSUPPORTED: crm_err("LRM operation (%d) %s on %s %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status)); break; case LRM_OP_DONE: crm_debug("LRM operation (%d) %s on %s %s", op->call_id, op->op_type, crm_str(op->rsc_id), op_status2text(op->op_status)); break; } g_hash_table_replace(resources_confirmed, crm_strdup(op->rsc_id), crm_strdup(op->op_type)); do_update_resource(op); if(g_hash_table_size(shutdown_ops) > 0) { char *op_id = make_stop_id(op->rsc_id, op->call_id); if(g_hash_table_remove(shutdown_ops, op_id)) { crm_debug("Shutdown op %d (%s %s) confirmed", op->call_id, op->op_type, op->rsc_id); } else { crm_debug("Shutdown op %d (%s %s) not matched: %s", op->call_id, op->op_type, op->rsc_id, op_id); } crm_free(op_id); } if(is_set(fsa_input_register, R_SENT_RSC_STOP)) { if(g_hash_table_size(shutdown_ops) == 0) { register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } else { crm_debug("Still waiting for %d pending stop operations" " to complete before exiting", g_hash_table_size(shutdown_ops)); g_hash_table_foreach( shutdown_ops, ghash_print_pending, NULL); } } return I_NULL; } char * make_stop_id(const char *rsc, int call_id) { char *op_id = NULL; crm_malloc0(op_id, strlen(rsc) + 34); if(op_id != NULL) { snprintf(op_id, strlen(rsc) + 34, "%s:%d", rsc, call_id); } return op_id; } void ghash_print_pending(gpointer key, gpointer value, gpointer user_data) { const char *uname = key; crm_info("Pending action: %s", uname); } gboolean resource_stopped(gpointer key, gpointer value, gpointer user_data) { const char *this_rsc = value; const char *target_rsc = user_data; if(safe_str_eq(this_rsc, target_rsc)) { return TRUE; } return FALSE; } diff --git a/crm/tengine/callbacks.c b/crm/tengine/callbacks.c index c97c7ef238..670494ef05 100644 --- a/crm/tengine/callbacks.c +++ b/crm/tengine/callbacks.c @@ -1,299 +1,293 @@ -/* $Id: callbacks.c,v 1.25 2005/05/10 13:20:32 andrew Exp $ */ +/* $Id: callbacks.c,v 1.26 2005/05/15 13:13:41 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include void te_update_confirm(const char *event, HA_Message *msg); void te_update_confirm(const char *event, HA_Message *msg) { int rc = -1; gboolean done = FALSE; const char *op = cl_get_string(msg, F_CIB_OPERATION); const char *type = cl_get_string(msg, F_CIB_OBJTYPE); crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE); ha_msg_value_int(msg, F_CIB_RC, &rc); crm_debug("Processing %s...", event); crm_xml_verbose(update, "Processing update"); if (MSG_LOG) { struct stat buf; if(stat(DEVEL_DIR, &buf) != 0) { cl_perror("Stat of %s failed... exiting", DEVEL_DIR); exit(100); } } if(op == NULL) { crm_err( "Illegal CIB update, the operation must be specified"); send_complete("Illegal update", update, te_update); done = TRUE; } else if(strcmp(op, CRM_OP_CIB_ERASE) == 0) { /* these are always unexpected, trigger the PE */ crm_err("Need to trigger an election here so that" " the current state of all nodes is obtained"); send_complete("Erase event", update, te_update); done = TRUE; } else if(strcmp(op, CRM_OP_CIB_CREATE) == 0 || strcmp(op, CRM_OP_CIB_DELETE) == 0 || strcmp(op, CRM_OP_CIB_REPLACE) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* these are always unexpected, trigger the PE */ send_complete("Non-update change", update, te_update); done = TRUE; } else if(strcmp(op, CRM_OP_CIB_UPDATE) != 0) { crm_verbose("Ignoring %s op confirmation", op); done = TRUE; } if(done) { free_xml(update); return; } if(safe_str_eq(type, XML_CIB_TAG_CRMCONFIG)) { /* ignore - for the moment */ crm_debug("Ignoring changes to the %s section", type); } else if(safe_str_eq(type, XML_CIB_TAG_NODES)) { /* ignore new nodes until they sign up */ crm_debug("Ignoring changes to the %s section", type); } else if(safe_str_eq(type, XML_CIB_TAG_STATUS)) { /* this _may_ not be un-expected */ if(extract_event(update) == FALSE) { send_complete("Unexpected status update", update, te_update); } } else if(safe_str_eq(type, XML_CIB_TAG_NODES) || safe_str_eq(type, XML_CIB_TAG_RESOURCES) || safe_str_eq(type, XML_CIB_TAG_CONSTRAINTS)) { /* these are never expected */ crm_debug("Aborting on changes to the %s section", type); send_complete("Non-status update", update, te_update); } else { crm_warn("Ignoring update confirmation for %s object", type); } free_xml(update); } gboolean process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) { const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); const char *op = cl_get_string(msg, F_CRM_TASK); crm_log_message(LOG_DEV, msg); if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE) && safe_str_neq(op, CRM_OP_EVENTCC)) { crm_info("Message was a response not a request. Discarding"); return TRUE; } - crm_devel("Processing %s (%s) message", op, ref); + crm_debug("Processing %s (%s) message", op, ref); if(op == NULL){ /* error */ } else if(strcmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(sys_to == NULL || strcmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { crm_verbose("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcmp(op, CRM_OP_TRANSITION) == 0) { - - crm_trace("Initializing graph..."); initialize_graph(); - - crm_trace("Unpacking graph..."); unpack_graph(xml_data); - crm_debug("Initiating transition..."); in_transition = TRUE; - + crm_debug("Initiating transition..."); if(initiate_transition() == FALSE) { /* nothing to be done.. means we're done. */ crm_info("No actions to be taken..." " transition compelte."); } - crm_trace("Processing complete..."); } else if(strcmp(op, CRM_OP_TE_HALT) == 0) { initialize_graph(); send_complete(CRM_OP_TE_HALT, NULL, te_halt); } else if(strcmp(op, CRM_OP_TEABORT) == 0) { initialize_graph(); send_complete(CRM_OP_TEABORT, NULL, te_abort); } else if(strcmp(op, CRM_OP_QUIT) == 0) { crm_info("Received quit message, terminating"); exit(0); - } else if(in_transition == FALSE) { - crm_info("Received event_cc while not in a transition..." - " Poking the Policy Engine"); - send_complete("Initiate a transition", NULL, te_update); #ifdef TESTING } else if(strcmp(op, CRM_OP_EVENTCC) == 0) { crm_trace("Processing %s...", CRM_OP_EVENTCC); if(extract_event(msg) == FALSE) { send_complete("ttest loopback", msg, te_failed); } #endif + } else if(in_transition == FALSE) { + crm_info("Received event_cc while not in a transition..." + " Poking the Policy Engine"); + send_complete("Initiate a transition", NULL, te_update); } crm_devel("finished processing message"); return TRUE; } void tengine_stonith_callback(stonith_ops_t * op, void * private_data) { int action_id = -1; if(op == NULL) { crm_err("Called with a NULL op!"); return; } crm_info("optype=%d, node_name=%s, result=%d, node_list=%s", op->optype, op->node_name, op->op_result, (char *)op->node_list); /* this will mark the event complete if a match is found */ action_id = match_down_event( - op->node_name, XML_CIB_ATTR_STONITH, op->op_result); + op->node_name, CRM_OP_FENCE, op->op_result); if(op->op_result == STONITH_SUCCEEDED) { enum cib_errors rc = cib_ok; const char *target = op->node_name; const char *uuid = op->node_uuid; /* zero out the node-status & remove all LRM status info */ crm_data_t *update = NULL; crm_data_t *node_state = create_xml_node( NULL, XML_CIB_TAG_STATE); CRM_DEV_ASSERT(op->node_name != NULL); CRM_DEV_ASSERT(op->node_uuid != NULL); set_xml_property_copy(node_state, XML_ATTR_UUID, uuid); set_xml_property_copy(node_state, XML_ATTR_UNAME, target); set_xml_property_copy( node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); set_xml_property_copy( node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); set_xml_property_copy( node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); set_xml_property_copy( node_state, XML_CIB_ATTR_JOINSTATE,CRMD_JOINSTATE_DOWN); set_xml_property_copy( node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); set_xml_property_copy( node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); create_xml_node(node_state, XML_CIB_TAG_LRM); update = create_cib_fragment(node_state, NULL); free_xml(node_state); rc = te_cib_conn->cmds->modify( te_cib_conn, XML_CIB_TAG_STATUS, update, NULL, cib_quorum_override); if(action_id < 0) { send_complete("Stonith not matched", update, te_update); } else if(rc != cib_ok) { send_complete("Couldnt update CIB after stonith", update, te_failed); } else { process_trigger(action_id); check_for_completion(); } free_xml(update); } else { send_complete("Fencing op failed", NULL, te_failed); } } void tengine_stonith_connection_destroy(gpointer user_data) { #if 0 crm_err("Fencing daemon has left us: Shutting down...NOW"); /* shutdown properly later */ CRM_DEV_ASSERT(FALSE/* fencing daemon died */); #else crm_err("Fencing daemon has left us"); #endif return; } gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; while(stonithd_op_result_ready()) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if(ST_FAIL == stonithd_receive_ops_result(FALSE)) { crm_err("stonithd_receive_ops_result() failed"); } else { lpc++; } } crm_verbose("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index d9caa661d7..fa3452d8da 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,923 +1,923 @@ -/* $Id: tengine.c,v 1.68 2005/05/06 11:34:52 andrew Exp $ */ +/* $Id: tengine.c,v 1.69 2005/05/15 13:13:41 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include gboolean graph_complete = FALSE; GListPtr graph = NULL; IPC_Channel *crm_ch = NULL; uint transition_timeout = 30*1000; /* 30 seconds */ uint transition_fuzz_timeout = 0; uint default_transition_timeout = 30*1000; /* 30 seconds */ uint next_transition_timeout = 30*1000; /* 30 seconds */ void fire_synapse(synapse_t *synapse); gboolean initiate_action(action_t *action); gboolean confirm_synapse(synapse_t *synapse, int action_id); void check_synapse_triggers(synapse_t *synapse, int action_id); void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); gboolean in_transition = FALSE; te_timer_t *transition_timer = NULL; te_timer_t *transition_fuzz_timer = NULL; int transition_counter = 1; gboolean initialize_graph(void) { remove_cib_op_callback(-1, TRUE); if(transition_timer == NULL) { crm_malloc0(transition_timer, sizeof(te_timer_t)); transition_timer->timeout = 10; transition_timer->source_id = -1; transition_timer->reason = timeout_timeout; transition_timer->action = NULL; } else { stop_te_timer(transition_timer); } if(transition_fuzz_timer == NULL) { crm_malloc0(transition_fuzz_timer, sizeof(te_timer_t)); transition_fuzz_timer->timeout = 10; transition_fuzz_timer->source_id = -1; transition_fuzz_timer->reason = timeout_fuzz; transition_fuzz_timer->action = NULL; } else { stop_te_timer(transition_fuzz_timer); } while(g_list_length(graph) > 0) { synapse_t *synapse = g_list_nth_data(graph, 0); while(g_list_length(synapse->actions) > 0) { action_t *action = g_list_nth_data(synapse->actions,0); synapse->actions = g_list_remove( synapse->actions, action); if(action->timer->source_id > 0) { crm_devel("Removing timer for action: %d", action->id); g_source_remove(action->timer->source_id); } free_xml(action->xml); crm_free(action->timer); crm_free(action); } while(g_list_length(synapse->inputs) > 0) { action_t *action = g_list_nth_data(synapse->inputs, 0); synapse->inputs = g_list_remove(synapse->inputs, action); free_xml(action->xml); crm_free(action); } graph = g_list_remove(graph, synapse); crm_free(synapse); } graph = NULL; return TRUE; } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int match_graph_event(action_t *action, crm_data_t *event, const char *event_node) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_rsc = NULL; const char *event_rsc; const char *rsc_state; const char *event_action; const char *event_rc; const char *op_status; action_t *match = NULL; int op_status_i = -3; if(event == NULL) { crm_trace("Ignoring NULL event"); return -1; } event_action = crm_element_value(event, XML_LRM_ATTR_LASTOP); event_rsc = crm_element_value(event, XML_ATTR_ID); event_rc = crm_element_value(event, XML_LRM_ATTR_RC); rsc_state = crm_element_value(event, XML_LRM_ATTR_RSCSTATE); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); } this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK); this_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); this_rsc = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); crm_debug("matching against: <%s task=%s node=%s rsc_id=%s/>", crm_element_name(action->xml), this_action, this_node, this_rsc); if(safe_str_neq(this_action, event_action)) { crm_debug("Action %d : Action mismatch %s", action->id, event_action); } else if(safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_CRM_EVENT)) { - if(safe_str_eq(this_action, XML_CIB_ATTR_STONITH)) { + if(safe_str_eq(this_action, CRM_OP_FENCE)) { } else if(safe_str_neq(this_node, event_node)) { crm_debug("node mismatch: %s", event_node); } else { crm_devel(XML_GRAPH_TAG_CRM_EVENT); match = action; } crm_devel(XML_GRAPH_TAG_CRM_EVENT); match = action; } else if(safe_str_neq(this_node, event_node)) { crm_debug("Action %d : Node mismatch %s", action->id, event_node); } else if(safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_RSC_OP)) { crm_devel(XML_GRAPH_TAG_RSC_OP); if(safe_str_eq(this_rsc, event_rsc)) { match = action; } else { crm_debug("Action %d : bad rsc (%s) != (%s)", action->id, this_rsc, event_rsc); } } else { crm_debug("no match"); } if(match == NULL) { crm_devel("didnt match current action"); return -1; } crm_devel("matched"); /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ allow_fail = crm_element_value(match->xml, "allow_fail"); switch(op_status_i) { case LRM_OP_PENDING: /* should never happen */ CRM_DEV_ASSERT(op_status_i != LRM_OP_PENDING); break; case LRM_OP_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Action %s for \"%s\" on %s failed: %s", event_action, event_rsc, event_node, op_status2text(op_status_i)); if(FALSE == crm_is_true(allow_fail)) { send_complete( "Action failed", event, te_failed); return -2; } break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: crm_err("Unsupported action result: %d", op_status_i); send_complete("Unsupport action result", event, te_failed); return -2; } crm_debug("Action %d confirmed", match->id); match->complete = TRUE; return match->id; } int match_down_event(const char *target, const char *filter, int rc) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; action_t *match = NULL; slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, crm_data_t *action_args = NULL; if(action->type != action_type_crm) { continue; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } - if(safe_str_eq(this_action, XML_CIB_ATTR_STONITH)) { + if(safe_str_eq(this_action, CRM_OP_FENCE)) { action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); this_node = crm_element_value( action_args, XML_LRM_ATTR_TARGET); } else if(safe_str_eq(this_action, CRM_OP_SHUTDOWN)) { crm_element_value( action->xml, XML_LRM_ATTR_TASK); this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET); } else { crm_info("Action %d : Bad action %s", action->id, this_action); continue; } if(safe_str_neq(this_node, target)) { crm_info("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; ); if(match != NULL) { break; } ); if(match == NULL) { crm_devel("didnt match current action"); return -1; } crm_devel("matched"); /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ switch(rc) { case STONITH_SUCCEEDED: break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: allow_fail = crm_element_value(match->xml, "allow_fail"); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", target, rc); send_complete("Stonith failed", match->xml, te_failed); return -2; } break; default: crm_err("Unsupported action result: %d", rc); send_complete("Unsupport Stonith result", match->xml, te_failed); return -2; } crm_devel("Action %d was successful, looking for next action", match->id); match->complete = TRUE; return match->id; } gboolean process_graph_event(crm_data_t *event, const char *event_node) { int action_id = -1; int op_status_i = 0; const char *task = NULL; const char *rsc_id = NULL; const char *op_status = NULL; if(event != NULL) { task = crm_element_value(event, XML_LRM_ATTR_LASTOP); rsc_id = crm_element_value(event, XML_ATTR_ID); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); } crm_debug("Processing CIB update: %s %s on %s: %s", task, rsc_id, event_node, op_status2text(op_status_i)); } next_transition_timeout = transition_timeout; if(op_status_i == -1) { /* just information that the action was sent */ crm_debug("Ignoring TE initiated updates"); return TRUE; } slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, action_id = match_graph_event(action, event,event_node); if(action_id != -1) { break; } ); if(action_id != -1) { break; } ); if(event == NULL) { crm_debug("a transition is starting"); } else if(action_id > -1) { crm_xml_devel(event, "Event found"); } else if(action_id == -2) { crm_xml_info(event, "Event found but failed"); } else { /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ send_complete("Event not matched", event, te_update); return FALSE; } process_trigger(action_id); check_for_completion(); return TRUE; } void check_for_completion(void) { if(graph_complete) { /* allow some slack until we are pretty sure nothing * else is happening */ crm_info("Transition complete"); if(transition_fuzz_timer->timeout > 0) { crm_info("Allowing the system to stabilize for %d ms" " before S_IDLE transition", transition_fuzz_timer->timeout); start_te_timer(transition_fuzz_timer); } else { send_complete("complete", NULL, te_done); } } else { /* restart the transition timer again */ crm_devel("Transition not yet complete"); transition_timer->timeout = next_transition_timeout; start_te_timer(transition_timer); } } #ifdef TESTING # define te_log_action(log_level, fmt...) { \ do_crm_log(log_level, __FILE__, __FUNCTION__, fmt); \ fprintf(stderr, fmt); \ } #else # define te_log_action(log_level, fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt) #endif gboolean initiate_action(action_t *action) { gboolean ret = FALSE; gboolean send_command = FALSE; const char *on_node = NULL; const char *id = NULL; const char *task = NULL; const char *timeout = NULL; const char *msg_task = XML_GRAPH_TAG_RSC_OP; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); id = crm_element_value(action->xml, XML_ATTR_ID); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); timeout = crm_element_value(action->xml, XML_ATTR_TIMEOUT); if(id == NULL || strlen(id) == 0 || task == NULL || strlen(task) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s", crm_element_name(action->xml), crm_str(id), crm_str(task)); } else if(action->type == action_type_pseudo){ te_log_action(LOG_INFO, "Executing pseudo-event (%d): " "%s on %s", action->id, task, on_node); action->complete = TRUE; process_trigger(action->id); ret = TRUE; } else if(action->type == action_type_crm - && safe_str_eq(task, XML_CIB_ATTR_STONITH)){ + && safe_str_eq(task, CRM_OP_FENCE)){ crm_data_t *action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); const char *uuid = NULL; const char *target = NULL; const char *name = NULL; #ifndef TESTING stonith_ops_t * st_op = NULL; #endif xml_child_iter( action_args, nvpair, XML_CIB_TAG_NVPAIR, name = crm_element_value(nvpair, XML_NVPAIR_ATTR_NAME); if(safe_str_eq(name, XML_LRM_ATTR_TARGET)) { target = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } else if(safe_str_eq(name, XML_LRM_ATTR_TARGET_UUID)) { uuid = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } ); CRM_DEV_ASSERT(target != NULL); CRM_DEV_ASSERT(uuid != NULL); te_log_action(LOG_INFO, "Executing fencing operation (%s) on %s", id, target); #ifdef TESTING ret = TRUE; action->complete = TRUE; #else crm_malloc0(st_op, sizeof(stonith_ops_t)); st_op->optype = RESET; st_op->timeout = crm_atoi(timeout, "100"); /* ten seconds */ st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); if(stonithd_input_IPC_channel() == NULL) { crm_err("Cannot fence %s - stonith not available", target); } else if (ST_OK == stonithd_node_fence( st_op )) { ret = TRUE; } #endif } else if(on_node == NULL || strlen(on_node) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s on %s\n", crm_element_name(action->xml), crm_str(id), crm_str(task), crm_str(on_node)); } else if(action->type == action_type_crm){ te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", id, task, on_node); action->complete = TRUE; msg_task = task; send_command = TRUE; } else if(action->type == action_type_rsc){ /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ - if(safe_str_neq(task, CRMD_RSCSTATE_STOP)) { + if(safe_str_neq(task, CRMD_ACTION_STOP)) { cib_action_update(action, LRM_OP_PENDING); } else { cib_action_updated(NULL, 0, cib_ok, NULL, action); } ret = TRUE; } else { te_log_action(LOG_ERR, "Failed on unsupported command type: " "%s, %s (id=%s) on %s", crm_element_name(action->xml), task, id, on_node); } if(send_command) { HA_Message *cmd = NULL; char *counter = crm_itoa(transition_counter); cmd = create_request(msg_task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); ha_msg_add(cmd, "transition_id", crm_str(counter)); #ifndef TESTING ret = send_ipc_message(crm_ch, cmd); #else ret = TRUE; crm_log_message(LOG_INFO, cmd); #endif crm_free(counter); if(ret && action->timeout > 0) { crm_devel("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } return ret; } gboolean cib_action_update(action_t *action, int status) { char *code = NULL; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_inhibit_notify|cib_quorum_override; if(status == LRM_OP_TIMEOUT) { if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(action->xml), task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(action->xml), task, target); } #ifdef TESTING /* turn the "pending" notification into a "op completed" notification * when testing... exercises more code this way. */ } else if(status == LRM_OP_PENDING) { status = LRM_OP_DONE; #endif } code = crm_itoa(status); /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); set_xml_property_copy(state, XML_ATTR_UUID, target_uuid); set_xml_property_copy(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP); set_xml_property_copy(rsc, XML_ATTR_ID, rsc_id); set_xml_property_copy(xml_op, XML_ATTR_ID, task); if(action->interval > 0) { char *op_id = generate_op_key(rsc_id, task, action->interval); set_xml_property_copy(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); } set_xml_property_copy(xml_op, XML_LRM_ATTR_TASK, task); set_xml_property_copy(rsc, XML_LRM_ATTR_RSCSTATE, get_rsc_state(task, status)); set_xml_property_copy(rsc, XML_LRM_ATTR_OPSTATUS, code); set_xml_property_copy(rsc, XML_LRM_ATTR_RC, code); set_xml_property_copy(rsc, XML_LRM_ATTR_LASTOP, task); set_xml_property_copy(xml_op, XML_LRM_ATTR_OPSTATUS, code); set_xml_property_copy(xml_op, XML_LRM_ATTR_RC, code); set_xml_property_copy(xml_op, "origin", __FUNCTION__); set_node_tstamp(xml_op); crm_free(code); fragment = create_cib_fragment(state, NULL); crm_devel("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); #ifndef TESTING rc = te_cib_conn->cmds->modify( te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task, rsc_id, target, rc); if(status == LRM_OP_PENDING) { crm_debug("Waiting for callback id: %d)", rc); add_cib_op_callback(rc, FALSE, action, cib_action_updated); } #else fprintf(stderr, "Initiating action %d: %s %s on %s", action->id, task, rsc_id, target); call_options = 0; { HA_Message *cmd = ha_msg_new(11); ha_msg_add(cmd, F_TYPE, T_CRM); ha_msg_add(cmd, F_CRM_VERSION, CRM_VERSION); ha_msg_add(cmd, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); ha_msg_add(cmd, F_CRM_TASK, CRM_OP_EVENTCC); ha_msg_add(cmd, F_CRM_SYS_TO, CRM_SYSTEM_TENGINE); ha_msg_add(cmd, F_CRM_SYS_FROM, CRM_SYSTEM_TENGINE); ha_msg_addstruct(cmd, crm_element_name(state), state); send_ipc_message(crm_ch, cmd); } #endif free_xml(fragment); free_xml(state); if(rc < cib_ok) { return FALSE; } return TRUE; } void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; const char *task = NULL; const char *rsc_id = NULL; const char *on_node = NULL; action_t *action = user_data; char *counter = crm_itoa(transition_counter); CRM_DEV_ASSERT(action != NULL); if(crm_assert_failed) { return; } CRM_DEV_ASSERT(action->xml != NULL); if(crm_assert_failed) { return; } rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); rsc_id = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); if(rc < cib_ok) { crm_err("Update for action %d: %s %s on %s FAILED", action->id, task, rsc_id, on_node); send_complete(cib_error2string(rc), output, te_failed); return; } crm_info("Initiating action %d: %s %s on %s", action->id, task, rsc_id, on_node); if(rsc_op != NULL) { crm_xml_debug(rsc_op, "Performing"); } cmd = create_request( task, rsc_op, on_node, CRM_SYSTEM_LRMD,CRM_SYSTEM_TENGINE,NULL); ha_msg_add(cmd, "transition_id", counter); crm_free(counter); #ifndef TESTING send_ipc_message(crm_ch, cmd); #else crm_log_message(LOG_INFO, cmd); #endif if(action->timeout > 0) { crm_devel("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } gboolean initiate_transition(void) { crm_info("Initating transition"); process_graph_event(NULL, NULL); return TRUE; } void check_synapse_triggers(synapse_t *synapse, int action_id) { synapse->triggers_complete = TRUE; if(synapse->confirmed) { crm_devel("Skipping confirmed synapse %d", synapse->id); return; } else if(synapse->complete == FALSE) { crm_devel("Checking pre-reqs for %d", synapse->id); /* lookup prereqs */ slist_iter( prereq, action_t, synapse->inputs, lpc, crm_devel("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_devel("Marking input %d complete", action_id); prereq->complete = TRUE; } else if(prereq->complete == FALSE) { crm_devel("Inputs for synapse %d not satisfied", synapse->id); synapse->triggers_complete = FALSE; } ); } } void fire_synapse(synapse_t *synapse) { if(synapse == NULL) { crm_err("Synapse was NULL!"); return; } crm_devel("Checking if synapse %d needs to be fired", synapse->id); if(synapse->complete) { crm_devel("Skipping complete synapse %d", synapse->id); return; } else if(synapse->triggers_complete == FALSE) { crm_devel("Synapse %d not yet satisfied", synapse->id); return; } crm_debug("All inputs for synapse %d satisfied... invoking actions", synapse->id); synapse->complete = TRUE; slist_iter( action, action_t, synapse->actions, lpc, /* allow some leway */ unsigned tmp_time = 2 * action->timeout; gboolean passed = FALSE; action->invoked = TRUE; /* Invoke the action and start the timer */ passed = initiate_action(action); if(passed == FALSE) { crm_err("Failed initiating <%s id=%d> in synapse %d", crm_element_name(action->xml), action->id, synapse->id); send_complete( "Action init failed", action->xml, te_failed); return; } if(tmp_time > next_transition_timeout) { next_transition_timeout = tmp_time; } ); crm_debug("Synapse %d complete", synapse->id); } gboolean confirm_synapse(synapse_t *synapse, int action_id) { gboolean complete = TRUE; synapse->confirmed = TRUE; slist_iter( action, action_t, synapse->actions, lpc, if(action->complete == FALSE) { complete = FALSE; synapse->confirmed = FALSE; crm_devel("Found an incomplete action" " - transition not complete"); break; } ); if(complete) { crm_debug("Synapse %d complete (action=%d)", synapse->id, action_id); } return complete; } void process_trigger(int action_id) { graph_complete = TRUE; crm_devel("Processing trigger from action %d", action_id); /* something happened, stop the timer and start it again at the end */ stop_te_timer(transition_timer); slist_iter( synapse, synapse_t, graph, lpc, if(synapse->confirmed) { crm_devel("Skipping confirmed synapse %d", synapse->id); continue; } check_synapse_triggers(synapse, action_id); fire_synapse(synapse); if(graph == NULL) { crm_err("Trigger processing aborted after failed synapse"); break; } crm_devel("Checking if %d is confirmed", synapse->id); if(synapse->complete == FALSE) { crm_devel("Found an incomplete synapse" " - transition not complete"); /* indicate that the transition is not yet complete */ graph_complete = FALSE; } else if(synapse->confirmed == FALSE) { gboolean confirmed = confirm_synapse(synapse,action_id); graph_complete = graph_complete && confirmed; } crm_devel("%d is %s", synapse->id, synapse->confirmed?"confirmed":synapse->complete?"complete":"pending"); ); } diff --git a/crm/tengine/unpack.c b/crm/tengine/unpack.c index 310d0e2145..9c3dadcfdc 100644 --- a/crm/tengine/unpack.c +++ b/crm/tengine/unpack.c @@ -1,394 +1,394 @@ -/* $Id: unpack.c,v 1.29 2005/04/25 13:01:44 andrew Exp $ */ +/* $Id: unpack.c,v 1.30 2005/05/15 13:13:41 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include cib_t *te_cib_conn = NULL; action_t* unpack_action(crm_data_t *xml_action); crm_data_t *create_shutdown_event(const char *node, int op_status); void set_timer_value(te_timer_t *timer, const char *time, int time_default); extern int transition_counter; void set_timer_value(te_timer_t *timer, const char *time, int time_default) { int tmp_time; if(timer == NULL) { return; } timer->timeout = time_default; tmp_time = crm_get_msec(time); if(tmp_time > 0) { timer->timeout = tmp_time; } } gboolean unpack_graph(crm_data_t *xml_graph) { /* timeout = crm_get_msec(time); transition_timeout = transition_timer->timeout; time = crm_element_value(xml_graph, "transition_fuzz"); set_timer_value(transition_fuzz_timer, time, transition_fuzz_timeout); transition_counter = crm_atoi(t_id, "-1"); crm_info("Beginning transition %d : timeout set to %dms", transition_counter, transition_timer->timeout); xml_child_iter( xml_graph, synapse, "synapse", synapse_t *new_synapse = NULL; crm_devel("looking in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); crm_malloc0(new_synapse, sizeof(synapse_t)); new_synapse->id = num_synapses++; new_synapse->complete = FALSE; new_synapse->confirmed = FALSE; new_synapse->actions = NULL; new_synapse->inputs = NULL; graph = g_list_append(graph, new_synapse); crm_devel("look for actions in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); xml_child_iter( synapse, actions, "action_set", xml_child_iter( actions, action, NULL, action_t *new_action = unpack_action(action); num_actions++; if(new_action == NULL) { continue; } crm_devel("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_devel("look for inputs in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); xml_child_iter( synapse, inputs, "inputs", xml_child_iter( inputs, trigger, NULL, xml_child_iter( trigger, input, NULL, action_t *new_input = unpack_action(input); if(new_input == NULL) { continue; } crm_devel("Adding input %d to synapse %d", new_input->id, new_synapse->id); new_synapse->inputs = g_list_append( new_synapse->inputs, new_input); ); ); ); ); crm_info("Unpacked %d actions in %d synapses", num_actions, num_synapses); if(num_actions > 0) { return TRUE; } else { /* indicate to caller that there's nothing to do */ return FALSE; } } action_t* unpack_action(crm_data_t *xml_action) { const char *tmp = crm_element_value(xml_action, XML_ATTR_ID); action_t *action = NULL; crm_data_t *action_copy = NULL; crm_data_t *nvpair_list = NULL; if(tmp == NULL) { crm_err("Actions must have an id!"); crm_xml_devel(xml_action, "Action with missing id"); return NULL; } action_copy = copy_xml_node_recursive(xml_action); crm_malloc0(action, sizeof(action_t)); if(action == NULL) { return NULL; } action->id = atoi(tmp); action->timeout = 0; action->interval = 0; action->timer = NULL; action->invoked = FALSE; action->complete = FALSE; action->can_fail = FALSE; action->type = action_type_rsc; action->xml = action_copy; if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_RSC_OP)) { action->type = action_type_rsc; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_PSEUDO_EVENT)) { action->type = action_type_pseudo; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_CRM_EVENT)) { action->type = action_type_crm; } nvpair_list = find_xml_node(action_copy, XML_TAG_ATTRS, FALSE); if(nvpair_list == NULL) { crm_verbose("No attributes in %s", crm_element_name(action_copy)); } xml_child_iter( nvpair_list, node_iter, XML_CIB_TAG_NVPAIR, const char *key = crm_element_value( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value( node_iter, XML_NVPAIR_ATTR_VALUE); if(safe_str_eq(key, "timeout")) { action->timeout = crm_get_msec(value); } else if(safe_str_eq(key, "interval")) { action->interval = crm_get_msec(value); } ); crm_devel("Action %d has timer set to %dms", action->id, action->timeout); crm_malloc0(action->timer, sizeof(te_timer_t)); action->timer->timeout = 2 * action->timeout; action->timer->source_id = -1; action->timer->reason = timeout_action; action->timer->action = action; tmp = crm_element_value(action_copy, "can_fail"); crm_str_to_boolean(tmp, &(action->can_fail)); return action; } gboolean extract_event(crm_data_t *msg) { gboolean abort = FALSE; const char *event_node = NULL; /* [cib fragment] ... */ crm_trace("Extracting event from %s", crm_element_name(msg)); xml_child_iter( msg, node_state, XML_CIB_TAG_STATE, crm_data_t *resources = NULL; const char *ccm_state = crm_element_value( node_state, XML_CIB_ATTR_INCCM); const char *crmd_state = crm_element_value( node_state, XML_CIB_ATTR_CRMDSTATE); const char *join_state = crm_element_value( node_state, XML_CIB_ATTR_JOINSTATE); event_node = crm_element_value(node_state, XML_ATTR_UNAME); crm_xml_devel(node_state,"Processing"); if(crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN) != NULL) { send_complete( "Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute", node_state, te_update); break; - } else if(crm_element_value(node_state, XML_CIB_ATTR_STONITH) != NULL) { + } else if(crm_element_value(node_state, CRM_OP_FENCE) != NULL) { /* node marked for STONITH * possibly by us when a shutdown timmed out */ int action_id = -1; crm_devel("Checking for STONITH"); event_node = crm_element_value(node_state, XML_ATTR_UNAME); action_id = match_down_event( event_node, CRM_OP_SHUTDOWN, LRM_OP_DONE); if(action_id < 0) { send_complete( "Stonith/shutdown event not matched", node_state, te_update); break; } else { process_trigger(action_id); check_for_completion(); } continue; } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); if(crmd_state != NULL || ccm_state != NULL || join_state != NULL) { /* simple node state update... * possibly from a shutdown we requested */ crm_devel("Processing state update"); if(crmd_state != NULL && safe_str_neq(crmd_state, OFFLINESTATUS)) { /* the node is comming up, * only recompute after the join completes, * we dont need to check for this */ continue; } else if(join_state != NULL && safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)) { /* the node is comming up, * only recompute after the join completes, * we dont need to check for this */ continue; } else { /* this may be called more than once per shutdown * ie. once per update of each field */ int action_id = -1; crm_devel("Checking if this was a known shutdown"); action_id = match_down_event( event_node, NULL, LRM_OP_DONE); if(action_id < 0) { send_complete("Stonith/shutdown event not matched", node_state, te_update); break; } else { process_trigger(action_id); check_for_completion(); } } if(ccm_state != NULL && crm_is_true(ccm_state)) { crm_devel("Ignore - new CCM node"); } } if(resources != NULL) { /* LRM resource update... */ xml_child_iter( resources, child, NULL, crm_xml_devel(child, "Processing LRM resource update"); abort = !process_graph_event(child, event_node); if(abort) { break; } ); if(abort) { break; } } ); return !abort; } crm_data_t* create_shutdown_event(const char *node, int op_status) { crm_data_t *event = create_xml_node(NULL, XML_CIB_TAG_STATE); char *code = crm_itoa(op_status); set_xml_property_copy(event, XML_LRM_ATTR_TARGET, node); /* event_rsc = set_xml_property_copy(event, XML_ATTR_ID); */ set_xml_property_copy(event, XML_LRM_ATTR_RC, "0"); set_xml_property_copy( event, XML_LRM_ATTR_LASTOP, XML_CIB_ATTR_SHUTDOWN); set_xml_property_copy( - event, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_GENERIC_OK); + event, XML_LRM_ATTR_RSCSTATE, CRMD_ACTION_GENERIC_OK); set_xml_property_copy(event, XML_LRM_ATTR_OPSTATUS, code); crm_free(code); return event; } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index f040f3f452..108b587ae9 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,385 +1,385 @@ -/* $Id: utils.c,v 1.27 2005/05/10 13:20:32 andrew Exp $ */ +/* $Id: utils.c,v 1.28 2005/05/15 13:13:40 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include extern cib_t *te_cib_conn; extern int global_transition_timer; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); gboolean timer_callback(gpointer data); void send_complete(const char *text, crm_data_t *msg, te_reason_t reason) { HA_Message *cmd = NULL; const char *op = CRM_OP_TEABORT; /* the transition is over... ignore all future callbacks * resulting from our CIB updates (usually for pending operations) */ remove_cib_op_callback(-1, TRUE); if(reason == te_done && in_transition == FALSE) { crm_warn("Not in transition, not sending message"); return; } else if(reason == te_timeout && in_transition == FALSE) { crm_err("Not in transition, not sending message"); return; } switch(reason) { case te_update: crm_debug("Transition status: %s by CIB update: %s", in_transition?"Aborted":"Triggered", text); if(msg != NULL) { if(safe_str_eq(crm_element_name(msg), XML_TAG_CIB)) { crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg); crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB); crm_debug("Cause:" " full CIB replace/update"); copy_in_properties(generation, msg); crm_xml_debug(generation, "[generation]"); crm_xml_debug(status, "[in ]"); free_xml(generation); } else { crm_xml_debug(msg, "Cause"); } } print_state(LOG_DEBUG); break; case te_halt: crm_info("Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_abort: crm_info("Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); break; case te_done: crm_info("Transition status: Complete%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_timeout: crm_err("Transition status: Timed out after %dms", transition_timer->timeout); print_state(LOG_WARNING); op = CRM_OP_TETIMEOUT; break; case te_failed: crm_err("Transition status: Aborted by failed action: %s", text); crm_xml_debug(msg, "Cause"); print_state(LOG_WARNING); break; } in_transition = FALSE; initialize_graph(); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(text != NULL) { ha_msg_add(cmd, "message", text); } #ifdef TESTING if(reason == te_done) { crm_log_message(LOG_INFO, cmd); } else { crm_log_message(LOG_ERR, cmd); } g_main_quit(mainloop); return; #else send_ipc_message(crm_ch, cmd); #endif } void print_state(int log_level) { if(graph == NULL && log_level > LOG_DEBUG) { do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "\tEmpty transition graph"); do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); return; } do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); slist_iter( synapse, synapse_t, graph, lpc, do_crm_log(log_level, __FILE__, __FUNCTION__, "Synapse %d %s", synapse->id, synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending"); if(synapse->confirmed == FALSE) { slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, log_level); ); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, log_level); ); } ); do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); } void print_input(const char *prefix, action_t *input, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)", prefix, input->id, input->complete?"Satisfied":"Pending", actiontype2text(input->type)); if(input->complete == FALSE) { crm_log_xml((unsigned)log_level, "\t Raw input", input->xml); } } void print_action(const char *prefix, action_t *action, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->can_fail?"can":"cannot"); switch(action->type) { case action_type_pseudo: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tResource Op: %s/%s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_RSCID), crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; case action_type_crm: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tCRM Op: %s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; } if(action->timeout > 0 || action->timer->source_id > 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); } if(action->complete == FALSE) { crm_log_xml(LOG_VERBOSE, "\tRaw action", action->xml); } } gboolean timer_callback(gpointer data) { te_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (te_timer_t*)data; if(timer->source_id > 0) { g_source_remove(timer->source_id); } timer->source_id = -1; if(timer->reason == timeout_fuzz) { crm_warn("Transition timeout reached..." " marking transition complete."); send_complete("success", NULL, te_done); return TRUE; } else if(timer->reason == timeout_timeout) { /* global timeout - abort the transition */ crm_warn("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } else if(timer->reason == timeout_action_warn) { crm_warn("Action %d is taking more than 2x its timeout (%d)", timer->action->id, timer->action->timeout); crm_xml_debug(timer->action->xml, "Slow action"); return TRUE; } else { /* fail the action * - which may or may not abort the transition */ /* TODO: send a cancel notice to the LRM */ /* TODO: use the ack from above to update the CIB */ return cib_action_update(timer->action, LRM_OP_TIMEOUT); } } gboolean start_te_timer(te_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->timeout > 0) { timer->source_id = Gmain_timeout_add( timer->timeout, timer_callback, (void*)timer); return TRUE; } else if(timer->timeout < 0) { crm_err("Tried to start timer with -ve period"); } else { crm_devel("#!!#!!# Timer already running (%d)", timer->source_id); } return FALSE; } gboolean stop_te_timer(te_timer_t *timer) { if(timer == NULL) { return FALSE; } if(((int)timer->source_id) > 0) { g_source_remove(timer->source_id); timer->source_id = -2; } else { return FALSE; } return TRUE; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } const char * get_rsc_state(const char *task, op_status_t status) { - if(safe_str_eq(CRMD_RSCSTATE_START, task)) { + if(safe_str_eq(CRMD_ACTION_START, task)) { if(status == LRM_OP_PENDING) { - return CRMD_RSCSTATE_START_PENDING; + return CRMD_ACTION_START_PENDING; } else if(status == LRM_OP_DONE) { - return CRMD_RSCSTATE_START_OK; + return CRMD_ACTION_STARTED; } else { - return CRMD_RSCSTATE_START_FAIL; + return CRMD_ACTION_START_FAIL; } - } else if(safe_str_eq(CRMD_RSCSTATE_STOP, task)) { + } else if(safe_str_eq(CRMD_ACTION_STOP, task)) { if(status == LRM_OP_PENDING) { - return CRMD_RSCSTATE_STOP_PENDING; + return CRMD_ACTION_STOP_PENDING; } else if(status == LRM_OP_DONE) { - return CRMD_RSCSTATE_STOP_OK; + return CRMD_ACTION_STOPPED; } else { - return CRMD_RSCSTATE_STOP_FAIL; + return CRMD_ACTION_STOP_FAIL; } } else { - if(safe_str_eq(CRMD_RSCSTATE_MON, task)) { + if(safe_str_eq(CRMD_ACTION_MON, task)) { if(status == LRM_OP_PENDING) { - return CRMD_RSCSTATE_MON_PENDING; + return CRMD_ACTION_MON_PENDING; } else if(status == LRM_OP_DONE) { - return CRMD_RSCSTATE_MON_OK; + return CRMD_ACTION_MON_OK; } else { - return CRMD_RSCSTATE_MON_FAIL; + return CRMD_ACTION_MON_FAIL; } } else { const char *rsc_state = NULL; if(status == LRM_OP_PENDING) { - rsc_state = CRMD_RSCSTATE_GENERIC_PENDING; + rsc_state = CRMD_ACTION_GENERIC_PENDING; } else if(status == LRM_OP_DONE) { - rsc_state = CRMD_RSCSTATE_GENERIC_OK; + rsc_state = CRMD_ACTION_GENERIC_OK; } else { - rsc_state = CRMD_RSCSTATE_GENERIC_FAIL; + rsc_state = CRMD_ACTION_GENERIC_FAIL; } crm_warn("Using status \"%s\" for op \"%s\"..." " this is still in the experimental stage.", rsc_state, task); return rsc_state; } } } diff --git a/include/crm/crm.h b/include/crm/crm.h index 307dcfc539..f5361b37f8 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,284 +1,287 @@ -/* $Id: crm.h,v 1.59 2005/05/12 11:16:40 andrew Exp $ */ +/* $Id: crm.h,v 1.60 2005/05/15 13:13:40 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRM__H #define CRM__H #include #include #include #include #include #include #ifdef MCHECK #include #endif #include #ifndef CRM_DEV_BUILD # define CRM_DEV_BUILD 0 #endif #define ipc_call_diff_max_ms 2000 #define action_diff_warn_ms 5000 #define action_diff_max_ms 15000 #define fsa_diff_warn_ms 10000 #define fsa_diff_max_ms 20000 #include #define CRM_ASSERT(expr) if((expr) == FALSE) { \ do_crm_log(LOG_CRIT, __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ abort(); \ } extern gboolean crm_assert_failed; #define CRM_DEV_ASSERT(expr) crm_assert_failed = FALSE; \ if((expr) == FALSE) { \ crm_assert_failed = TRUE; \ do_crm_log(CRM_DEV_BUILD?LOG_CRIT:LOG_ERR, \ __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ if(CRM_DEV_BUILD) { \ abort(); \ } \ } /* Clean these up at some point, some probably should be runtime options */ #define WORKING_DIR HA_VARLIBDIR"/heartbeat/crm" #define BIN_DIR HA_LIBDIR"/heartbeat" #define SOCKET_LEN 1024 #define APPNAME_LEN 256 #define LOG_DIR "/var/log" #define MAX_IPC_FAIL 5 #define CIB_FILENAME WORKING_DIR"/cib.xml" #define CIB_BACKUP WORKING_DIR"/cib_backup.xml" #define DEVEL_CIB_COPY 1 #define DEVEL_DIR "/tmp/crm" #define CRM_VERSION "0.7" #define MSG_LOG 1 #define DOT_FSA_ACTIONS 1 #define DOT_ALL_FSA_INPUTS 1 #define FSA_TRACE 1 /* #define USE_FAKE_LRM 1 */ #define INFINITY_S "INFINITY" #define MINUS_INFINITY_S "-INFINITY" #define INFINITY 1000000.0 /* Sub-systems */ #define CRM_SYSTEM_DC "dc" #define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ #define CRM_SYSTEM_CIB "cib" #define CRM_SYSTEM_CRMD "crmd" #define CRM_SYSTEM_LRMD "lrmd" #define CRM_SYSTEM_PENGINE "pengine" #define CRM_SYSTEM_TENGINE "tengine" /* Valid operations */ #define CRM_OP_NOOP "noop" /* soon to be moved to cib.h */ #define CRM_OP_CIB_SLAVE "cib_slave" #define CRM_OP_CIB_SLAVEALL "cib_slave_all" #define CRM_OP_CIB_MASTER "cib_master" #define CRM_OP_CIB_SYNC "cib_sync" #define CRM_OP_CIB_ISMASTER "cib_ismaster" #define CRM_OP_CIB_BUMP "cib_bump" #define CRM_OP_CIB_QUERY "cib_query" #define CRM_OP_CIB_CREATE "cib_create" #define CRM_OP_CIB_UPDATE "cib_update" #define CRM_OP_CIB_DELETE "cib_delete" #define CRM_OP_CIB_ERASE "cib_erase" #define CRM_OP_CIB_REPLACE "cib_replace" #define CRM_OP_CIB_NOTIFY "cib_notify" #define CRM_OP_JOIN_ANNOUNCE "join_announce" #define CRM_OP_JOIN_OFFER "join_offer" #define CRM_OP_JOIN_REQUEST "join_request" #define CRM_OP_JOIN_ACKNAK "join_ack_nack" #define CRM_OP_JOIN_CONFIRM "join_confirm" #define CRM_OP_DIE "die_no_respawn" #define CRM_OP_RETRIVE_CIB "retrieve_cib" #define CRM_OP_PING "ping" #define CRM_OP_VOTE "vote" #define CRM_OP_HELLO "hello" #define CRM_OP_HBEAT "dc_beat" #define CRM_OP_PECALC "pe_calc" #define CRM_OP_ABORT "abort" #define CRM_OP_QUIT "quit" #define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" #define CRM_OP_SHUTDOWN_REQ "req_shutdown" #define CRM_OP_SHUTDOWN "do_shutdown" +#define CRM_OP_FENCE "stonith" #define CRM_OP_EVENTCC "event_cc" #define CRM_OP_TEABORT "te_abort" #define CRM_OP_TE_HALT "te_halt" #define CRM_OP_TECOMPLETE "te_complete" #define CRM_OP_TETIMEOUT "te_timeout" #define CRM_OP_TRANSITION "transition" #define CRM_OP_REGISTER "register" #define CRM_OP_DEBUG_UP "debug_inc" #define CRM_OP_DEBUG_DOWN "debug_dec" #define CRMD_STATE_ACTIVE "member" #define CRMD_STATE_INACTIVE "down" #define CRMD_JOINSTATE_DOWN "down" #define CRMD_JOINSTATE_PENDING "pending" #define CRMD_JOINSTATE_MEMBER "member" -#define CRMD_RSCSTATE_START "start" -#define CRMD_RSCSTATE_START_PENDING "starting" -#define CRMD_RSCSTATE_START_OK "running" -#define CRMD_RSCSTATE_START_FAIL "start_failed" -#define CRMD_RSCSTATE_STOP "stop" -#define CRMD_RSCSTATE_STOP_PENDING "stopping" -#define CRMD_RSCSTATE_STOP_OK "stopped" -#define CRMD_RSCSTATE_STOP_FAIL "stop_failed" -#define CRMD_RSCSTATE_MON "monitor" -#define CRMD_RSCSTATE_MON_PENDING CRMD_RSCSTATE_START_OK -#define CRMD_RSCSTATE_MON_OK CRMD_RSCSTATE_START_OK -#define CRMD_RSCSTATE_MON_FAIL "monitor_failed" -/* #define CRMD_RSCSTATE_GENERIC "pending" */ -#define CRMD_RSCSTATE_GENERIC_PENDING "pending" -#define CRMD_RSCSTATE_GENERIC_OK "complete" -#define CRMD_RSCSTATE_GENERIC_FAIL "pending_failed" +#define CRMD_ACTION_START "start" +#define CRMD_ACTION_STARTED "running" +#define CRMD_ACTION_START_FAIL "start_failed" +#define CRMD_ACTION_START_PENDING "starting" + +#define CRMD_ACTION_STOP "stop" +#define CRMD_ACTION_STOPPED "stopped" +#define CRMD_ACTION_STOP_FAIL "stop_failed" +#define CRMD_ACTION_STOP_PENDING "stopping" + +#define CRMD_ACTION_MON "monitor" +#define CRMD_ACTION_MON_PENDING CRMD_ACTION_STARTED +#define CRMD_ACTION_MON_OK CRMD_ACTION_STARTED +#define CRMD_ACTION_MON_FAIL "monitor_failed" +/* #define CRMD_ACTION_GENERIC "pending" */ +#define CRMD_ACTION_GENERIC_PENDING "pending" +#define CRMD_ACTION_GENERIC_OK "complete" +#define CRMD_ACTION_GENERIC_FAIL "pending_failed" typedef GList* GListPtr; #define crm_atoi(text, default) atoi(text?text:default) extern gboolean safe_str_eq(const char *a, const char *b); extern gboolean safe_str_neq(const char *a, const char *b); #define slist_iter(child, child_type, parent, counter, a) \ { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ int counter = 0; \ for(; __crm_iter_head != NULL; counter++) { \ child = __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ } #define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def) /* Developmental debug stuff */ #define LOG_VERBOSE LOG_DEBUG+1 #define LOG_DEV LOG_DEBUG+2 #define LOG_TRACE LOG_DEBUG+3 #define LOG_INSANE LOG_DEBUG+5 #define LOG_MSG LOG_DEV # define crm_crit(w...) do_crm_log(LOG_CRIT, __FILE__, __FUNCTION__, w) # define crm_err(w...) do_crm_log(LOG_ERR, __FILE__, __FUNCTION__, w) # define crm_warn(w...) do_crm_log(LOG_WARNING, __FILE__, __FUNCTION__, w) # define crm_notice(w...) do_crm_log(LOG_NOTICE, __FILE__, __FUNCTION__, w) # define crm_info(w...) do_crm_log(LOG_INFO, __FILE__, __FUNCTION__, w) #if 1 # define crm_debug(w...) do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, w) # define crm_devel(w...) do_crm_log(LOG_DEV, __FILE__, __FUNCTION__, w) # define crm_verbose(w...) do_crm_log(LOG_VERBOSE, __FILE__, __FUNCTION__, w) # define crm_trace(w...) do_crm_log(LOG_TRACE, __FILE__, __FUNCTION__, w) # define crm_insane(w...) do_crm_log(LOG_INSANE, __FILE__, __FUNCTION__, w) #else # define crm_debug(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_devel(w...) if(0) { do_crm_log(LOG_DEV, NULL, NULL, w); } # define crm_verbose(w...) if(0) { do_crm_log(LOG_VERBOSE, NULL, NULL, w); } # define crm_trace(w...) if(0) { do_crm_log(LOG_TRACE, NULL, NULL, w); } # define crm_insane(w...) if(0) { do_crm_log(LOG_INSANE, NULL, NULL, w); } #endif extern void crm_log_message_adv(int level, const char *alt_debugfile, const HA_Message *msg); #define crm_log_message(level, msg) crm_log_message_adv(level, NULL, msg) #define crm_do_action(level, actions) if(crm_log_level >= level) { \ actions; \ } #define crm_info_action(x) crm_do_action(LOG_INFO, x) #define crm_debug_action(x) crm_do_action(LOG_DEBUG, x) #define crm_verbose_action(x) crm_do_action(LOG_VERBOSE, x) #define crm_devel_action(x) crm_do_action(LOG_DEV, x) #define crm_log_xml(level, text, xml) if(crm_log_level >= level) { \ print_xml_formatted(level, __FUNCTION__, xml, text); \ } #define crm_xml_crit(xml, text) crm_log_xml(LOG_CRIT, text, xml) #define crm_xml_err(xml, text) crm_log_xml(LOG_ERR, text, xml) #define crm_xml_warn(xml, text) crm_log_xml(LOG_WARNING, text, xml) #define crm_xml_notice(xml, text) crm_log_xml(LOG_NOTICE, text, xml) #define crm_xml_info(xml, text) crm_log_xml(LOG_INFO, text, xml) #define crm_xml_debug(xml, text) crm_log_xml(LOG_DEBUG, text, xml) #define crm_xml_devel(xml, text) crm_log_xml(LOG_DEV, text, xml) #define crm_xml_verbose(xml, text) crm_log_xml(LOG_VERBOSE, text, xml) #define crm_xml_trace(xml, text) crm_log_xml(LOG_TRACE, text, xml) #define crm_xml_insane(xml, text) crm_log_xml(LOG_INSANE, text, xml) #define crm_malloc0(new_obj,length) \ { \ if(new_obj) { \ crm_err("Potential memory leak:" \ " %s at %s:%d not NULL before alloc.", \ #new_obj, __FILE__, __LINE__); \ if(CRM_DEV_BUILD) { abort(); } \ } \ new_obj = cl_malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ exit(1); \ } else { \ memset(new_obj, 0, length); \ } \ } /* for temporary backwards compatibility */ #define crm_malloc(new_obj,length) crm_malloc0(new_obj,length) #if 1 # define crm_free(x) if(x) { \ CRM_ASSERT(cl_is_allocated(x) == 1); \ cl_free(x); \ x=NULL; \ } #else # define crm_free(x) x=NULL #endif #define crm_str(x) (const char*)(x?x:"") #if 1 # define crm_msg_del(msg) if(msg != NULL) { ha_msg_del(msg); msg = NULL; } #else # define crm_msg_del(msg) msg = NULL #endif #endif