diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index 0ef23fd135..d07ed57047 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,1129 +1,1194 @@ /* * 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 /* for access */ #include #include #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_ACTION_START; case crmd_rscstate_START_PENDING: return CRMD_ACTION_START_PENDING; case crmd_rscstate_START_OK: return CRMD_ACTION_STARTED; case crmd_rscstate_START_FAIL: return CRMD_ACTION_START_FAIL; case crmd_rscstate_STOP: return CRMD_ACTION_STOP; case crmd_rscstate_STOP_PENDING: return CRMD_ACTION_STOP_PENDING; case crmd_rscstate_STOP_OK: return CRMD_ACTION_STOPPED; case crmd_rscstate_STOP_FAIL: return CRMD_ACTION_STOP_FAIL; case crmd_rscstate_MON: return CRMD_ACTION_MON; case crmd_rscstate_MON_PENDING: return CRMD_ACTION_MON_PENDING; case crmd_rscstate_MON_OK: return CRMD_ACTION_MON_OK; case crmd_rscstate_MON_FAIL: return CRMD_ACTION_MON_FAIL; case crmd_rscstate_GENERIC_PENDING: return CRMD_ACTION_GENERIC_PENDING; case crmd_rscstate_GENERIC_OK: return CRMD_ACTION_GENERIC_OK; case 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_debug_4("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_debug_4("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_debug_4("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, const char *last_op = g_hash_table_lookup(resources, rsc_id); if(safe_str_neq(last_op, CRMD_ACTION_STOP)) { crm_warn("Resource %s was active at shutdown", rsc_id); 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; const char *state = NULL; crm_data_t *xml_op = NULL; char *op_id = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return FALSE; } crm_debug("%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(safe_str_eq(op->op_type, CRMD_ACTION_NOTIFY)) { + const char *n_type = g_hash_table_lookup( + op->params, "notify_type"); + const char *n_task = g_hash_table_lookup( + op->params, "notify_operation"); + CRM_DEV_ASSERT(n_type != NULL); + CRM_DEV_ASSERT(n_task != NULL); + op_id = generate_notify_key(op->rsc_id, n_type, n_task); + + /* these are not yet allowed to fail */ + op->op_status = LRM_OP_DONE; + op->rc = 0; + + } else { + op_id = generate_op_key(op->rsc_id, op->op_type, op->interval); + } - op_id = generate_op_key(op->rsc_id, op->op_type, op->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_rsc, XML_LRM_ATTR_LASTOP, op->op_type); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, op->op_type); crm_xml_add(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; } } if(op->user_data == NULL) { op->user_data = generate_transition_key(-1, fsa_our_uname); } fail_state = generate_transition_magic(op->user_data, op->op_status); - crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data); - crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, fail_state); + crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data); + crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, fail_state); crm_free(fail_state); 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); } crm_xml_add(xml_op, XML_LRM_ATTR_RSCSTATE, fail_state); crm_xml_add(xml_rsc, XML_LRM_ATTR_RSCSTATE, fail_state); crm_free(fail_state); break; case LRM_OP_DONE: if(safe_str_eq(CRMD_ACTION_START, op->op_type)) { state = CRMD_ACTION_STARTED; } else if(safe_str_eq(CRMD_ACTION_STOP, op->op_type)) { state = CRMD_ACTION_STOPPED; } else if(safe_str_eq(CRMD_ACTION_MON, op->op_type)) { state = CRMD_ACTION_STARTED; } else { crm_warn("Using status \"%s\" for op \"%s\"" "... this is still in the experimental stage.", CRMD_ACTION_GENERIC_OK, op->op_type); state = CRMD_ACTION_GENERIC_OK; } crm_xml_add(xml_op, XML_LRM_ATTR_RSCSTATE, state); crm_xml_add(xml_rsc, XML_LRM_ATTR_RSCSTATE, state); break; } tmp = crm_itoa(op->call_id); crm_xml_add(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); crm_xml_add(xml_op, XML_LRM_ATTR_RC, tmp); crm_xml_add(xml_rsc, XML_LRM_ATTR_RC, tmp); crm_free(tmp); tmp = crm_itoa(op->op_status); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, tmp); crm_xml_add(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_debug("Processing lrm_rsc_t entry %s", rid); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); continue; } crm_xml_add(xml_rsc, XML_ATTR_ID, the_rsc->id); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_debug_2("\tcurrent state:%s", cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, crm_debug_2("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); } max_call_id = 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 = NULL; crm_data_t *xml_data = NULL; crm_data_t *rsc_list = NULL; xml_state = create_node_state( fsa_our_uname, fsa_our_uname, ACTIVESTATUS, XML_BOOLEAN_TRUE, ONLINESTATUS, CRMD_JOINSTATE_MEMBER, CRMD_JOINSTATE_MEMBER, __FUNCTION__); xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); 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) { crm_xml_add(xml_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); } xml_result = create_cib_fragment(xml_state, NULL); crm_log_xml_debug_3(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_DEV_ASSERT(id_from_cib != NULL); + if(crm_assert_failed) { crm_err("No value for %s in message at level %d.", XML_ATTR_ID, DIMOF(rsc_path) -2); crm_log_xml_err(input->xml, "Bad command"); 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; const char *transition = 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(msg != NULL) { transition = crm_element_value(msg, XML_ATTR_TRANSITION_KEY); if(transition == NULL) { crm_err("Missing transition"); crm_log_message(LOG_ERR, msg); } } 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_err("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_debug_2("adding rsc %s before operation", rid); if(msg != NULL) { params = xml2list(msg); } else { 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_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; op->user_data_len = 0; if(transition != NULL) { op->user_data = crm_strdup(transition); op->user_data_len = 1+strlen(op->user_data); } else { CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); } if(params == NULL) { if(msg != NULL) { params = xml2list(msg); } else { CRM_DEV_ASSERT(safe_str_eq( 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_ACTION_MON)) { op->target_rc = CHANGED; } else { op->target_rc = EVERYTIME; } if(safe_str_eq(CRMD_ACTION_MON, operation)) { const char *last_op = g_hash_table_lookup(resources, rsc->id); if(safe_str_eq(last_op, CRMD_ACTION_STOP)) { crm_warn("Attempting to schedule %s after a stop.", op_id); free_lrm_op(op); crm_free(op_id); return I_NULL; } } g_hash_table_replace( resources, crm_strdup(rsc->id), crm_strdup(operation)); 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->output); + crm_free(op->rsc_id); crm_free(op->op_type); crm_free(op->app_name); crm_free(op); } -GHashTable * -xml2list(crm_data_t *parent) +static void dup_attr(gpointer key, gpointer value, gpointer user_data) { - crm_data_t *nvpair_list = NULL; - GHashTable *nvpair_hash = g_hash_table_new_full( + g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); +} + +lrm_op_t * +copy_lrm_op(const lrm_op_t *op) +{ + lrm_op_t *op_copy = NULL; + + CRM_DEV_ASSERT(op != NULL); + if(crm_assert_failed) { + return NULL; + } + CRM_ASSERT(op->rsc_id != NULL); + + crm_malloc0(op_copy, sizeof(lrm_op_t)); + + op_copy->op_type = crm_strdup(op->op_type); + /* input fields */ + op_copy->params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); + + if(op->params != NULL) { + g_hash_table_foreach(op->params, dup_attr, op_copy->params); + } + op_copy->timeout = op->timeout; + op_copy->interval = op->interval; + op_copy->target_rc = op->target_rc; - 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_log_xml_debug_2(parent,"No attributes for resource op"); - } + /* in the CRM, this is always a string */ + if(op->user_data != NULL) { + op_copy->user_data = crm_strdup(op->user_data); } - 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_debug_2("Added %s=%s", key, value); - - g_hash_table_insert( - nvpair_hash, crm_strdup(key), crm_strdup(value)); - ); + /* output fields */ + op_copy->op_status = op->op_status; + op_copy->rc = op->rc; + op_copy->call_id = op->call_id; + op_copy->output = NULL; + op_copy->rsc_id = crm_strdup(op->rsc_id); + if(op->app_name != NULL) { + op_copy->app_name = crm_strdup(op->app_name); + } + if(op->output != NULL) { + op_copy->output = crm_strdup(op->output); + } - return nvpair_hash; + return op_copy; } +lrm_rsc_t * +copy_lrm_rsc(const lrm_rsc_t *rsc) +{ + lrm_rsc_t *rsc_copy = NULL; + + if(rsc == NULL) { + return NULL; + } + + crm_malloc0(rsc_copy, sizeof(lrm_rsc_t)); + + rsc_copy->id = crm_strdup(rsc->id); + rsc_copy->type = crm_strdup(rsc->type); + rsc_copy->class = NULL; + rsc_copy->provider = NULL; + + if(rsc->class != NULL) { + rsc_copy->class = crm_strdup(rsc->class); + } + if(rsc->provider != NULL) { + rsc_copy->provider = crm_strdup(rsc->provider); + } +/* GHashTable* params; */ + rsc_copy->params = NULL; + rsc_copy->ops = NULL; + + return rsc_copy; +} + 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); crm_xml_add(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); crm_xml_add(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_debug_3("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_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("Op %d (%s %s) confirmed", op->call_id, op->op_type, op->rsc_id); } else if(op->interval == 0) { crm_err("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_debug("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/crmd/messages.c b/crm/crmd/messages.c index 6f1d6a2eed..bb7be7bdd9 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,1237 +1,1234 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include GListPtr fsa_message_queue = NULL; extern void crm_shutdown(int nsig); enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg); enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg); enum crmd_fsa_input handle_shutdown_request(HA_Message *stored_msg); ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig); gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data); #ifdef MSG_LOG # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x); \ crm_log_message_adv(LOG_MSG, "router.log", relay_message); #else # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x) #endif /* debug only, can wrap all it likes */ int last_data_id = 0; void register_fsa_error_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, fsa_data_t *cur_data, void *new_data, const char *raised_from) { /* save the current actions if any */ if(fsa_actions != A_NOTHING) { register_fsa_input_adv( cur_data?cur_data->fsa_cause:C_FSA_INTERNAL, I_NULL, cur_data?cur_data->data:NULL, fsa_actions, TRUE, __FUNCTION__); } /* reset the action list */ fsa_actions = A_NOTHING; /* register the error */ register_fsa_input_adv( cause, input, new_data, A_NOTHING, TRUE, raised_from); } static gboolean last_was_vote = FALSE; void register_fsa_input_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, void *data, long long with_actions, gboolean prepend, const char *raised_from) { unsigned old_len = g_list_length(fsa_message_queue); fsa_data_t *fsa_data = NULL; last_data_id++; crm_debug_2("%s raised FSA input %d (%s) (cause=%s) %s data", raised_from, last_data_id, fsa_input2string(input), fsa_cause2string(cause), data?"with":"without"); if(input == I_WAIT_FOR_EVENT) { do_fsa_stall = TRUE; crm_debug("Stalling the FSA pending further input"); if(old_len > 0) { crm_warn("%s stalled the FSA with pending inputs", raised_from); fsa_dump_queue(LOG_DEBUG); } if(data == NULL) { set_bit_inplace(fsa_actions, with_actions); with_actions = A_NOTHING; return; } crm_err("%s stalled the FSA with data - this may be broken", raised_from); } if(old_len == 0) { last_was_vote = FALSE; } if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){ /* no point doing anything */ crm_err("Cannot add entry to queue: no input and no action"); return; } else if(data == NULL) { last_was_vote = FALSE; } else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) { const char *op = cl_get_string( ((ha_msg_input_t*)data)->msg, F_CRM_TASK); if(safe_str_eq(op, CRM_OP_VOTE)) { /* It is always safe to treat N successive votes as * a single one * * If all the discarded votes are more "loosing" than * the first then the result is accurate * (win or loose). * * If any of the discarded votes are less "loosing" * than the first then we will cast our vote and the * eventual winner will vote us down again (which * even in the case that N=2, is no worse than if we * had not disarded the vote). */ crm_debug_2("Vote compression: %d", old_len); return; } } else if (cause == C_HA_MESSAGE && input == I_ROUTER) { const char *op = cl_get_string( ((ha_msg_input_t*)data)->msg, F_CRM_TASK); if(safe_str_eq(op, CRM_OP_VOTE)) { last_was_vote = TRUE; crm_debug_3("Added vote: %d", old_len); } } else { last_was_vote = FALSE; } crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->id = last_data_id; fsa_data->fsa_input = input; fsa_data->fsa_cause = cause; fsa_data->origin = raised_from; fsa_data->data = NULL; fsa_data->data_type = fsa_dt_none; fsa_data->actions = with_actions; if(with_actions != A_NOTHING) { crm_debug_3("Adding actions %.16llx to input", with_actions); } if(data != NULL) { switch(cause) { case C_FSA_INTERNAL: case C_CRMD_STATUS_CALLBACK: case C_IPC_MESSAGE: case C_HA_MESSAGE: crm_debug_3("Copying %s data from %s as a HA msg", fsa_cause2string(cause), raised_from); fsa_data->data = copy_ha_msg_input(data); fsa_data->data_type = fsa_dt_ha_msg; break; case C_LRM_OP_CALLBACK: crm_debug_3("Copying %s data from %s as lrm_op_t", fsa_cause2string(cause), raised_from); fsa_data->data = copy_lrm_op((lrm_op_t*)data); fsa_data->data_type = fsa_dt_lrm; break; case C_CCM_CALLBACK: crm_debug_3("Copying %s data from %s as CCM data", fsa_cause2string(cause), raised_from); fsa_data->data = copy_ccm_data(data); fsa_data->data_type = fsa_dt_ccm; break; case C_SUBSYSTEM_CONNECT: case C_LRM_MONITOR_CALLBACK: case C_TIMER_POPPED: case C_SHUTDOWN: case C_HEARTBEAT_FAILED: case C_HA_DISCONNECT: case C_ILLEGAL: case C_UNKNOWN: case C_STARTUP: crm_err("Copying %s data (from %s)" " not yet implemented", fsa_cause2string(cause), raised_from); exit(1); break; } crm_debug_4("%s data copied", fsa_cause2string(fsa_data->fsa_cause)); } /* make sure to free it properly later */ if(prepend) { crm_debug_2("Prepending input"); fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data); } else { fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); } crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue)); fsa_dump_queue(LOG_DEBUG_2); if(old_len == g_list_length(fsa_message_queue)){ crm_err("Couldnt add message to the queue"); } if(fsa_source) { G_main_set_trigger(fsa_source); } } void fsa_dump_queue(int log_level) { if(log_level < (int)crm_log_level) { return; } slist_iter( data, fsa_data_t, fsa_message_queue, lpc, do_crm_log(log_level, __FILE__, __FUNCTION__, "queue[%d(%d)]: input %s raised by %s()\t(cause=%s)", lpc, data->id, fsa_input2string(data->fsa_input), data->origin, fsa_cause2string(data->fsa_cause)); ); } ha_msg_input_t * copy_ha_msg_input(ha_msg_input_t *orig) { ha_msg_input_t *input_copy = NULL; crm_malloc0(input_copy, sizeof(ha_msg_input_t)); if(orig != NULL) { crm_debug_4("Copy msg"); input_copy->msg = ha_msg_copy(orig->msg); if(orig->xml != NULL) { crm_debug_4("Copy xml"); input_copy->xml = copy_xml(orig->xml); } } else { crm_debug_3("No message to copy"); } return input_copy; } void delete_fsa_input(fsa_data_t *fsa_data) { lrm_op_t *op = NULL; crm_data_t *foo = NULL; struct crmd_ccm_data_s *ccm_input = NULL; if(fsa_data == NULL) { return; } crm_debug_4("About to free %s data", fsa_cause2string(fsa_data->fsa_cause)); if(fsa_data->data != NULL) { switch(fsa_data->data_type) { case fsa_dt_ha_msg: delete_ha_msg_input(fsa_data->data); break; case fsa_dt_xml: foo = fsa_data->data; free_xml(foo); break; case fsa_dt_lrm: op = (lrm_op_t*)fsa_data->data; - crm_free(op->user_data); - crm_free(op->output); - crm_free(op->rsc_id); - crm_free(op->app_name); - crm_free(op); + free_lrm_op(op); break; case fsa_dt_ccm: ccm_input = (struct crmd_ccm_data_s *) fsa_data->data; crm_free(ccm_input->oc); crm_free(ccm_input); break; case fsa_dt_none: if(fsa_data->data != NULL) { crm_err("Dont know how to free %s data from %s", fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); exit(1); } break; } crm_debug_4("%s data freed", fsa_cause2string(fsa_data->fsa_cause)); } crm_free(fsa_data); } /* returns the next message */ fsa_data_t * get_message(void) { fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); fsa_message_queue = g_list_remove(fsa_message_queue, message); return message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (g_list_length(fsa_message_queue) > 0); } void * fsa_typed_data_adv( fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller) { void *ret_val = NULL; if(fsa_data == NULL) { do_crm_log(LOG_ERR, caller, NULL, "No FSA data available"); } else if(fsa_data->data == NULL) { do_crm_log(LOG_ERR, caller, NULL, "No message data available"); } else if(fsa_data->data_type != a_type) { do_crm_log(LOG_CRIT, caller, NULL, "Message data was the wrong type! %d vs. requested=%d." " Origin: %s", fsa_data->data_type, a_type, fsa_data->origin); CRM_ASSERT(fsa_data->data_type == a_type); } else { ret_val = fsa_data->data; } return ret_val; } /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { enum crmd_fsa_input result = I_NULL; ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); gboolean routed = FALSE; if(msg_data->fsa_cause != C_IPC_MESSAGE && msg_data->fsa_cause != C_HA_MESSAGE) { /* dont try and route these */ crm_warn("Can only process HA and IPC messages"); return I_NULL; } /* try passing the buck first */ crm_debug_4("Attempting to route message"); routed = relay_message(input->msg, cause==C_IPC_MESSAGE); if(routed == FALSE) { crm_debug_4("Message wasn't routed... try handling locally"); /* calculate defer */ result = handle_message(input); switch(result) { case I_NULL: break; case I_DC_HEARTBEAT: break; case I_CIB_OP: break; /* what else should go here? */ default: crm_debug_4("Defering local processing of message"); register_fsa_input_later( cause, result, msg_data->data); result = I_NULL; break; } if(result == I_NULL) { crm_debug_4("Message processed"); } else { register_fsa_input(cause, result, msg_data->data); } } else { crm_debug_4("Message routed..."); input->msg = NULL; } return I_NULL; } /* * This method frees msg */ gboolean send_request(HA_Message *msg, char **msg_reference) { gboolean was_sent = FALSE; /* crm_log_xml_debug_3(request, "Final request..."); */ if(msg_reference != NULL) { *msg_reference = crm_strdup( cl_get_string(msg, XML_ATTR_REFERENCE)); } was_sent = relay_message(msg, TRUE); if(was_sent == FALSE) { ha_msg_input_t *fsa_input = new_ha_msg_input(msg); register_fsa_input(C_IPC_MESSAGE, I_ROUTER, fsa_input); delete_ha_msg_input(fsa_input); crm_msg_del(msg); } return was_sent; } /* unless more processing is required, relay_message is freed */ gboolean relay_message(HA_Message *relay_message, gboolean originated_locally) { int is_for_dc = 0; int is_for_dcib = 0; int is_for_crm = 0; int is_for_cib = 0; int is_local = 0; gboolean processing_complete = FALSE; const char *host_to = cl_get_string(relay_message, F_CRM_HOST_TO); const char *sys_to = cl_get_string(relay_message, F_CRM_SYS_TO); const char *sys_from= cl_get_string(relay_message, F_CRM_SYS_FROM); const char *type = cl_get_string(relay_message, F_TYPE); const char *msg_error = NULL; crm_debug_3("Routing message %s", cl_get_string(relay_message, XML_ATTR_REFERENCE)); if(relay_message == NULL) { msg_error = "Cannot route empty message"; } else if(safe_str_eq(CRM_OP_HELLO, cl_get_string(relay_message, F_CRM_TASK))){ /* quietly ignore */ processing_complete = TRUE; } else if(safe_str_neq(type, T_CRM)) { msg_error = "Bad message type"; } else if(sys_to == NULL) { msg_error = "Bad message destination: no subsystem"; } if(msg_error != NULL) { processing_complete = TRUE; crm_err("%s", msg_error); crm_log_message(LOG_WARNING, relay_message); } if(processing_complete) { crm_msg_del(relay_message); return TRUE; } processing_complete = TRUE; is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0); is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0); is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0); is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0); is_local = 0; if(host_to == NULL || strlen(host_to) == 0) { if(is_for_dc) { is_local = 0; } else if(is_for_crm && originated_locally) { is_local = 0; } else { is_local = 1; } } else if(strcmp(fsa_our_uname, host_to) == 0) { is_local=1; } if(is_for_dc || is_for_dcib) { if(AM_I_DC) { ROUTER_RESULT("Message result: DC/CRMd process"); processing_complete = FALSE; /* more to be done by caller */ } else if(originated_locally && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE) && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) { /* Neither the TE or PE should be sending messages * to DC's on other nodes * * By definition, if we are no longer the DC, then * the PE or TE's data should be discarded */ ROUTER_RESULT("Message result: External relay to DC"); send_msg_via_ha(fsa_cluster_conn, relay_message); } else { /* discard */ ROUTER_RESULT("Message result: Discard, not DC"); crm_msg_del(relay_message); } } else if(is_local && (is_for_crm || is_for_cib)) { ROUTER_RESULT("Message result: CRMd process"); processing_complete = FALSE; /* more to be done by caller */ } else if(is_local) { ROUTER_RESULT("Message result: Local relay"); send_msg_via_ipc(relay_message, sys_to); } else { ROUTER_RESULT("Message result: External relay"); send_msg_via_ha(fsa_cluster_conn, relay_message); } return processing_complete; } gboolean crmd_authorize_message(ha_msg_input_t *client_msg, crmd_client_t *curr_client) { /* check the best case first */ const char *sys_from = cl_get_string(client_msg->msg, F_CRM_SYS_FROM); char *uuid = NULL; char *client_name = NULL; char *major_version = NULL; char *minor_version = NULL; const char *filtered_from; gpointer table_key = NULL; gboolean auth_result = FALSE; struct crm_subsystem_s *the_subsystem = NULL; gboolean can_reply = FALSE; /* no-one has registered with this id */ const char *op = cl_get_string(client_msg->msg, F_CRM_TASK); if (safe_str_neq(CRM_OP_HELLO, op)) { if(sys_from == NULL) { crm_warn("Message [%s] was had no value for %s... discarding", cl_get_string(client_msg->msg, XML_ATTR_REFERENCE), F_CRM_SYS_FROM); return FALSE; } filtered_from = sys_from; /* The CIB can have two names on the DC */ if(strcmp(sys_from, CRM_SYSTEM_DCIB) == 0) filtered_from = CRM_SYSTEM_CIB; if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) { can_reply = TRUE; /* reply can be routed */ } crm_debug_2("Message reply can%s be routed from %s.", can_reply?"":" not", sys_from); if(can_reply == FALSE) { crm_warn("Message [%s] not authorized", cl_get_string(client_msg->msg, XML_ATTR_REFERENCE)); } return can_reply; } crm_debug_3("received client join msg"); crm_log_message(LOG_MSG, client_msg->msg); auth_result = process_hello_message( client_msg->xml, &uuid, &client_name, &major_version, &minor_version); if (auth_result == TRUE) { if(client_name == NULL || uuid == NULL) { crm_err("Bad client details (client_name=%s, uuid=%s)", crm_str(client_name), crm_str(uuid)); auth_result = FALSE; } } if (auth_result == TRUE) { /* check version */ int mav = atoi(major_version); int miv = atoi(minor_version); crm_debug_3("Checking client version number"); if (mav < 0 || miv < 0) { crm_err("Client version (%d:%d) is not acceptable", mav, miv); auth_result = FALSE; } crm_free(major_version); crm_free(minor_version); } if (auth_result == TRUE) { /* if we already have one of those clients * only applies to te, pe etc. not admin clients */ if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0) { the_subsystem = te_subsystem; } if (the_subsystem != NULL) { /* do we already have one? */ crm_debug_3("Checking if %s is required/already connected", client_name); if(is_set(fsa_input_register, the_subsystem->flag_connected)) { auth_result = FALSE; crm_warn("Bit\t%.16llx set in %.16llx", the_subsystem->flag_connected, fsa_input_register); crm_err("Client %s is already connected", client_name); } else if(FALSE == is_set(fsa_input_register, the_subsystem->flag_required)) { auth_result = TRUE; crm_warn("Bit\t%.16llx not set in %.16llx", the_subsystem->flag_connected, fsa_input_register); crm_warn("Client %s joined but we dont need it", client_name); stop_subsystem(the_subsystem); } else { the_subsystem->ipc = curr_client->client_channel; set_bit_inplace(fsa_input_register, the_subsystem->flag_connected); } } else { table_key = (gpointer) generate_hash_key(client_name, uuid); } } if (auth_result == TRUE) { if(table_key == NULL) { table_key = (gpointer)crm_strdup(client_name); } crm_debug("Accepted client %s", crm_str(table_key)); curr_client->table_key = table_key; curr_client->sub_sys = crm_strdup(client_name); curr_client->uuid = crm_strdup(uuid); g_hash_table_insert (ipc_clients, table_key, curr_client->client_channel); send_hello_message(curr_client->client_channel, "n/a", CRM_SYSTEM_CRMD, "0", "1"); crm_debug_3("Updated client list with %s", crm_str(table_key)); G_main_set_trigger(fsa_source); } else { crm_warn("Rejected client logon request"); curr_client->client_channel->ch_status = IPC_DISC_PENDING; } if(uuid != NULL) crm_free(uuid); if(minor_version != NULL) crm_free(minor_version); if(major_version != NULL) crm_free(major_version); if(client_name != NULL) crm_free(client_name); /* hello messages should never be processed further */ return FALSE; } enum crmd_fsa_input handle_message(ha_msg_input_t *stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *type = NULL; if(stored_msg == NULL || stored_msg->msg == NULL) { crm_err("No message to handle"); return I_NULL; } type = cl_get_string(stored_msg->msg, F_CRM_MSG_TYPE); if(safe_str_eq(type, XML_ATTR_REQUEST)) { next_input = handle_request(stored_msg); } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { next_input = handle_response(stored_msg); } else { crm_err("Unknown message type: %s", type); } /* crm_debug_2("%s: Next input is %s", __FUNCTION__, */ /* fsa_input2string(next_input)); */ return next_input; } #define schedule_pe() \ { \ next_input = I_PE_CALC; \ if(fsa_pe_ref) { \ crm_debug("Cancelling %s...", fsa_pe_ref); \ crm_free(fsa_pe_ref); \ fsa_pe_ref = NULL; \ } \ } enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg) { HA_Message *msg = NULL; enum crmd_fsa_input next_input = I_NULL; const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK); const char *sys_to = cl_get_string(stored_msg->msg, F_CRM_SYS_TO); const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM); crm_debug_2("Received %s in state %s", op, fsa_state2string(fsa_state)); if(op == NULL) { crm_err("Bad message"); crm_log_message(LOG_ERR, stored_msg->msg); /*========== common actions ==========*/ } else if(strcmp(op, CRM_OP_NOOP) == 0) { crm_debug("no-op from %s", crm_str(host_from)); } else if(strcmp(op, CRM_OP_VOTE) == 0) { /* count the vote and decide what to do after that */ register_fsa_input_adv(C_HA_MESSAGE, I_NULL, stored_msg, A_ELECTION_COUNT, FALSE, __FUNCTION__); /* Sometimes we _must_ go into S_ELECTION */ if(fsa_state == S_HALT) { crm_debug("Forcing an election from S_HALT"); next_input = I_ELECTION; #if 0 } else if(AM_I_DC) { /* This is the old way of doing things but what is gained? */ next_input = I_ELECTION; #endif } } else if(strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) { crm_shutdown(SIGTERM); /*next_input = I_SHUTDOWN; */ next_input = I_NULL; } else if(strcmp(op, CRM_OP_PING) == 0) { /* eventually do some stuff to figure out * if we /are/ ok */ crm_data_t *ping = createPingAnswerFragment(sys_to, "ok"); crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state)); crm_info("Current state: %s", fsa_state2string(fsa_state)); msg = create_reply(stored_msg->msg, ping); if(relay_message(msg, TRUE) == FALSE) { crm_msg_del(msg); } /* probably better to do this via signals on the * local node */ } else if(strcmp(op, CRM_OP_DEBUG_UP) == 0) { int level = get_crm_log_level(); set_crm_log_level(level+1); crm_info("Debug set to %d (was %d)", get_crm_log_level(), level); } else if(strcmp(op, CRM_OP_DEBUG_DOWN) == 0) { int level = get_crm_log_level(); set_crm_log_level(level-1); crm_info("Debug set to %d (was %d)", get_crm_log_level(), level); } else if(strcmp(op, CRM_OP_JOIN_OFFER) == 0) { next_input = I_JOIN_OFFER; } else if(strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) { next_input = I_JOIN_RESULT; /* this functionality should only be enabled * if this is a development build */ } else if(CRM_DEV_BUILD && strcmp(op, CRM_OP_DIE) == 0/*constant condition*/) { crm_warn("Test-only code: Killing the CRM without mercy"); crm_warn("Inhibiting respawns"); exit(100); /*========== (NOT_DC)-Only Actions ==========*/ } else if(AM_I_DC == FALSE){ gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(dc_match || fsa_our_dc == NULL) { if(strcmp(op, CRM_OP_HBEAT) == 0) { crm_debug_3("Received DC heartbeat from %s", host_from); next_input = I_DC_HEARTBEAT; } else if(fsa_our_dc == NULL) { crm_warn("CRMd discarding request: %s" " (DC: %s, from: %s)", op, crm_str(fsa_our_dc), host_from); crm_warn("Ignored Request"); crm_log_message(LOG_WARNING, stored_msg->msg); } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { next_input = I_STOP; } else { crm_err("CRMd didnt expect request: %s", op); crm_log_message(LOG_ERR, stored_msg->msg); } } else { crm_warn("Discarding %s op from %s", op, host_from); } /*========== DC-Only Actions ==========*/ } else if(AM_I_DC) { const char *message = ha_msg_value(stored_msg->msg, "message"); /* setting "fsa_pe_ref = NULL" makes sure we ignore any * PE reply that might be pending or in the queue while * we ask the CIB for a more up-to-date copy */ if(safe_str_eq(op, CRM_OP_TEABORT)) { crm_debug("Transition cancelled: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(need_transition(fsa_state)) { schedule_pe(); } else { crm_debug("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(safe_str_eq(op, CRM_OP_TETIMEOUT)) { crm_debug("Transition cancelled: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(fsa_state == S_IDLE) { crm_err("Transition timed out in S_IDLE"); schedule_pe(); } else if(need_transition(fsa_state)) { schedule_pe(); } else { crm_err("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(safe_str_eq(op, CRM_OP_TEABORTED)) { crm_debug("Transition cancelled: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(need_transition(fsa_state)) { schedule_pe(); } else { crm_debug("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(strcmp(op, CRM_OP_TECOMPLETE) == 0) { crm_debug("Transition complete: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(fsa_state == S_TRANSITION_ENGINE) { next_input = I_TE_SUCCESS; } else { crm_debug("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } else if(strcmp(op, CRM_OP_JOIN_REQUEST) == 0) { next_input = I_JOIN_REQUEST; } else if(strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) { next_input = I_JOIN_RESULT; } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(dc_match) { crm_err("We didnt ask to be shut down yet our" " TE is telling us too." " Better get out now!"); next_input = I_TERMINATE; } else if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_err("We asked to be shut down, " " are still the DC, yet another node" " (DC) is askin us to shutdown!"); next_input = I_STOP; } else if(fsa_state != S_STOPPING) { crm_err("Another node is asking us to shutdown" " but we think we're ok."); next_input = I_ELECTION; } } else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* a slave wants to shut down */ /* create cib fragment and add to message */ next_input = handle_shutdown_request(stored_msg->msg); } else { crm_err("Unexpected request (%s) sent to the DC", op); crm_log_message(LOG_ERR, stored_msg->msg); } } return next_input; } enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK); const char *sys_from = cl_get_string(stored_msg->msg, F_CRM_SYS_FROM); const char *msg_ref = cl_get_string(stored_msg->msg, XML_ATTR_REFERENCE); crm_debug_2("Received %s %s in state %s", op, XML_ATTR_RESPONSE, fsa_state2string(fsa_state)); if(op == NULL) { crm_err("Bad message"); crm_log_message(LOG_ERR, stored_msg->msg); } else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) { crm_debug("Processing %s reply %s (fsa=%s)", sys_from, msg_ref, crm_str(fsa_pe_ref)); if(msg_ref != NULL && safe_str_eq(msg_ref, fsa_pe_ref)) { next_input = I_PE_SUCCESS; crm_debug("Completed: %s...", fsa_pe_ref); crm_free(fsa_pe_ref); fsa_pe_ref = NULL; } else { crm_debug("Skipping superceeded reply from %s", sys_from); } } else if(strcmp(op, CRM_OP_VOTE) == 0 || strcmp(op, CRM_OP_HBEAT) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) { next_input = I_NULL; } else { crm_err("Unexpected response (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); next_input = I_NULL; } return next_input; } enum crmd_fsa_input handle_shutdown_request(HA_Message *stored_msg) { /* handle here to avoid potential version issues * where the shutdown message/proceedure may have * been changed in later versions. * * This way the DC is always in control of the shutdown */ crm_data_t *frag = NULL; time_t now = time(NULL); char *now_s = crm_itoa((int)now); crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); const char *host_from= cl_get_string(stored_msg, F_CRM_HOST_FROM); crm_info("Creating shutdown request for %s",host_from); crm_log_message(LOG_MSG, stored_msg); set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, host_from); crm_xml_add(node_state, XML_ATTR_UNAME, host_from); crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN, now_s); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_INACTIVE); frag = create_cib_fragment(node_state, NULL); /* cleanup intermediate steps */ free_xml(node_state); crm_free(now_s); fsa_cib_conn->cmds->modify( fsa_cib_conn, XML_CIB_TAG_STATUS, frag, NULL, cib_quorum_override); free_xml(frag); /* will be picked up by the TE as long as its running */ if(need_transition(fsa_state) && is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) { register_fsa_action(A_TE_CANCEL); } return I_NULL; } /* frees msg upon completion */ gboolean send_msg_via_ha(ll_cluster_t *hb_fd, HA_Message *msg) { int log_level = LOG_DEBUG_3; gboolean broadcast = FALSE; gboolean all_is_good = TRUE; const char *op = cl_get_string(msg, F_CRM_TASK); const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *host_to = cl_get_string(msg, F_CRM_HOST_TO); if (msg == NULL) { crm_err("Attempt to send NULL Message via HA failed."); all_is_good = FALSE; } else { crm_debug_4("Relaying message to (%s) via HA", host_to); } if (all_is_good) { if (sys_to == NULL || strlen(sys_to) == 0) { crm_err("You did not specify a destination sub-system" " for this message."); all_is_good = FALSE; } } /* There are a number of messages may not need to be ordered. * At a later point perhaps we should detect them and send them * as unordered messages. */ if (all_is_good) { if (host_to == NULL || strlen(host_to) == 0 || safe_str_eq(sys_to, CRM_SYSTEM_DC)) { broadcast = TRUE; all_is_good = send_ha_message(hb_fd, msg, NULL, FALSE); } else { all_is_good = send_ha_message(hb_fd, msg, host_to, FALSE); } } if(all_is_good == FALSE) { log_level = LOG_ERR; } if(log_level == LOG_ERR || (safe_str_neq(op, CRM_OP_HBEAT))) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Sending %sHA message (ref=%s) to %s@%s %s.", broadcast?"broadcast ":"directed ", cl_get_string(msg, XML_ATTR_REFERENCE), crm_str(sys_to), host_to==NULL?"":host_to, all_is_good?"succeeded":"failed"); } crm_msg_del(msg); return all_is_good; } /* msg is deleted by the time this returns */ gboolean send_msg_via_ipc(HA_Message *msg, const char *sys) { gboolean send_ok = TRUE; IPC_Channel *client_channel; enum crmd_fsa_input next_input; crm_debug_4("relaying msg to sub_sys=%s via IPC", sys); client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys); if(cl_get_string(msg, F_CRM_HOST_FROM) == NULL) { ha_msg_add(msg, F_CRM_HOST_FROM, fsa_our_uname); } if (client_channel != NULL) { crm_debug_3("Sending message via channel %s.", sys); send_ok = send_ipc_message(client_channel, msg); msg = NULL; /* so the crm_msg_del() below doesnt fail */ } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) { crm_err("Sub-system (%s) has been incorporated into the CRMd.", sys); crm_err("Change the way we handle this CIB message"); crm_log_message(LOG_ERR, msg); send_ok = FALSE; } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) { fsa_data_t *fsa_data = NULL; ha_msg_input_t *msg_copy = new_ha_msg_input(msg); crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_MESSAGE; fsa_data->fsa_cause = C_IPC_MESSAGE; fsa_data->data = msg_copy; fsa_data->origin = __FUNCTION__; fsa_data->data_type = fsa_dt_ha_msg; #ifdef FSA_TRACE crm_debug_2("Invoking action %s (%.16llx)", fsa_action2string(A_LRM_INVOKE), A_LRM_INVOKE); #endif next_input = do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, fsa_data); delete_ha_msg_input(msg_copy); crm_free(fsa_data); /* todo: feed this back in for anything != I_NULL */ #ifdef FSA_TRACE crm_debug_2("Result of action %s was %s", fsa_action2string(A_LRM_INVOKE), fsa_input2string(next_input)); #endif } else { crm_err("Unknown Sub-system (%s)... discarding message.", crm_str(sys)); send_ok = FALSE; } crm_msg_del(msg); return send_ok; } void msg_queue_helper(void) { IPC_Channel *ipc = NULL; if(fsa_cluster_conn != NULL) { ipc = fsa_cluster_conn->llc_ops->ipcchan( fsa_cluster_conn); } if(ipc != NULL) { ipc->ops->resume_io(ipc); } /* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */ } gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data) { crmd_client_t *ipc_client = value; if(ipc_client->client_channel != NULL) { ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel); } return FALSE; } diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c index f66b36ba4c..afe585d657 100644 --- a/crm/crmd/utils.c +++ b/crm/crmd/utils.c @@ -1,1381 +1,1316 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy); /* A_DC_TIMER_STOP, A_DC_TIMER_START, * A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START * A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START */ enum crmd_fsa_input do_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { gboolean timer_op_ok = TRUE; enum crmd_fsa_input result = I_NULL; if(action & A_DC_TIMER_STOP) { timer_op_ok = crm_timer_stop(election_trigger); } else if(action & A_FINALIZE_TIMER_STOP) { timer_op_ok = crm_timer_stop(finalization_timer); } else if(action & A_INTEGRATE_TIMER_STOP) { timer_op_ok = crm_timer_stop(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_STOP) { */ /* timer_op_ok = crm_timer_stop(election_timeout); */ } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { crm_timer_start(election_trigger); if(AM_I_DC) { /* there can be only one */ result = I_ELECTION; } } else if(action & A_FINALIZE_TIMER_START) { crm_timer_start(finalization_timer); } else if(action & A_INTEGRATE_TIMER_START) { crm_timer_start(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_START) { */ /* crm_timer_start(election_timeout); */ } return I_NULL; } gboolean crm_timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; if(timer == election_trigger) { crm_info("Election Trigger (%s) just popped!", fsa_input2string(timer->fsa_input)); } else if(timer == election_timeout) { crm_info("Election Timeout (%s) just popped!", fsa_input2string(timer->fsa_input)); } else { crm_info("Timer %s just popped!", fsa_input2string(timer->fsa_input)); } if(timer->repeat == FALSE) { crm_timer_stop(timer); /* make it _not_ go off again */ } if(timer->fsa_input == I_INTEGRATED) { register_fsa_input_before( C_TIMER_POPPED, timer->fsa_input, NULL); } else if(timer->fsa_input == I_FINALIZED && fsa_state != S_FINALIZE_JOIN) { crm_debug("Discarding I_FINALIZED event in state: %s", fsa_state2string(fsa_state)); } else if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } G_main_set_trigger(fsa_source); return TRUE; } gboolean crm_timer_start(fsa_timer_t *timer) { const char *timer_desc = NULL; if(timer == election_trigger) { timer_desc = "Election Trigger"; } else if(timer == election_timeout) { timer_desc = "Election Timeout"; } else { timer_desc = "Timer"; } if((timer->source_id == (guint)-1 || timer->source_id == (guint)-2) && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add( timer->period_ms, timer->callback, (void*)timer); crm_debug("Started %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); } else if(timer->period_ms < 0) { crm_err("Tried to start %s (%s:%dms) with a -ve period", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); } else { crm_debug("%s (%s:%dms) already running: src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); return FALSE; } return TRUE; } gboolean crm_timer_stop(fsa_timer_t *timer) { const char *timer_desc = NULL; if(timer == election_trigger) { timer_desc = "Election Trigger"; } else if(timer == election_timeout) { timer_desc = "Election Timeout"; } else if(timer == wait_timer) { timer_desc = "Stall Timeout"; } else { timer_desc = "Timer"; } if(timer == NULL) { crm_err("Attempted to stop NULL timer"); return FALSE; } else if(timer->source_id != (guint)-1 && timer->source_id != (guint)-2) { crm_debug("Stopping %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); g_source_remove(timer->source_id); timer->source_id = -2; } else { crm_debug_2("%s (%s:%dms) already stopped", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); timer->source_id = -2; return FALSE; } return TRUE; } long long toggle_bit(long long action_list, long long action) { crm_debug_5("Toggling bit %.16llx", action); action_list ^= action; crm_debug_5("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "Clearing bit\t%.16llx", action); /* ensure its set */ action_list |= action; /* then toggle */ action_list = action_list ^ action; return action_list; } long long set_bit(long long action_list, long long action) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "Setting bit\t%.16llx", action); action_list |= action; return action_list; } gboolean is_set(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); return ((action_list & action) == action); } gboolean is_set_any(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); return ((action_list & action) != 0); } const char * fsa_input2string(enum crmd_fsa_input input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; break; case I_CCM_EVENT: inputAsText = "I_CCM_EVENT"; break; case I_CIB_OP: inputAsText = "I_CIB_OP"; break; case I_CIB_UPDATE: inputAsText = "I_CIB_UPDATE"; break; case I_DC_TIMEOUT: inputAsText = "I_DC_TIMEOUT"; break; case I_ELECTION: inputAsText = "I_ELECTION"; break; case I_PE_CALC: inputAsText = "I_PE_CALC"; break; case I_RELEASE_DC: inputAsText = "I_RELEASE_DC"; break; case I_ELECTION_DC: inputAsText = "I_ELECTION_DC"; break; case I_ERROR: inputAsText = "I_ERROR"; break; case I_FAIL: inputAsText = "I_FAIL"; break; case I_INTEGRATED: inputAsText = "I_INTEGRATED"; break; case I_FINALIZED: inputAsText = "I_FINALIZED"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; case I_JOIN_OFFER: inputAsText = "I_JOIN_OFFER"; break; case I_JOIN_REQUEST: inputAsText = "I_JOIN_REQUEST"; break; case I_JOIN_RESULT: inputAsText = "I_JOIN_RESULT"; break; case I_NOT_DC: inputAsText = "I_NOT_DC"; break; case I_RECOVERED: inputAsText = "I_RECOVERED"; break; case I_RELEASE_FAIL: inputAsText = "I_RELEASE_FAIL"; break; case I_RELEASE_SUCCESS: inputAsText = "I_RELEASE_SUCCESS"; break; case I_RESTART: inputAsText = "I_RESTART"; break; case I_PE_SUCCESS: inputAsText = "I_PE_SUCCESS"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_TE_SUCCESS: inputAsText = "I_TE_SUCCESS"; break; case I_STOP: inputAsText = "I_STOP"; break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; case I_WAIT_FOR_EVENT: inputAsText = "I_WAIT_FOR_EVENT"; break; case I_LRM_EVENT: inputAsText = "I_LRM_EVENT"; break; case I_PENDING: inputAsText = "I_PENDING"; break; case I_HALT: inputAsText = "I_HALT"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if(inputAsText == NULL) { crm_err("Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(enum crmd_fsa_state state) { const char *stateAsText = NULL; switch(state){ case S_IDLE: stateAsText = "S_IDLE"; break; case S_ELECTION: stateAsText = "S_ELECTION"; break; case S_INTEGRATION: stateAsText = "S_INTEGRATION"; break; case S_FINALIZE_JOIN: stateAsText = "S_FINALIZE_JOIN"; break; case S_NOT_DC: stateAsText = "S_NOT_DC"; break; case S_POLICY_ENGINE: stateAsText = "S_POLICY_ENGINE"; break; case S_RECOVERY: stateAsText = "S_RECOVERY"; break; case S_RELEASE_DC: stateAsText = "S_RELEASE_DC"; break; case S_PENDING: stateAsText = "S_PENDING"; break; case S_STOPPING: stateAsText = "S_STOPPING"; break; case S_TERMINATE: stateAsText = "S_TERMINATE"; break; case S_TRANSITION_ENGINE: stateAsText = "S_TRANSITION_ENGINE"; break; case S_STARTING: stateAsText = "S_STARTING"; break; case S_HALT: stateAsText = "S_HALT"; break; case S_ILLEGAL: stateAsText = "S_ILLEGAL"; break; } if(stateAsText == NULL) { crm_err("State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(enum crmd_fsa_cause cause) { const char *causeAsText = NULL; switch(cause){ case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_CCM_CALLBACK: causeAsText = "C_CCM_CALLBACK"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_HEARTBEAT_FAILED: causeAsText = "C_HEARTBEAT_FAILED"; break; case C_SUBSYSTEM_CONNECT: causeAsText = "C_SUBSYSTEM_CONNECT"; break; case C_LRM_OP_CALLBACK: causeAsText = "C_LRM_OP_CALLBACK"; break; case C_LRM_MONITOR_CALLBACK: causeAsText = "C_LRM_MONITOR_CALLBACK"; break; case C_CRMD_STATUS_CALLBACK: causeAsText = "C_CRMD_STATUS_CALLBACK"; break; case C_HA_DISCONNECT: causeAsText = "C_HA_DISCONNECT"; break; case C_FSA_INTERNAL: causeAsText = "C_FSA_INTERNAL"; break; case C_ILLEGAL: causeAsText = "C_ILLEGAL"; break; } if(causeAsText == NULL) { crm_err("Cause %d is unknown", cause); causeAsText = ""; } return causeAsText; } const char * fsa_action2string(long long action) { const char *actionAsText = NULL; switch(action){ case A_NOTHING: actionAsText = "A_NOTHING"; break; case A_ELECTION_START: actionAsText = "A_ELECTION_START"; break; case A_READCONFIG: actionAsText = "A_READCONFIG"; break; case O_RELEASE: actionAsText = "O_RELEASE"; break; case A_STARTUP: actionAsText = "A_STARTUP"; break; case A_STARTED: actionAsText = "A_STARTED"; break; case A_HA_CONNECT: actionAsText = "A_HA_CONNECT"; break; case A_HA_DISCONNECT: actionAsText = "A_HA_DISCONNECT"; break; case A_LRM_CONNECT: actionAsText = "A_LRM_CONNECT"; break; case A_LRM_EVENT: actionAsText = "A_LRM_EVENT"; break; case A_LRM_INVOKE: actionAsText = "A_LRM_INVOKE"; break; case A_LRM_DISCONNECT: actionAsText = "A_LRM_DISCONNECT"; break; case A_CL_JOIN_QUERY: actionAsText = "A_CL_JOIN_QUERY"; break; case A_DC_TIMER_STOP: actionAsText = "A_DC_TIMER_STOP"; break; case A_DC_TIMER_START: actionAsText = "A_DC_TIMER_START"; break; case A_INTEGRATE_TIMER_START: actionAsText = "A_INTEGRATE_TIMER_START"; break; case A_INTEGRATE_TIMER_STOP: actionAsText = "A_INTEGRATE_TIMER_STOP"; break; case A_FINALIZE_TIMER_START: actionAsText = "A_FINALIZE_TIMER_START"; break; case A_FINALIZE_TIMER_STOP: actionAsText = "A_FINALIZE_TIMER_STOP"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; case A_CL_JOIN_ANNOUNCE: actionAsText = "A_CL_JOIN_ANNOUNCE"; break; case A_CL_JOIN_REQUEST: actionAsText = "A_CL_JOIN_REQUEST"; break; case A_CL_JOIN_RESULT: actionAsText = "A_CL_JOIN_RESULT"; break; case A_DC_JOIN_OFFER_ALL: actionAsText = "A_DC_JOIN_OFFER_ALL"; break; case A_DC_JOIN_OFFER_ONE: actionAsText = "A_DC_JOIN_OFFER_ONE"; break; case A_DC_JOIN_PROCESS_REQ: actionAsText = "A_DC_JOIN_PROCESS_REQ"; break; case A_DC_JOIN_PROCESS_ACK: actionAsText = "A_DC_JOIN_PROCESS_ACK"; break; case A_DC_JOIN_FINALIZE: actionAsText = "A_DC_JOIN_FINALIZE"; break; case A_MSG_PROCESS: actionAsText = "A_MSG_PROCESS"; break; case A_MSG_ROUTE: actionAsText = "A_MSG_ROUTE"; break; case A_RECOVER: actionAsText = "A_RECOVER"; break; case A_DC_RELEASE: actionAsText = "A_DC_RELEASE"; break; case A_DC_RELEASED: actionAsText = "A_DC_RELEASED"; break; case A_DC_TAKEOVER: actionAsText = "A_DC_TAKEOVER"; break; case A_SHUTDOWN: actionAsText = "A_SHUTDOWN"; break; case A_SHUTDOWN_REQ: actionAsText = "A_SHUTDOWN_REQ"; break; case A_STOP: actionAsText = "A_STOP "; break; case A_EXIT_0: actionAsText = "A_EXIT_0"; break; case A_EXIT_1: actionAsText = "A_EXIT_1"; break; case A_CCM_CONNECT: actionAsText = "A_CCM_CONNECT"; break; case A_CCM_DISCONNECT: actionAsText = "A_CCM_DISCONNECT"; break; case A_CCM_EVENT: actionAsText = "A_CCM_EVENT"; break; case A_CCM_UPDATE_CACHE: actionAsText = "A_CCM_UPDATE_CACHE"; break; case A_CIB_BUMPGEN: actionAsText = "A_CIB_BUMPGEN"; break; case A_CIB_INVOKE: actionAsText = "A_CIB_INVOKE"; break; case O_CIB_RESTART: actionAsText = "O_CIB_RESTART"; break; case A_CIB_START: actionAsText = "A_CIB_START"; break; case A_CIB_STOP: actionAsText = "A_CIB_STOP"; break; case A_TE_INVOKE: actionAsText = "A_TE_INVOKE"; break; case O_TE_RESTART: actionAsText = "O_TE_RESTART"; break; case A_TE_START: actionAsText = "A_TE_START"; break; case A_TE_STOP: actionAsText = "A_TE_STOP"; break; case A_TE_CANCEL: actionAsText = "A_TE_CANCEL"; break; case A_PE_INVOKE: actionAsText = "A_PE_INVOKE"; break; case O_PE_RESTART: actionAsText = "O_PE_RESTART"; break; case A_PE_START: actionAsText = "A_PE_START"; break; case A_PE_STOP: actionAsText = "A_PE_STOP"; break; case A_NODE_BLOCK: actionAsText = "A_NODE_BLOCK"; break; case A_UPDATE_NODESTATUS: actionAsText = "A_UPDATE_NODESTATUS"; break; case A_LOG: actionAsText = "A_LOG "; break; case A_ERROR: actionAsText = "A_ERROR "; break; case A_WARN: actionAsText = "A_WARN "; break; } if(actionAsText == NULL) { crm_err("Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } void fsa_dump_inputs(int log_level, const char *text, long long input_register) { if(input_register == A_NOTHING) { return; } if(text == NULL) { text = "Input register contents:"; } if(is_set(input_register, R_THE_DC)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_THE_DC)", text, R_THE_DC); } if(is_set(input_register, R_STARTING)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_STARTING)", text, R_STARTING); } if(is_set(input_register, R_SHUTDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN); } if(is_set(input_register, R_STAYDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN); } if(is_set(input_register, R_JOIN_OK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK); } if(is_set(input_register, R_HAVE_RES)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_HAVE_RES)", text, R_HAVE_RES); } if(is_set(input_register, R_INVOKE_PE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE); } if(is_set(input_register, R_CIB_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if(is_set(input_register, R_PE_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if(is_set(input_register, R_TE_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if(is_set(input_register, R_LRM_CONNECTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } if(is_set(input_register, R_CIB_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); } if(is_set(input_register, R_PE_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED); } if(is_set(input_register, R_TE_REQUIRED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED); } if(is_set(input_register, R_REQ_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND); } if(is_set(input_register, R_PE_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PE_PEND)", text, R_PE_PEND); } if(is_set(input_register, R_TE_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_TE_PEND)", text, R_TE_PEND); } if(is_set(input_register, R_RESP_PEND)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND); } if(is_set(input_register, R_CIB_DONE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE); } if(is_set(input_register, R_HAVE_CIB)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB); } if(is_set(input_register, R_CIB_ASKED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED); } if(is_set(input_register, R_CCM_DATA)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA); } if(is_set(input_register, R_PEER_DATA)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA); } if(is_set(input_register, R_IN_RECOVERY)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY); } } void fsa_dump_actions(long long action, const char *text) { int log_level = LOG_DEBUG_3; if(is_set(action, A_READCONFIG)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if(is_set(action, A_DC_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if(is_set(action, A_FINALIZE_TIMER_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if(is_set(action, A_FINALIZE_TIMER_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if(is_set(action, A_CL_JOIN_REQUEST)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if(is_set(action, A_CL_JOIN_RESULT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if(is_set(action, A_DC_JOIN_OFFER_ALL)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text); } if(is_set(action, A_DC_JOIN_OFFER_ONE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text); } if(is_set(action, A_DC_JOIN_PROCESS_REQ)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text); } if(is_set(action, A_DC_JOIN_PROCESS_ACK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text); } if(is_set(action, A_DC_JOIN_FINALIZE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_RECOVER)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CCM_EVENT)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_EVENT) %s", A_CCM_EVENT, text); } if(is_set(action, A_CCM_UPDATE_CACHE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CCM_UPDATE_CACHE) %s", A_CCM_UPDATE_CACHE, text); } if(is_set(action, A_CIB_BUMPGEN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_BUMPGEN) %s", A_CIB_BUMPGEN, text); } if(is_set(action, A_CIB_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_INVOKE) %s", A_CIB_INVOKE, text); } if(is_set(action, A_CIB_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_PE_INVOKE)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { do_crm_log(log_level, __FILE__, __FUNCTION__, "Action %.16llx (A_WARN ) %s", A_WARN, text); } } void create_node_entry(const char *uuid, const char *uname, const char *type) { /* make sure a node entry exists for the new node * * this will add anyone except the first ever node in the cluster * since it will also be the DC which doesnt go through the * join process (with itself). We can include a special case * later if desired. */ crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug_3("Creating node entry for %s", uname); set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname); crm_xml_add(tmp1, XML_ATTR_UNAME, uname); crm_xml_add(tmp1, XML_ATTR_TYPE, type); update_local_cib(create_cib_fragment(tmp1, NULL)); free_xml(tmp1); } struct crmd_ccm_data_s * copy_ccm_data(const struct crmd_ccm_data_s *ccm_input) { const oc_ev_membership_t *oc_in = (const oc_ev_membership_t *)ccm_input->oc; struct crmd_ccm_data_s *ccm_input_copy = NULL; crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s)); ccm_input_copy->oc = copy_ccm_oc_data(oc_in); ccm_input_copy->event = ccm_input->event; return ccm_input_copy; } oc_ev_membership_t * copy_ccm_oc_data(const oc_ev_membership_t *oc_in) { unsigned lpc = 0; int size = 0; int offset = 0; unsigned num_nodes = 0; oc_ev_membership_t *oc_copy = NULL; if(oc_in->m_n_member > 0 && num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) { num_nodes = oc_in->m_n_member + oc_in->m_memb_idx; crm_debug_3("Updated ccm nodes to %d - 1", num_nodes); } if(oc_in->m_n_in > 0 && num_nodes < oc_in->m_n_in + oc_in->m_in_idx) { num_nodes = oc_in->m_n_in + oc_in->m_in_idx; crm_debug_3("Updated ccm nodes to %d - 2", num_nodes); } if(oc_in->m_n_out > 0 && num_nodes < oc_in->m_n_out + oc_in->m_out_idx) { num_nodes = oc_in->m_n_out + oc_in->m_out_idx; crm_debug_3("Updated ccm nodes to %d - 3", num_nodes); } /* why 2*?? * ccm code does it like this so i guess its right... */ size = sizeof(oc_ev_membership_t) + sizeof(int) + 2*num_nodes*sizeof(oc_node_t); crm_debug_3("Copying %d ccm nodes", num_nodes); crm_malloc0(oc_copy, size); oc_copy->m_instance = oc_in->m_instance; oc_copy->m_n_member = oc_in->m_n_member; oc_copy->m_memb_idx = oc_in->m_memb_idx; oc_copy->m_n_out = oc_in->m_n_out; oc_copy->m_out_idx = oc_in->m_out_idx; oc_copy->m_n_in = oc_in->m_n_in; oc_copy->m_in_idx = oc_in->m_in_idx; crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)", oc_in->m_instance, oc_in->m_n_member, oc_in->m_memb_idx, oc_in->m_n_in, oc_in->m_in_idx, oc_in->m_n_out, oc_in->m_out_idx); offset = oc_in->m_memb_idx; for(lpc = 0; lpc < oc_in->m_n_member; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm member node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_in_idx; for(lpc = 0; lpc < oc_in->m_n_in; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm new node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_out_idx; for(lpc = 0; lpc < oc_in->m_n_out; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_debug_3("Copying ccm lost node %d", lpc); copy_ccm_node(a_node, a_node_copy); } return oc_copy; } void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy) { crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s", a_node.node_id, a_node.node_born_on, a_node.node_uname); a_node_copy->node_id = a_node.node_id; a_node_copy->node_born_on = a_node.node_born_on; a_node_copy->node_uname = NULL; if(a_node.node_uname != NULL) { a_node_copy->node_uname = crm_strdup(a_node.node_uname); } else { crm_err("Node Id %d had a NULL uname!", a_node.node_id); } crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s", a_node_copy->node_id, a_node_copy->node_born_on, a_node_copy->node_uname); } - -lrm_op_t * -copy_lrm_op(const lrm_op_t *op) -{ - lrm_op_t *op_copy = NULL; - crm_malloc0(op_copy, sizeof(lrm_op_t)); - - op_copy->op_type = crm_strdup(op->op_type); - /* input fields */ -/* GHashTable* params; */ - op_copy->params = NULL; - op_copy->timeout = op->timeout; - op_copy->interval = op->interval; - op_copy->target_rc = op->target_rc; - - /* in the CRM, this is always an int */ - if(op->user_data != NULL) { - op_copy->user_data = crm_strdup(op->user_data); - } - - /* output fields */ - op_copy->op_status = op->op_status; - op_copy->rc = op->rc; - op_copy->call_id = op->call_id; - op_copy->output = NULL; - op_copy->rsc_id = crm_strdup(op->rsc_id); - op_copy->app_name = crm_strdup(op->app_name); - if(op->output!= NULL) { - op_copy->output = crm_strdup(op->output); - } - - return op_copy; -} - - -lrm_rsc_t * -copy_lrm_rsc(const lrm_rsc_t *rsc) -{ - lrm_rsc_t *rsc_copy = NULL; - - if(rsc == NULL) { - return NULL; - } - - crm_malloc0(rsc_copy, sizeof(lrm_rsc_t)); - - rsc_copy->id = crm_strdup(rsc->id); - rsc_copy->type = crm_strdup(rsc->type); - rsc_copy->class = NULL; - rsc_copy->provider = NULL; - - if(rsc->class != NULL) { - rsc_copy->class = crm_strdup(rsc->class); - } - if(rsc->provider != NULL) { - rsc_copy->provider = crm_strdup(rsc->provider); - } -/* GHashTable* params; */ - rsc_copy->params = NULL; - rsc_copy->ops = NULL; - - return rsc_copy; -} - - crm_data_t* create_node_state( const char *uuid, const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, const char *src) { crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug_2("%s Creating node state entry for %s", src, uname); set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname); crm_xml_add(node_state, XML_ATTR_UNAME, uname); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state); crm_xml_add(node_state, "origin", src); crm_log_xml_debug_3(node_state, "created"); return node_state; } gboolean need_transition(enum crmd_fsa_state state) { if(state == S_POLICY_ENGINE || state == S_TRANSITION_ENGINE || state == S_IDLE) { return TRUE; } return FALSE; } extern GHashTable *ipc_clients; void process_client_disconnect(crmd_client_t *curr_client) { struct crm_subsystem_s *the_subsystem = NULL; CRM_DEV_ASSERT(curr_client != NULL); if(crm_assert_failed) { return; } crm_debug_2("received HUP from %s", curr_client->table_key); if (curr_client->sub_sys == NULL) { crm_debug("Client hadn't registered with us yet"); } else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { the_subsystem->ipc = NULL; } /* else that was a transient client */ if (curr_client->table_key != NULL) { /* * Key is destroyed below: * curr_client->table_key * Value is cleaned up by: * G_main_del_IPC_Channel */ g_hash_table_remove(ipc_clients, curr_client->table_key); } crm_free(curr_client->table_key); crm_free(curr_client->sub_sys); crm_free(curr_client->uuid); crm_free(curr_client); } diff --git a/crm/pengine/complex.h b/crm/pengine/complex.h index 230c429d7c..c8bcc9ae1f 100644 --- a/crm/pengine/complex.h +++ b/crm/pengine/complex.h @@ -1,189 +1,188 @@ -/* $Id: complex.h,v 1.18 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: complex.h,v 1.19 2005/08/10 08:55:04 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_PENGINE_COMPLEX__H #define CRM_PENGINE_COMPLEX__H #include #include #include #define n_object_classes 3 /*#define PE_OBJ_F_ ""*/ #define PE_OBJ_T_NATIVE "native" #define PE_OBJ_T_GROUP "group" #define PE_OBJ_T_INCARNATION "incarnation" enum pe_obj_types { pe_native = 0, pe_group = 1, pe_clone = 2, pe_unknown = -1 }; extern int get_resource_type(const char *name); typedef struct resource_object_functions_s { void (*unpack)(resource_t *, pe_working_set_t *); resource_t *(*find_child)(resource_t *, const char *); int (*num_allowed_nodes)(resource_t *); void (*color)(resource_t *, pe_working_set_t *); void (*create_actions)(resource_t *, pe_working_set_t *); void (*internal_constraints)(resource_t *, pe_working_set_t *); void (*agent_constraints)(resource_t *); void (*rsc_colocation_lh)(rsc_colocation_t *); void (*rsc_colocation_rh)(resource_t *, rsc_colocation_t *); void (*rsc_order_lh)(resource_t *, order_constraint_t *); void (*rsc_order_rh)( action_t *, resource_t *, order_constraint_t *); void (*rsc_location)(resource_t *, rsc_to_node_t *); void (*expand)(resource_t *, pe_working_set_t *); void (*dump)(resource_t *, const char *, gboolean); void (*printw)(resource_t *, const char *, int*); void (*html)(resource_t *, const char *, FILE*); gboolean (*active)(resource_t *,gboolean); rsc_state_t (*state)(resource_t *); - void (*create_notify_element)(resource_t*,action_t*,crm_data_t*, - const char*,pe_working_set_t*); + void (*create_notify_element)(resource_t*,action_t*, + crm_data_t*,pe_working_set_t*); void (*free)(resource_t *); } resource_object_functions_t; extern void native_unpack(resource_t *rsc, pe_working_set_t *data_set); extern resource_t *native_find_child(resource_t *rsc, const char *id); extern int native_num_allowed_nodes(resource_t *rsc); extern void native_color(resource_t *rsc, pe_working_set_t *data_set); extern void native_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void native_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void native_agent_constraints(resource_t *rsc); extern void native_rsc_colocation_lh(rsc_colocation_t *constraint); extern void native_rsc_colocation_rh( resource_t *rsc, rsc_colocation_t *constraint); extern void native_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void native_expand(resource_t *rsc, pe_working_set_t *data_set); extern void native_dump(resource_t *rsc, const char *pre_text, gboolean details); extern gboolean native_active(resource_t *rsc, gboolean all); extern void native_printw(resource_t *rsc, const char *pre_text, int *index); extern void native_html(resource_t *rsc, const char *pre_text, FILE *stream); extern void native_free(resource_t *rsc); extern rsc_state_t native_resource_state(resource_t *rsc); extern void native_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set); - + resource_t *rsc, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set); extern void group_unpack(resource_t *rsc, pe_working_set_t *data_set); extern resource_t *group_find_child(resource_t *rsc, const char *id); extern int group_num_allowed_nodes(resource_t *rsc); extern void group_color(resource_t *rsc, pe_working_set_t *data_set); extern void group_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void group_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void group_agent_constraints(resource_t *rsc); extern void group_rsc_colocation_lh(rsc_colocation_t *constraint); extern void group_rsc_colocation_rh( resource_t *rsc, rsc_colocation_t *constraint); extern void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void group_expand(resource_t *rsc, pe_working_set_t *data_set); extern void group_dump(resource_t *rsc, const char *pre_text, gboolean details); extern gboolean group_active(resource_t *rsc, gboolean all); extern void group_printw(resource_t *rsc, const char *pre_text, int *index); extern void group_html(resource_t *rsc, const char *pre_text, FILE *stream); extern void group_free(resource_t *rsc); extern rsc_state_t group_resource_state(resource_t *rsc); extern void group_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set); + resource_t *rsc, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set); extern void clone_unpack(resource_t *rsc, pe_working_set_t *data_set); extern resource_t *clone_find_child(resource_t *rsc, const char *id); extern int clone_num_allowed_nodes(resource_t *rsc); extern void clone_color(resource_t *rsc, pe_working_set_t *data_set); extern void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set); extern void clone_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void clone_agent_constraints(resource_t *rsc); extern void clone_rsc_colocation_lh(rsc_colocation_t *constraint); extern void clone_rsc_colocation_rh( resource_t *rsc, rsc_colocation_t *constraint); extern void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void clone_expand(resource_t *rsc, pe_working_set_t *data_set); extern void clone_dump(resource_t *rsc, const char *pre_text, gboolean details); extern gboolean clone_active(resource_t *rsc, gboolean all); extern void clone_printw(resource_t *rsc, const char *pre_text, int *index); extern void clone_html(resource_t *rsc, const char *pre_text, FILE *stream); extern void clone_free(resource_t *rsc); extern rsc_state_t clone_resource_state(resource_t *rsc); extern void clone_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set); + resource_t *rsc, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set); /* extern resource_object_functions_t resource_variants[]; */ extern resource_object_functions_t resource_class_functions[]; extern gboolean common_unpack( crm_data_t *xml_obj, resource_t **rsc, pe_working_set_t *data_set); extern void common_dump( resource_t *rsc, const char *pre_text, gboolean details); extern void common_printw(resource_t *rsc, const char *pre_text, int *index); extern void common_html(resource_t *rsc, const char *pre_text, FILE *stream); extern void common_free(resource_t *rsc); extern void native_add_running( resource_t *rsc, node_t *node, pe_working_set_t *data_set); extern gboolean is_active(rsc_to_node_t *cons); extern gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); extern void order_actions(action_t *lh, action_t *rh, order_constraint_t *order); extern void common_agent_constraints( GListPtr node_list, lrm_agent_t *agent, const char *id); extern void unpack_instance_attributes( crm_data_t *xml_obj, node_t *node, GHashTable *hash, const char **attr_filter, int attrs_length); extern const char *get_rsc_param(resource_t *rsc, const char *prop); extern void add_rsc_param(resource_t *rsc, const char *name, const char *value); extern void add_hash_param(GHashTable *hash, const char *name, const char *value); extern void hash2nvpair(gpointer key, gpointer value, gpointer user_data); extern void inherit_parent_attributes( crm_data_t *parent, crm_data_t *child, gboolean overwrite); #endif diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c index 4decb3978a..0699c4ccd4 100644 --- a/crm/pengine/graph.c +++ b/crm/pengine/graph.c @@ -1,493 +1,496 @@ -/* $Id: graph.c,v 1.56 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: graph.c,v 1.57 2005/08/10 08:55:03 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 update_action(action_t *action); gboolean update_action_states(GListPtr actions) { crm_debug_2("Updating %d actions", g_list_length(actions)); slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } #define UPDATE_THEM 1 gboolean update_action(action_t *action) { gboolean change = FALSE; enum action_tasks task = no_action; crm_debug_3("Processing action %d: %s", action->id, action->optional?"optional":"required"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, crm_debug_3("\tChecking action %d: %s/%s", other->action->id, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->type == pe_ordering_restart && action->rsc->start_pending == FALSE) { crm_debug_3("Upgrading %s constraint to %s", ordering_type2text(other->type), ordering_type2text(pe_ordering_manditory)); other->type = pe_ordering_manditory; } if(other->type != pe_ordering_manditory) { crm_debug_3("\t Ignoring: %s", ordering_type2text(other->type)); continue; } else if(action->optional || other->action->optional == FALSE){ crm_debug_3("\t Ignoring: %s/%s", other->action->optional?"-":"they are not optional", action->optional?"we are optional":"-"); continue; } else if(safe_str_eq(other->action->task, CRMD_ACTION_START)) { const char *interval = g_hash_table_lookup( action->extra, "interval"); int interval_i = 0; if(interval != NULL) { interval_i = atoi(interval); if(interval_i > 0) { crm_debug_3("Ignoring: start + recurring"); continue; } } } other->action->optional = FALSE; crm_debug_2("* Marking action %d manditory because of %d", other->action->id, action->id); update_action(other->action); ); slist_iter( other, action_wrapper_t, action->actions_after, lpc, if(action->pseudo == FALSE && action->runnable == FALSE) { if(other->action->runnable == FALSE) { crm_debug_2("Action %d already un-runnable", other->action->id); } else if(action->optional == FALSE) { other->action->runnable = FALSE; crm_debug_2("Marking action %d un-runnable" " because of %d", other->action->id, action->id); update_action(other->action); } } crm_debug_3("\t(Recover) Checking action %d: %s/%s", other->action->id, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->action->rsc == NULL) { continue; } else if(other->type == pe_ordering_recover) { if(other->action->rsc->restart_type != pe_restart_restart) { crm_debug_3("\t Ignoring: restart type %d", other->action->rsc->restart_type); continue; } } else if(other->type == pe_ordering_restart) { } else if(other->type == pe_ordering_postnotify) { CRM_DEV_ASSERT(action->rsc == other->action->rsc); if(crm_assert_failed) { continue; } } else { crm_debug_3("\t Ignoring: ordering %s", ordering_type2text(other->type)); continue; } if(other->action->optional == FALSE || action->optional) { crm_debug_3("\t Ignoring: %s/%s", action->optional?"we are optional":"-", other->action->optional?"-":"they are not optional"); continue; } task = text2task(action->task); switch(task) { case stop_rsc: case stopped_rsc: crm_debug_3("\t Ignoring: action %s", action->task); break; case start_rsc: case started_rsc: crm_debug_2("* (Recover) Marking action %d" " manditory because of %d", other->action->id, action->id); other->action->optional = FALSE; update_action(other->action); break; default: crm_debug_3("\t Ignoring: action %s", action->task); break; } ); if(change) { update_action(action); } crm_debug_3("Action %d: %s", action->id, change?"update":"untouched"); return change; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { /* add the stop to the before lists so it counts as a pre-req * for the shutdown */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, pe_ordering_manditory, data_set); ); return TRUE; } gboolean stonith_constraints(node_t *node, action_t *stonith_op, action_t *shutdown_op, pe_working_set_t *data_set) { GListPtr stop_actions = NULL; gboolean run_unprotected = TRUE; if(shutdown_op != NULL) { /* stop everything we can via shutdown_constraints() and then * shoot the node... the shutdown has been superceeded */ shutdown_op->pseudo = TRUE; shutdown_op->runnable = TRUE; /* shutdown before stonith */ /* Give any resources a chance to shutdown normally */ crm_debug_4("Adding shutdown (%d) as an input to stonith (%d)", shutdown_op->id, stonith_op->id); custom_action_order( NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, NULL, crm_strdup(CRM_OP_FENCE), stonith_op, pe_ordering_manditory, data_set); } /* * Make sure the stonith OP occurs before we start any shared resources */ slist_iter( rsc, resource_t, data_set->resources, lpc, slist_iter(action, action_t, rsc->actions, lpc2, if(action->needs != rsc_req_stonith) { continue; } if(stonith_op != NULL) { custom_action_order( NULL, crm_strdup(CRM_OP_FENCE), stonith_op, rsc, NULL, action, pe_ordering_manditory, data_set); } else if(run_unprotected == FALSE) { /* mark the start unrunnable */ action->runnable = FALSE; } else { pe_err("SHARED RESOURCE %s IS NOT PROTECTED:" " Stonith disabled", rsc->id); } ); ); /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(stonith_op != NULL) { char *key = stop_key(rsc); stop_actions = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, stop_actions, lpc2, if(node->details->online == FALSE || rsc->unclean) { /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, stop_key(rsc), NULL, pe_ordering_manditory, data_set); } else { /* stop healthy resources before the * stonith op */ custom_action_order( rsc, stop_key(rsc), NULL, NULL,crm_strdup(CRM_OP_FENCE),stonith_op, pe_ordering_manditory, data_set); } ); crm_debug_4("Adding stonith (%d) as an input to stop", stonith_op->id); /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_block) { */ /* /\* depend on the stop action which will fail *\/ */ /* pe_err("SHARED RESOURCE %s WILL REMAIN BLOCKED" */ /* " ON NODE %s UNTIL %s", */ /* rsc->id, node->details->uname, */ /* data_set->stonith_enabled?"QUORUM RETURNS":"CLEANED UP MANUALLY"); */ /* continue; */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_ignore) { */ /* /\* nothing to do here *\/ */ /* pe_err("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); */ /* continue; */ } ); return TRUE; } crm_data_t * action2xml(action_t *action, gboolean as_input) { gboolean needs_node_info = TRUE; crm_data_t * action_xml = NULL; crm_data_t * args_xml = NULL; char *action_id_s = NULL; if(action == NULL) { return NULL; } crm_debug_4("Dumping action %d as XML", action->id); if(safe_str_eq(action->task, CRM_OP_FENCE)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); needs_node_info = FALSE; } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); } else if(action->pseudo) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); needs_node_info = FALSE; } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } action_id_s = crm_itoa(action->id); crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); crm_free(action_id_s); if(action->rsc != NULL) { crm_xml_add( action_xml, XML_LRM_ATTR_RSCID, action->rsc->id); } crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); + crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); if(needs_node_info && action->node != NULL) { crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname); crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id); CRM_DEV_ASSERT(NULL != crm_element_value( action_xml, XML_LRM_ATTR_TARGET)); CRM_DEV_ASSERT(NULL != crm_element_value( action_xml, XML_LRM_ATTR_TARGET_UUID)); } crm_xml_add(action_xml, "allow_fail", action->failure_is_fatal?XML_BOOLEAN_FALSE:XML_BOOLEAN_TRUE); if(as_input) { return action_xml; } if(action->rsc != NULL && action->pseudo == FALSE) { crm_data_t *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); copy_in_properties(rsc_xml, action->rsc->xml); args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); g_hash_table_foreach(action->extra, hash2nvpair, args_xml); g_hash_table_foreach( action->rsc->parameters, hash2nvpair, args_xml); } else { args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); g_hash_table_foreach(action->extra, hash2nvpair, args_xml); } if(action->extra_xml != NULL) { add_node_copy(action_xml, action->extra_xml); } crm_log_xml_debug_2(action_xml, "dumped action"); return action_xml; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { int last_action = -1; char *syn_id = NULL; crm_data_t * syn = NULL; crm_data_t * set = NULL; crm_data_t * in = NULL; crm_data_t * input = NULL; crm_data_t * xml_action = NULL; if(action == NULL) { pe_err("Cannot dump NULL action"); return; } else if(action->optional) { crm_debug_5("action %d was optional", action->id); return; } else if(action->pseudo == FALSE && action->runnable == FALSE) { crm_debug_5("action %d was not runnable", action->id); return; } else if(action->dumped) { crm_debug_5("action %d was already dumped", action->id); return; } else if(action->pseudo || safe_str_eq(action->task, CRM_OP_FENCE) || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { /* skip the next two checks */ } else if(action->rsc != NULL && action->rsc->is_managed == FALSE) { pe_warn("action %d was for an unmanaged resource (%s)", action->id, action->rsc->id); return; } else { if(action->node == NULL) { pe_err("action %d was not allocated", action->id); log_action(LOG_DEBUG, "Unallocated action", action, FALSE); return; } else if(action->node->details->online == FALSE) { pe_err("action %d was scheduled for offline node", action->id); log_action(LOG_DEBUG, "Action for offline node", action, FALSE); return; } } action->dumped = TRUE; syn = create_xml_node(data_set->graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); syn_id = crm_itoa(data_set->num_synapse); crm_xml_add(syn, XML_ATTR_ID, syn_id); crm_free(syn_id); data_set->num_synapse++; xml_action = action2xml(action, FALSE); add_node_copy(set, xml_action); free_xml(xml_action); action->actions_before = g_list_sort( action->actions_before, sort_action_id); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(last_action == wrapper->action->id) { - crm_debug_2("Input %d duplicated", - wrapper->action->id); + crm_debug_2("Input (%d) %s duplicated", + wrapper->action->id, + wrapper->action->uuid); continue; } else if(wrapper->action->optional == TRUE) { - crm_debug_2("Input %d optional", - wrapper->action->id); + crm_debug_2("Input (%d) %s optional", + wrapper->action->id, + wrapper->action->uuid); continue; } CRM_DEV_ASSERT(last_action < wrapper->action->id); last_action = wrapper->action->id; input = create_xml_node(in, "trigger"); xml_action = action2xml(wrapper->action, TRUE); add_node_copy(input, xml_action); free_xml(xml_action); ); } diff --git a/crm/pengine/group.c b/crm/pengine/group.c index fd5419b19a..ed60417934 100644 --- a/crm/pengine/group.c +++ b/crm/pengine/group.c @@ -1,583 +1,581 @@ -/* $Id: group.c,v 1.31 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: group.c,v 1.32 2005/08/10 08:55:03 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); typedef struct group_variant_data_s { int num_children; GListPtr child_list; /* resource_t* */ resource_t *self; resource_t *first_child; resource_t *last_child; gboolean child_starting; gboolean child_stopping; } group_variant_data_t; #define get_group_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_group); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (group_variant_data_t *)rsc->variant_opaque; \ void group_unpack(resource_t *rsc, pe_working_set_t *data_set) { crm_data_t *xml_obj = rsc->xml; crm_data_t *xml_self = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); group_variant_data_t *group_data = NULL; resource_t *self = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(group_data, sizeof(group_variant_data_t)); group_data->num_children = 0; group_data->self = NULL; group_data->child_list = NULL; group_data->first_child = NULL; group_data->last_child = NULL; /* this is a bit of a hack - but simplifies everything else */ copy_in_properties(xml_self, xml_obj); if(common_unpack(xml_self, &self, data_set)) { group_data->self = self; self->restart_type = pe_restart_restart; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } xml_child_iter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; set_id(xml_native_rsc, rsc->id, -1); inherit_parent_attributes(xml_self, xml_native_rsc, TRUE); if(common_unpack(xml_native_rsc, &new_rsc, data_set)) { group_data->num_children++; group_data->child_list = g_list_append( group_data->child_list, new_rsc); group_data->last_child = new_rsc; if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } rsc_colocation_new("pe_group_internal_colo", pecs_must, group_data->self, new_rsc); crm_action_debug_3( print_resource("Added", new_rsc, FALSE)); } else { pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); } ); crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id); rsc->variant_opaque = group_data; } resource_t * group_find_child(resource_t *rsc, const char *id) { group_variant_data_t *group_data = NULL; if(rsc->variant == pe_group) { group_data = (group_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"group\" variant", rsc->id); return NULL; } return pe_find_resource(group_data->child_list, id); } int group_num_allowed_nodes(resource_t *rsc) { group_variant_data_t *group_data = NULL; if(rsc->variant == pe_native) { group_data = (group_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"native\" variant", rsc->id); return 0; } if(group_data->self == NULL) { return 0; } return group_data->self->fns->num_allowed_nodes(group_data->self); } void group_color(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } group_data->self->fns->color(group_data->self, data_set); } void group_update_pseudo_status(resource_t *parent, resource_t *child); void group_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *op = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); group_update_pseudo_status(rsc, child_rsc); ); op = start_action(group_data->self, NULL, !group_data->child_starting); op->pseudo = TRUE; op = custom_action(group_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !group_data->child_starting, data_set); op->pseudo = TRUE; op = stop_action(group_data->self, NULL, !group_data->child_stopping); op->pseudo = TRUE; op = custom_action(group_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !group_data->child_stopping, data_set); op->pseudo = TRUE; } void group_update_pseudo_status(resource_t *parent, resource_t *child) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, parent); if(group_data->child_stopping && group_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { group_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { group_data->child_starting = TRUE; } ); } void group_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); custom_action_order( group_data->self, stopped_key(group_data->self), NULL, group_data->self, start_key(group_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, order_restart(child_rsc); if(last_rsc != NULL) { order_start_start( last_rsc, child_rsc, pe_ordering_optional); order_stop_stop( child_rsc, last_rsc, pe_ordering_optional); } else { custom_action_order( child_rsc, stop_key(child_rsc), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); order_start_start(group_data->self, child_rsc, pe_ordering_optional); } last_rsc = child_rsc; ); if(last_rsc != NULL) { custom_action_order( last_rsc, start_key(last_rsc), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); order_stop_stop( group_data->self, last_rsc, pe_ordering_optional); } } void group_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; group_variant_data_t *group_data = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_colocation_rh(group_data->self, constraint); } void group_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { resource_t *rsc_lh = rsc; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing RH of constraint %s", constraint->id); crm_action_debug_3(print_resource("LHS", rsc_lh, TRUE)); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_colocation_rh(group_data->self, constraint); } void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); group_data->self->fns->rsc_order_lh(group_data->self, order); } void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_order_rh(lh_action, group_data->self, order); } void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); if(group_data->self != NULL) { group_data->self->fns->rsc_location(group_data->self, constraint); } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } void group_expand(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); group_data->self->fns->expand(group_data->self, data_set); if(group_data->self == NULL) { return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->expand(child_rsc, data_set); ); } gboolean group_active(resource_t *rsc, gboolean all) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void group_printw(resource_t *rsc, const char *pre_text, int *index) { #if CURSES_ENABLED const char *child_text = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } move(*index, 0); printw("Resource Group: %s\n", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, (*index)++; child_rsc->fns->printw(child_rsc, child_text, index); ); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void group_html(resource_t *rsc, const char *pre_text, FILE *stream) { const char *child_text = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } fprintf(stream, "Resource Group: %s\n", rsc->id); fprintf(stream, "
    \n"); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, fprintf(stream, "
  • \n"); child_rsc->fns->html(child_rsc, child_text, stream); fprintf(stream, "
  • \n"); ); fprintf(stream, "
\n"); } void group_dump(resource_t *rsc, const char *pre_text, gboolean details) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } common_dump(rsc, pre_text, details); group_data->self->fns->dump(group_data->self, pre_text, details); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->dump(child_rsc, pre_text, details); ); } void group_free(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(group_data->child_list, FALSE); free_xml(group_data->self->xml); if(group_data->self != NULL) { group_data->self->fns->free(group_data->self); } common_free(rsc); } void group_agent_constraints(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } rsc_state_t group_resource_state(resource_t *rsc) { rsc_state_t state = rsc_state_unknown; rsc_state_t last_state = rsc_state_unknown; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, last_state = child_rsc->fns->state(child_rsc); switch(last_state) { case rsc_state_unknown: case rsc_state_move: return last_state; break; case rsc_state_restart: CRM_DEV_ASSERT(state != rsc_state_stopping); CRM_DEV_ASSERT(state != rsc_state_stopped); /* CRM_DEV_ASSERT(state != rsc_state_active); */ state = last_state; break; case rsc_state_active: /* CRM_DEV_ASSERT(state != rsc_state_restart); */ CRM_DEV_ASSERT(state != rsc_state_stopping); if(last_state == rsc_state_unknown) { state = last_state; } break; case rsc_state_stopped: CRM_DEV_ASSERT(state != rsc_state_restart); CRM_DEV_ASSERT(state != rsc_state_starting); if(last_state == rsc_state_unknown) { state = last_state; } break; case rsc_state_starting: CRM_DEV_ASSERT(state != rsc_state_stopped); if(state != rsc_state_restart) { state = last_state; } break; case rsc_state_stopping: CRM_DEV_ASSERT(state != rsc_state_active); if(state != rsc_state_restart) { state = last_state; } break; } ); return state; } - void -group_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set) +group_create_notify_element(resource_t *rsc, action_t *op, crm_data_t *parent, + pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->create_notify_element( - child_rsc, op, parent, tagname, data_set); + child_rsc, op, parent, data_set); ); } diff --git a/crm/pengine/incarnation.c b/crm/pengine/incarnation.c index e1bc8d7781..973479a1cf 100644 --- a/crm/pengine/incarnation.c +++ b/crm/pengine/incarnation.c @@ -1,912 +1,973 @@ -/* $Id: incarnation.c,v 1.42 2005/08/08 13:07:52 andrew Exp $ */ +/* $Id: incarnation.c,v 1.43 2005/08/10 08:55:03 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 extern void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_max_node; int active_clones; gboolean interleave; gboolean ordered; + gboolean notify_confirm; + GListPtr child_list; /* resource_t* */ gboolean child_starting; gboolean child_stopping; } clone_variant_data_t; void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_clone); \ data = (clone_variant_data_t *)rsc->variant_opaque; void clone_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; crm_data_t * xml_obj_child = NULL; crm_data_t * xml_obj = rsc->xml; crm_data_t * xml_self = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); clone_variant_data_t *clone_data = NULL; resource_t *self = NULL; char *inc_max = NULL; const char *ordered = crm_element_value(xml_obj, XML_RSC_ATTR_ORDERED); const char *interleave = crm_element_value(xml_obj, XML_RSC_ATTR_INTERLEAVE); const char *max_clones = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_MAX); const char *max_clones_node = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(clone_data, sizeof(clone_variant_data_t)); - clone_data->child_list = NULL; - clone_data->interleave = FALSE; - clone_data->ordered = FALSE; - clone_data->active_clones = 0; + clone_data->child_list = NULL; + clone_data->interleave = FALSE; + clone_data->ordered = FALSE; + + clone_data->active_clones = 0; clone_data->clone_max = crm_atoi(max_clones, "1"); clone_data->clone_max_node = crm_atoi(max_clones_node,"1"); - + /* this is a bit of a hack - but simplifies everything else */ copy_in_properties(xml_self, xml_obj); xml_obj_child = find_xml_node(xml_obj, "operations", FALSE); if(xml_obj_child != NULL) { add_node_copy(xml_self, xml_obj_child); } - + xml_obj_child = find_xml_node(xml_obj, XML_CIB_TAG_GROUP, FALSE); if(xml_obj_child == NULL) { xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } CRM_DEV_ASSERT(xml_obj_child != NULL); if(crm_assert_failed) { return; } if(common_unpack(xml_self, &self, data_set)) { clone_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } - + if(crm_is_true(interleave)) { clone_data->interleave = TRUE; } if(crm_is_true(ordered)) { clone_data->ordered = TRUE; } +#if 0 + { + const char *confirm = crm_element_value( + xml_obj, "notify_confirm"); + clone_data->notify_confirm = crm_is_true(confirm); + } +#else + clone_data->notify_confirm = clone_data->self->notify; +#endif + inherit_parent_attributes(xml_self, xml_obj_child, FALSE); inc_max = crm_itoa(clone_data->clone_max); for(lpc = 0; lpc < clone_data->clone_max; lpc++) { resource_t *child_rsc = NULL; crm_data_t * child_copy = copy_xml(xml_obj_child); set_id(child_copy, rsc->id, lpc); if(common_unpack(child_copy, &child_rsc, data_set)) { char *inc_num = crm_itoa(lpc); clone_data->child_list = g_list_append( clone_data->child_list, child_rsc); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION, inc_num); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION_MAX, inc_max); crm_action_debug_3( print_resource("Added", child_rsc, FALSE)); crm_free(inc_num); } else { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); } } crm_free(inc_max); crm_debug_3("Added %d children to resource %s...", clone_data->clone_max, rsc->id); rsc->variant_opaque = clone_data; } resource_t * clone_find_child(resource_t *rsc, const char *id) { clone_variant_data_t *clone_data = NULL; if(rsc->variant == pe_clone) { clone_data = (clone_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"" XML_CIB_TAG_INCARNATION "\" variant", rsc->id); return NULL; } return pe_find_resource(clone_data->child_list, id); } int clone_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; clone_variant_data_t *clone_data = NULL; if(rsc->variant == pe_clone) { clone_data = (clone_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not an \"" XML_CIB_TAG_INCARNATION "\" variant", rsc->id); return 0; } /* what *should* we return here? */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, int tmp_num_nodes = child_rsc->fns->num_allowed_nodes(child_rsc); if(tmp_num_nodes > num_nodes) { num_nodes = tmp_num_nodes; } ); return num_nodes; } void clone_color(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0, lpc2 = 0, max_nodes = 0; resource_t *child_0 = NULL; resource_t *child_lh = NULL; resource_t *child_rh = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->self->is_managed == FALSE) { return; } child_0 = g_list_nth_data(clone_data->child_list, 0); max_nodes = rsc->fns->num_allowed_nodes(rsc); /* generate up to max_nodes * clone_node_max constraints */ lpc = 0; clone_data->active_clones = max_nodes * clone_data->clone_max_node; if(clone_data->active_clones > clone_data->clone_max) { clone_data->active_clones = clone_data->clone_max; } crm_info("Distributing %d (of %d) %s clones over %d nodes", clone_data->active_clones, clone_data->clone_max, rsc->id, max_nodes); for(; lpc < clone_data->active_clones && lpc < max_nodes; lpc++) { child_lh = g_list_nth_data(clone_data->child_list, lpc); for(lpc2 = lpc + 1; lpc2 < clone_data->active_clones; lpc2++) { child_rh = g_list_nth_data(clone_data->child_list,lpc2); if(lpc2 < max_nodes) { crm_debug_2("Clone %d will not run with %d", lpc, lpc2); rsc_colocation_new( "__clone_internal_must_not__", pecs_must_not, child_lh, child_rh); } else if((lpc2 % max_nodes) == lpc) { crm_debug_2("Clone %d can run with %d", lpc, lpc2); rsc_colocation_new( "__clone_internal_must__", pecs_must, child_lh, child_rh); } } for(; lpc2 < clone_data->clone_max; lpc2++) { child_rh = g_list_nth_data(clone_data->child_list,lpc2); crm_debug_2("Unrunnable: Clone %d will not run with %d", lpc2, lpc); rsc_colocation_new("__clone_internal_must_not__", pecs_must_not, child_lh, child_rh); } } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(lpc >= clone_data->active_clones) { crm_warn("Clone %s cannot be started", child_rsc->id); } child_rsc->fns->color(child_rsc, data_set); ); } void clone_update_pseudo_status(resource_t *parent, resource_t *child); void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *action = NULL; action_t *action_complete = NULL; resource_t *last_start_rsc = NULL; resource_t *last_stop_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); clone_update_pseudo_status(rsc, child_rsc); if(child_rsc->starting) { last_start_rsc = child_rsc; } if(child_rsc->stopping) { last_stop_rsc = child_rsc; } ); /* start */ action = start_action(clone_data->self, NULL, !clone_data->child_starting); action_complete = custom_action(clone_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !clone_data->child_starting, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; - + child_starting_constraints( clone_data, pe_ordering_optional, NULL, last_start_rsc, data_set); clone_create_notifications( - clone_data->self, action, action_complete, data_set); + rsc, action, action_complete, data_set); /* stop */ action = stop_action(clone_data->self, NULL, !clone_data->child_stopping); action_complete = custom_action(clone_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !clone_data->child_stopping, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; child_stopping_constraints( clone_data, pe_ordering_optional, NULL, last_stop_rsc, data_set); clone_create_notifications( - clone_data->self, action, action_complete, data_set); + rsc, action, action_complete, data_set); } void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set) { /* - * pre_notify -> pseudo_action -> (real actions) -> pseudo_action_complete -> post_notify + * pre_notify -> pre_notify_complete -> pseudo_action + * -> (real actions) -> pseudo_action_complete + * -> post_notify -> post_notify_complete * * if the pre_noitfy requires confirmation, * then a list of confirmations will be added as triggers * to pseudo_action in clone_expand() */ action_t *notify = NULL; + action_t *notify_complete = NULL; + enum action_tasks task; char *notify_key = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); if(rsc->notify == FALSE) { return; } + + task = text2task(action->task); /* create pre_notify */ - notify_key = generate_notify_key(rsc->id, "pre", action->task); - notify = custom_action(rsc, notify_key, + notify_key = generate_notify_key( + clone_data->self->id, "pre", action->task); + notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action->optional, data_set); add_hash_param(notify->extra, "notify_type", "pre"); add_hash_param(notify->extra, "notify_operation", action->task); - add_hash_param(notify->extra, "notify_key", notify_key); + if(clone_data->notify_confirm) { + add_hash_param(notify->extra, "notify_confirm", "yes"); + } else { + add_hash_param(notify->extra, "notify_confirm", "no"); + } + notify->pseudo = TRUE; + + /* create pre_notify_complete */ + notify_key = generate_notify_key( + clone_data->self->id, "confirmed-pre", action->task); + notify_complete = custom_action(clone_data->self, notify_key, + CRMD_ACTION_NOTIFIED, NULL, + action->optional, data_set); + add_hash_param(notify_complete->extra, "notify_type", "pre"); + add_hash_param(notify_complete->extra, "notify_operation", action->task); + if(clone_data->notify_confirm) { + add_hash_param(notify->extra, "notify_confirm", "yes"); + } else { + add_hash_param(notify->extra, "notify_confirm", "no"); + } notify->pseudo = TRUE; + notify_complete->pseudo = TRUE; + + /* pre_notify before pre_notify_complete */ + custom_action_order( + clone_data->self, NULL, notify, + clone_data->self, NULL, notify_complete, + pe_ordering_manditory, data_set); - /* pre_notify before action */ + /* pre_notify_complete before action */ custom_action_order( - rsc, NULL, notify, rsc, NULL, action, + clone_data->self, NULL, notify_complete, + clone_data->self, NULL, action, pe_ordering_manditory, data_set); + + action->pre_notify = notify; + action->pre_notified = notify_complete; /* create post_notify */ - notify_key = generate_notify_key(rsc->id, "post", action->task); - notify = custom_action(rsc, notify_key, + notify_key = generate_notify_key + (clone_data->self->id, "post", action->task); + notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action_complete->optional, data_set); add_hash_param(notify->extra, "notify_type", "post"); add_hash_param(notify->extra, "notify_operation", action->task); - add_hash_param(notify->extra, "notify_key", notify_key); + if(clone_data->notify_confirm) { + add_hash_param(notify->extra, "notify_confirm", "yes"); + } else { + add_hash_param(notify->extra, "notify_confirm", "no"); + } notify->pseudo = TRUE; - + /* action_complete before post_notify */ custom_action_order( - rsc, NULL, action_complete, rsc, NULL, notify, + clone_data->self, NULL, action_complete, + clone_data->self, NULL, notify, pe_ordering_postnotify, data_set); + + /* create post_notify_complete */ + notify_key = generate_notify_key( + clone_data->self->id, "confirmed-post", action->task); + notify_complete = custom_action(clone_data->self, notify_key, + CRMD_ACTION_NOTIFIED, NULL, + action->optional, data_set); + add_hash_param(notify_complete->extra, "notify_type", "pre"); + add_hash_param(notify_complete->extra, "notify_operation", action->task); + if(clone_data->notify_confirm) { + add_hash_param(notify->extra, "notify_confirm", "yes"); + } else { + add_hash_param(notify->extra, "notify_confirm", "no"); + } + notify_complete->pseudo = TRUE; + + /* post_notify before post_notify_complete */ + custom_action_order( + clone_data->self, NULL, notify, + clone_data->self, NULL, notify_complete, + pe_ordering_manditory, data_set); + + action->post_notify = notify; + action->post_notified = notify_complete; + + + if(safe_str_eq(action->task, CRMD_ACTION_STOP)) { + /* post_notify_complete before start */ + custom_action_order( + clone_data->self, NULL, notify_complete, + clone_data->self, start_key(clone_data->self), NULL, + pe_ordering_optional, data_set); + } } void clone_update_pseudo_status(resource_t *parent, resource_t *child) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, parent); if(clone_data->child_stopping && clone_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { clone_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { clone_data->child_starting = TRUE; } ); } void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child start before global started */ custom_action_order( last, start_key(last), NULL, clone_data->self, started_key(clone_data->self), NULL, type, data_set); } } else if(clone_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global start before first child start */ last = clone_data->self; } /* else: child/child relative start */ order_start_start(last, child, type); } else { crm_debug_4("Un-ordered version"); /* child start before global started */ custom_action_order( child, start_key(child), NULL, clone_data->self, started_key(clone_data->self), NULL, type, data_set); /* global start before child start */ /* order_start_start(clone_data->self, child, type); */ order_start_start( clone_data->self, child, pe_ordering_manditory); } } void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global stop before first child stop */ order_stop_stop(clone_data->self, last, pe_ordering_manditory); } } else if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative stop */ order_stop_stop(child, last, type); } else if(clone_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, clone_data->self, stopped_key(clone_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, clone_data->self, stopped_key(clone_data->self), NULL, type, data_set); /* global stop before child stop */ order_stop_stop(clone_data->self, child, type); } } void clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* global stopped before start */ custom_action_order( clone_data->self, stopped_key(clone_data->self), NULL, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_manditory, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, /* child stop before start */ order_restart(child_rsc); child_starting_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_stopping_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } void clone_rsc_colocation_lh(rsc_colocation_t *constraint) { gboolean do_interleave = FALSE; resource_t *rsc = constraint->rsc_lh; clone_variant_data_t *clone_data = NULL; clone_variant_data_t *clone_data_rh = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_clone_variant_data(clone_data, rsc); if(constraint->rsc_rh->variant == pe_clone) { get_clone_variant_data( clone_data_rh, constraint->rsc_rh); if(clone_data->clone_max_node != clone_data_rh->clone_max_node) { pe_err("Cannot interleave "XML_CIB_TAG_INCARNATION" %s and %s because" " they do not support the same number of" " resources per node", constraint->rsc_lh->id, constraint->rsc_rh->id); /* only the LHS side needs to be labeled as interleave */ } else if(clone_data->interleave) { do_interleave = TRUE; } } if(do_interleave) { resource_t *child_lh = NULL; resource_t *child_rh = NULL; resource_t *parent_rh = constraint->rsc_rh; GListPtr iter_lh = clone_data->child_list; GListPtr iter_rh = clone_data_rh->child_list; crm_debug_2("Interleaving %s with %s", constraint->rsc_lh->id, constraint->rsc_rh->id); /* If the resource have different numbers of incarnations, * then just do as many as are available */ while(iter_lh != NULL && iter_rh != NULL) { child_lh = iter_lh->data; child_rh = iter_rh->data; iter_lh = iter_lh->next; iter_rh = iter_rh->next; constraint->rsc_rh = child_rh; crm_debug_3("Colocating %s with %s", child_lh->id, child_rh->id); child_rh->fns->rsc_colocation_rh(child_lh, constraint); } /* restore the original RHS of the constraint */ constraint->rsc_rh = parent_rh; return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_colocations other than \"-INFINITY\"" " are not supported for non-interleaved" " "XML_CIB_TAG_INCARNATION" resources"); return; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_action_debug_3(print_resource("LHS", child_rsc, TRUE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void clone_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { clone_variant_data_t *clone_data = NULL; crm_debug_3("Processing RH of constraint %s", constraint->id); if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_dependencies other than \"must_not\" " "are not supported for incarnation resources"); return; } else { crm_action_debug_3(print_resource("LHS", rsc, FALSE)); } get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_action_debug_3(print_resource("RHS", child_rsc, FALSE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); clone_data->self->fns->rsc_order_lh(clone_data->self, order); } void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); clone_data->self->fns->rsc_order_rh(lh_action, clone_data->self, order); } void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); clone_data->self->fns->rsc_location(clone_data->self, constraint); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { - gboolean needs_notify = FALSE; - enum action_tasks task = no_action; crm_data_t *notify_xml = create_xml_node(NULL, "notify"); clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_2("Processing actions from %s", rsc->id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, slist_iter( - action, action_t, child_rsc->actions, lpc2, - - needs_notify = FALSE; - if(rsc->notify == FALSE) { - crm_debug_4("No notification requuired for %s", - action->uuid); - - } else if(!action->pseudo && !action->runnable) { - crm_debug_2("Skipping notifications for" - " unrunnable action %s", - action->uuid); - - } else if(!action->pseudo && action->optional) { - crm_debug_3("Skipping notifications for" - " optional action %s",action->uuid); - - } else { - task = text2task(action->task); - if(task == stop_rsc || task == start_rsc) { - needs_notify = TRUE; - } else { - crm_debug_4("No notification requuired" - " for %s operations", - action->task); - } - } - - if(needs_notify) { - crm_debug_2("Processing notifications for %s", - action->uuid); + op, action_t, clone_data->self->actions, lpc2, - child_rsc->fns->create_notify_element( - child_rsc, action, notify_xml, "target", - data_set); - } - + child_rsc->fns->create_notify_element( + child_rsc, op, notify_xml, data_set); ); + ); + + /* yes we DO need the second loop */ + slist_iter( + child_rsc, resource_t, clone_data->child_list, lpc, + child_rsc->fns->expand(child_rsc, data_set); ); - + slist_iter( action, action_t, clone_data->self->actions, lpc2, if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { action->extra_xml = notify_xml; } ); clone_data->self->fns->expand(clone_data->self, data_set); - free_xml(notify_xml); } gboolean clone_active(resource_t *rsc, gboolean all) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(all && child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void clone_printw(resource_t *rsc, const char *pre_text, int *index) { #if CURSES_ENABLED const char *child_text = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } move(*index, 0); printw("Clone: %s\n", rsc->id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, (*index)++; child_rsc->fns->printw(child_rsc, child_text, index); ); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void clone_html(resource_t *rsc, const char *pre_text, FILE *stream) { const char *child_text = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } fprintf(stream, "Clone: %s\n", rsc->id); fprintf(stream, "
    \n"); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, fprintf(stream, "
  • \n"); child_rsc->fns->html(child_rsc, child_text, stream); fprintf(stream, "
  • \n"); ); fprintf(stream, "
\n"); } void clone_dump(resource_t *rsc, const char *pre_text, gboolean details) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); common_dump(rsc, pre_text, details); clone_data->self->fns->dump( clone_data->self, pre_text, details); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->dump(child_rsc, pre_text, details); ); } void clone_free(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); free_xml(child_rsc->xml); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(clone_data->child_list, FALSE); free_xml(clone_data->self->xml); clone_data->self->fns->free(clone_data->self); common_free(rsc); } void clone_agent_constraints(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } rsc_state_t clone_resource_state(resource_t *rsc) { return rsc_state_unknown; } void -clone_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set) +clone_create_notify_element(resource_t *rsc, action_t *op, crm_data_t *parent, + pe_working_set_t *data_set) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->create_notify_element( - child_rsc, op, parent, tagname, data_set); + child_rsc, op, parent, data_set); ); } diff --git a/crm/pengine/native.c b/crm/pengine/native.c index 9a49db1f8f..606d8bce11 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,1533 +1,1673 @@ -/* $Id: native.c,v 1.69 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: native.c,v 1.70 2005/08/10 08:55:03 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 extern color_t *add_color(resource_t *rh_resource, color_t *color); gboolean native_choose_color(resource_t *lh_resource, color_t *no_color); void native_assign_color(resource_t *rsc, color_t *color); void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, const char *id, GListPtr nodes); void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void filter_nodes(resource_t *rsc); int num_allowed_nodes4color(color_t *color); void create_recurring_actions(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); action_t *create_recurring_action(resource_t *rsc, node_t *node, const char *action, const char *key); +void register_state( + resource_t *rsc, action_t *op, node_t *node, crm_data_t *parent); +void register_activity( + resource_t *rsc, action_t *op, node_t *node, crm_data_t *parent); +void pe_pre_notify( + resource_t *rsc, node_t *node, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set); +void pe_post_notify( + resource_t *rsc, node_t *node, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set); extern rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, double weight, node_t *node, pe_working_set_t *data_set); typedef struct native_variant_data_s { lrm_agent_t *agent; GListPtr running_on; /* node_t* */ color_t *color; GListPtr node_cons; /* rsc_to_node_t* */ GListPtr allowed_nodes; /* node_t* */ } native_variant_data_t; #define get_native_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_native); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (native_variant_data_t *)rsc->variant_opaque; void native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return; } slist_iter( a_node, node_t, native_data->running_on, lpc, CRM_DEV_ASSERT(a_node != NULL); if(safe_str_eq(a_node->details->id, node->details->id)) { return; } ); native_data->running_on = g_list_append(native_data->running_on, node); node->details->running_rsc = g_list_append( node->details->running_rsc, rsc); if(rsc->is_managed == FALSE) { rsc2node_new( "not_managed_default", rsc, INFINITY, node, data_set); return; } else if(rsc->stickiness > 0) { rsc2node_new("stickiness", rsc, INFINITY, node, data_set); } else if(rsc->stickiness < 0) { rsc2node_new("stickiness", rsc, -INFINITY, node, data_set); } if(g_list_length(native_data->running_on) > 1) { pe_warn("Resource %s is (potentially) active on %d nodes." " Latest: %s/%s", rsc->id, g_list_length(native_data->running_on), node->details->uname, node->details->id); } } void native_unpack(resource_t *rsc, pe_working_set_t *data_set) { crm_data_t * xml_obj = rsc->xml; native_variant_data_t *native_data = NULL; const char *version = crm_element_value(xml_obj, XML_ATTR_VERSION); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(native_data, sizeof(native_variant_data_t)); crm_malloc0(native_data->agent, sizeof(lrm_agent_t)); native_data->agent->class = crm_element_value(xml_obj, "class"); native_data->agent->type = crm_element_value(xml_obj, "type"); native_data->agent->version = version?version:"0.0"; native_data->color = NULL; native_data->allowed_nodes = NULL; native_data->node_cons = NULL; native_data->running_on = NULL; rsc->variant_opaque = native_data; } resource_t * native_find_child(resource_t *rsc, const char *id) { return NULL; } int native_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; native_variant_data_t *native_data = NULL; if(rsc->variant == pe_native) { native_data = (native_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"native\" variant", rsc->id); return 0; } if(native_data->color) { crm_debug_4("Colored case"); num_nodes = num_allowed_nodes4color(native_data->color); } else if(rsc->candidate_colors) { /* TODO: sort colors first */ color_t *color = g_list_nth_data(rsc->candidate_colors, 0); crm_debug_4("Candidate colors case"); num_nodes = num_allowed_nodes4color(color); } else { crm_debug_4("Default case"); slist_iter( this_node, node_t, native_data->allowed_nodes, lpc, crm_debug_3("Rsc %s Checking %s: %f", rsc->id, this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); } crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes); return num_nodes; } int num_allowed_nodes4color(color_t *color) { int num_nodes = 0; if(color->details->pending == FALSE) { if(color->details->chosen_node) { return 1; } return 0; } slist_iter( this_node, node_t, color->details->candidate_nodes, lpc, crm_debug_3("Checking %s: %f", this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); return num_nodes; } void native_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *new_color = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if( native_choose_color(rsc, data_set->no_color) ) { crm_debug_3("Colored resource %s with color %d", rsc->id, native_data->color->id); } else { if(native_data->allowed_nodes != NULL) { /* filter out nodes with a negative weight */ filter_nodes(rsc); new_color = create_color(data_set, rsc, native_data->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { pe_warn("Resource %s cannot run anywhere", rsc->id); print_resource("ERROR: No color", rsc, FALSE); native_assign_color(rsc, data_set->no_color); } } rsc->provisional = FALSE; } void create_recurring_actions(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { action_t *mon = NULL; char *key = NULL; const char *node_uname = NULL; const char *name = NULL; const char *value = NULL; int interval_ms = 0; gboolean is_optional = TRUE; GListPtr possible_matches = NULL; crm_debug_2("Creating recurring actions for %s", rsc->id); if(node != NULL) { node_uname = node->details->uname; } xml_child_iter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); value = crm_element_value(operation, "interval"); interval_ms = crm_get_msec(value); if(interval_ms <= 0) { continue; } key = generate_op_key(rsc->id, name, interval_ms); possible_matches = find_actions(rsc->actions, key, node); if(start != NULL) { is_optional = start->optional; } else { is_optional = TRUE; } /* start a monitor for an already active resource */ if(possible_matches == NULL) { is_optional = FALSE; } mon = custom_action(rsc, key, name, node, is_optional,data_set); if(start == NULL || start->runnable == FALSE) { crm_warn(" %s:\t(%s) (cancelled : start un-runnable)", mon->uuid, crm_str(node_uname)); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_warn(" %s:\t(%s) (cancelled : no node available)", mon->uuid, crm_str(node_uname)); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_info(" %s:\t(%s)", mon->uuid, crm_str(node_uname)); } custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_ordering_manditory, data_set); ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; action_t *stop = NULL; node_t *chosen = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(native_data->color != NULL) { chosen = native_data->color->details->chosen_node; } unpack_instance_attributes(rsc->xml, chosen, rsc->parameters, NULL, 0); if(chosen != NULL && g_list_length(native_data->running_on) == 0) { start = start_action(rsc, chosen, TRUE); if(start->runnable) { crm_info("Start resource %s\t(%s)", rsc->id, chosen->details->uname); start->optional = FALSE; start->rsc->start_pending = TRUE; } } else if(g_list_length(native_data->running_on) > 1) { pe_err("Attempting recovery of resource %s", rsc->id); if(rsc->recovery_type == recovery_stop_start || rsc->recovery_type == recovery_stop_only) { slist_iter( node, node_t, native_data->running_on, lpc, pe_warn("Stop resource %s\t(%s) (recovery)", rsc->id, node->details->uname); stop = stop_action(rsc, node, FALSE); ); } if(rsc->recovery_type == recovery_stop_start && chosen) { /* if one of the "stops" is for a node outside * our partition, then this will block anyway */ start = start_action(rsc, chosen, FALSE); if(start->runnable) { pe_warn("Recover resource %s\t(%s)", rsc->id, chosen->details->uname); } /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); } if(rsc->recovery_type == recovery_block) { pe_warn("RESOURCE %s WILL REMAIN ACTIVE ON MULTIPLE" " NODES PENDING MANUAL INTERVENTION", rsc->id); slist_iter( node, node_t, native_data->running_on, lpc, pe_warn("Resource %s active on %s", rsc->id, node->details->uname); ); } } else if(g_list_length(native_data->running_on) == 1) { node_t *node = native_data->running_on->data; crm_debug_2("Stop%s of %s", chosen?" and restart":"", rsc->id); CRM_DEV_ASSERT(node != NULL); if(chosen == NULL) { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); stop_action(rsc, node, FALSE); } else if(safe_str_eq(node->details->id, chosen->details->id)) { stop = stop_action(rsc, node, TRUE); start = start_action(rsc, chosen, TRUE); if(start->runnable == FALSE) { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); stop->optional = FALSE; } else if(rsc->recover) { crm_info("Restart resource %s\t(%s)", rsc->id, node->details->uname); /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); start->optional = FALSE; stop->optional = FALSE; } else { crm_info("Leave resource %s\t(%s)", rsc->id, node->details->uname); if(stop->optional == FALSE) { start->optional = FALSE; } else if(rsc->start_pending) { start->optional = FALSE; } } } else { /* move */ stop = stop_action(rsc, node, FALSE); start = start_action(rsc, chosen, FALSE); if(start->runnable) { crm_info("Move resource %s\t(%s -> %s)", rsc->id, node->details->uname, chosen->details->uname); } else { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); } /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); } } create_recurring_actions(rsc, start, chosen, data_set); } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); order_restart(rsc); } void native_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } constraint->rsc_rh->fns->rsc_colocation_rh(rsc, constraint); } void native_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { gboolean do_check = FALSE; gboolean update_lh = FALSE; gboolean update_rh = FALSE; resource_t *rsc_lh = rsc; resource_t *rsc_rh = constraint->rsc_rh; native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); crm_debug_2("%sColocating %s with %s", constraint->strength == pecs_must?"":"Anti-", rsc_lh->id, rsc_rh->id); if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_debug_4("Skipping constraint type %d", constraint->strength); return; } if(rsc_lh->provisional && rsc_rh->provisional) { if(constraint->strength == pecs_must) { /* update effective_priorities */ native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); } else { /* nothing */ crm_debug_4( "Skipping constraint, both sides provisional"); } return; } else if( (!rsc_lh->provisional) && (!rsc_rh->provisional) && (!native_data_lh->color->details->pending) && (!native_data_rh->color->details->pending) ) { /* error check */ do_check = TRUE; if(rsc_lh->effective_priority < rsc_rh->effective_priority) { update_lh = TRUE; } else if(rsc_lh->effective_priority > rsc_rh->effective_priority) { update_rh = TRUE; } else { update_lh = TRUE; update_rh = TRUE; } } else if(rsc_lh->provisional == FALSE && native_data_lh->color->details->pending == FALSE) { /* update _them_ : postproc color version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE && native_data_rh->color->details->pending == FALSE) { /* update _us_ : postproc color alt version */ update_lh = TRUE; } else if(rsc_lh->provisional == FALSE) { /* update _them_ : preproc version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE) { /* update _us_ : postproc version */ update_lh = TRUE; } else { pe_warn("Un-expected combination of inputs"); return; } if(update_lh) { crm_debug_4("Updating LHS"); } if(update_rh) { crm_debug_4("Updating RHS"); } if(do_check) { if(native_constraint_violated( rsc_lh, rsc_rh, constraint) == FALSE) { crm_debug_4("Constraint satisfied"); return; } /* else constraint cant be satisified */ pe_warn("Constraint %s could not be satisfied", constraint->id); if(update_lh) { pe_warn("Marking resource %s unrunnable as a result", rsc_lh->id); rsc_lh->runnable = FALSE; } if(update_rh) { pe_warn("Marking resource %s unrunnable as a result", rsc_rh->id); rsc_rh->runnable = FALSE; } } if(constraint->strength == pecs_must) { native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); return; } else if(constraint->strength != pecs_must_not) { /* unknown type */ pe_err("Unknown constraint type %d", constraint->strength); return; } native_rsc_colocation_rh_mustnot(rsc_lh, update_lh,rsc_rh, update_rh); } void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order) { GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; crm_debug_3("Processing LH of ordering constraint %d", order->id); if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL && lh_rsc != NULL) { #if 0 /* this should be safe to remove */ if(order->strength == pecs_must) { crm_debug_4("No LH-Side (%s/%s) found for constraint..." " creating", lh_rsc->id, order->lh_action_task); pe_err("BROKEN CODE"); custom_action( lh_rsc, order->lh_action_task, NULL, NULL); } #endif lh_actions = find_actions( lh_rsc->actions, order->lh_action_task, NULL); if(lh_actions == NULL) { crm_debug_4("No LH-Side (%s/%s) found for constraint", lh_rsc->id, order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } } else { pe_warn("No LH-Side (%s) specified for constraint", order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } slist_iter( lh_action_iter, action_t, lh_actions, lpc, resource_t *rh_rsc = order->rh_rsc; if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { rh_rsc->fns->rsc_order_rh( lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions(lh_action_iter, order->rh_action, order); } ); pe_free_shallow_adv(lh_actions, FALSE); } void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { GListPtr rh_actions = NULL; action_t *rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_append(NULL, rh_action); } else if(rh_action == NULL && rsc != NULL) { rh_actions = find_actions( rsc->actions, order->rh_action_task, NULL); if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id, order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } } else if(rh_action == NULL) { crm_debug_4("No RH-Side (%s) specified for constraint..." " ignoring", order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } slist_iter( rh_action_iter, action_t, rh_actions, lpc, order_actions(lh_action, rh_action_iter, order); ); pe_free_shallow_adv(rh_actions, FALSE); } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr or_list; native_variant_data_t *native_data = NULL; crm_action_debug_3(print_rsc_to_node("Applying", constraint, FALSE)); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } get_native_variant_data(native_data, rsc); native_data->node_cons = g_list_append(native_data->node_cons, constraint); if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } crm_action_debug_3(print_resource("before update", rsc,TRUE)); or_list = node_list_or( native_data->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(native_data->allowed_nodes); native_data->allowed_nodes = or_list; slist_iter(node_rh, node_t, constraint->node_list_rh, lpc, native_update_node_weight( rsc, constraint, node_rh->details->uname, native_data->allowed_nodes)); crm_action_debug_3(print_resource("after update", rsc, TRUE)); } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, data_set); ); } gboolean native_active(resource_t *rsc, gboolean all) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); slist_iter( a_node, node_t, native_data->running_on, lpc, if(a_node->details->online == FALSE) { crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname); } else if(a_node->details->unclean) { crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname); } else { crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname); return TRUE; } ); return FALSE; } void native_printw(resource_t *rsc, const char *pre_text, int *index) { #if CURSES_ENABLED native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); common_printw(rsc, pre_text, index); if(rsc->is_managed == FALSE) { printw(" (unmanaged) "); } if(g_list_length(native_data->running_on) == 0) { printw("NOT ACTIVE"); } else if(g_list_length(native_data->running_on) == 1) { node_t *node = native_data->running_on->data; printw("%s (%s)", node->details->uname, node->details->id); if(rsc->unclean) { printw(" FAILED"); } } else if(g_list_length(native_data->running_on) == 1) { printw("["); slist_iter(node, node_t, native_data->running_on, lpc, if(lpc > 0) { printw(", "); } printw("%s (%s)", node->details->uname, node->details->id); ); printw("]"); } printw("\n"); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void native_html(resource_t *rsc, const char *pre_text, FILE *stream) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(rsc->is_managed == FALSE) { fprintf(stream, ""); } common_html(rsc, pre_text, stream); if(rsc->is_managed == FALSE) { fprintf(stream, " (unmanaged) "); } if(rsc->unclean) { fprintf(stream, ""); } else if(g_list_length(native_data->running_on) == 0) { fprintf(stream, ""); } else if(g_list_length(native_data->running_on) > 1) { fprintf(stream, ""); } else { fprintf(stream, ""); } if(g_list_length(native_data->running_on) == 0) { fprintf(stream, "NOT ACTIVE"); } else if(g_list_length(native_data->running_on) == 1) { node_t *node = native_data->running_on->data; fprintf(stream, "%s (%s)", node->details->uname, node->details->id); } else if(g_list_length(native_data->running_on) > 1) { fprintf(stream, "
    \n"); slist_iter(node, node_t, native_data->running_on, lpc, fprintf(stream, "
  • %s (%s)
  • \n", node->details->uname, node->details->id); ); fprintf(stream, "
\n"); } fprintf(stream, "

\n"); } void native_dump(resource_t *rsc, const char *pre_text, gboolean details) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); common_dump(rsc, pre_text, details); crm_debug_4("\t%d candidate colors, %d allowed nodes," " %d rsc_cons and %d node_cons", g_list_length(rsc->candidate_colors), g_list_length(native_data->allowed_nodes), g_list_length(rsc->rsc_cons), g_list_length(native_data->node_cons)); if(details) { crm_debug_4("\t=== Actions"); slist_iter( action, action_t, rsc->actions, lpc, print_action("\trsc action: ", action, FALSE); ); crm_debug_4("\t=== Colors"); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); crm_debug_4("\t=== Allowed Nodes"); slist_iter( node, node_t, native_data->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void native_free(resource_t *rsc) { native_variant_data_t *native_data = (native_variant_data_t *)rsc->variant_opaque; crm_debug_4("Freeing Allowed Nodes & Agent"); crm_free(native_data->color); pe_free_shallow(native_data->allowed_nodes); crm_free(native_data->agent); common_free(rsc); } void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; gboolean do_merge = FALSE; GListPtr old_list = NULL; GListPtr merged_node_list = NULL; float max_pri = rsc_lh->effective_priority; if(max_pri < rsc_rh->effective_priority) { max_pri = rsc_rh->effective_priority; } rsc_lh->effective_priority = max_pri; rsc_rh->effective_priority = max_pri; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); if(native_data_lh->color && native_data_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->color->details->candidate_nodes, native_data_rh->color->details->candidate_nodes, TRUE); } else if(native_data_lh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->color->details->candidate_nodes, native_data_rh->allowed_nodes, TRUE); } else if(native_data_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->allowed_nodes, native_data_rh->color->details->candidate_nodes, TRUE); } if(update_lh && rsc_rh != rsc_lh) { CRM_DEV_ASSERT(native_data_lh->color != native_data_rh->color); crm_free(native_data_lh->color); rsc_lh->runnable = rsc_rh->runnable; rsc_lh->provisional = rsc_rh->provisional; native_data_lh->color = copy_color(native_data_rh->color); } if(update_rh && rsc_rh != rsc_lh) { CRM_DEV_ASSERT(native_data_lh->color != native_data_rh->color); crm_free(native_data_rh->color); rsc_rh->runnable = rsc_lh->runnable; rsc_rh->provisional = rsc_lh->provisional; native_data_rh->color = copy_color(native_data_lh->color); } if((update_rh || update_lh) && do_merge) { crm_debug_4("Merging candidate nodes"); old_list = native_data_rh->color->details->candidate_nodes; native_data_rh->color->details->candidate_nodes = merged_node_list; pe_free_shallow(old_list); } crm_debug_4("Finished processing pecs_must constraint"); } void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { color_t *color_lh = NULL; color_t *color_rh = NULL; native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); crm_debug_4("Processing pecs_must_not constraint"); /* pecs_must_not */ if(update_lh) { color_rh = native_data_rh->color; if(rsc_lh->provisional) { color_lh = find_color( rsc_lh->candidate_colors, color_rh); rsc_lh->candidate_colors = g_list_remove( rsc_lh->candidate_colors, color_lh); crm_action_debug_3( print_color("Removed LH", color_lh, FALSE)); crm_action_debug_3( print_resource("Modified LH", rsc_lh, TRUE)); crm_free(color_lh); } else if(native_data_lh->color && native_data_lh->color->details->pending) { node_t *node_lh = NULL; color_lh = native_data_lh->color; node_lh = pe_find_node( color_lh->details->candidate_nodes, safe_val5(NULL, color_rh, details, chosen_node, details, uname)); color_lh->details->candidate_nodes = g_list_remove( color_lh->details->candidate_nodes, node_lh); crm_action_debug_3( print_node("Removed LH", node_lh, FALSE)); crm_action_debug_3( print_color("Modified LH", color_lh, FALSE)); crm_free(node_lh); } else { /* error, rsc marked as unrunnable above */ pe_warn("lh else"); } } if(update_rh) { color_lh = native_data_lh->color; if(rsc_rh->provisional) { color_rh = find_color( rsc_rh->candidate_colors, color_lh); rsc_rh->candidate_colors = g_list_remove( rsc_rh->candidate_colors, color_rh); crm_action_debug_3( print_color("Removed RH", color_rh, FALSE)); crm_action_debug_3( print_resource("Modified RH", rsc_rh, TRUE)); crm_free(color_rh); } else if(native_data_rh->color && native_data_rh->color->details->pending) { node_t *node_rh = NULL; color_rh = native_data_rh->color; node_rh = pe_find_node( color_rh->details->candidate_nodes, safe_val5(NULL, color_lh, details, chosen_node, details, uname)); color_rh->details->candidate_nodes = g_list_remove( color_rh->details->candidate_nodes, node_rh); crm_action_debug_3( print_node("Removed RH", node_rh, FALSE)); crm_action_debug_3( print_color("Modified RH", color_rh, FALSE)); crm_free(node_rh); } else { /* error, rsc marked as unrunnable above */ pe_warn("rh else"); } } } void native_agent_constraints(resource_t *rsc) { } gboolean native_choose_color(resource_t *rsc, color_t *no_color) { GListPtr sorted_colors = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(rsc->runnable == FALSE) { native_assign_color(rsc, no_color); } if(rsc->provisional == FALSE) { return !rsc->provisional; } sorted_colors = g_list_sort( rsc->candidate_colors, sort_color_weight); rsc->candidate_colors = sorted_colors; crm_debug_3("Choose a color from %d possibilities", g_list_length(sorted_colors)); slist_iter( this_color, color_t, rsc->candidate_colors, lpc, GListPtr intersection = NULL; GListPtr minus = NULL; int len = 0; if(this_color == NULL) { pe_err("color was NULL"); continue; } else if(rsc->effective_priority < this_color->details->highest_priority) { minus = node_list_minus( this_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); len = g_list_length(minus); pe_free_shallow(minus); if(len > 0) { native_assign_color(rsc, this_color); break; } } else { intersection = node_list_and( this_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); len = g_list_length(intersection); pe_free_shallow(intersection); if(len != 0) { native_assign_color(rsc, this_color); break; } } ); return !rsc->provisional; } void native_assign_color(resource_t *rsc, color_t *color) { color_t *local_color = add_color(rsc, color); GListPtr intersection = NULL; GListPtr old_list = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); native_data->color = copy_color(local_color); rsc->provisional = FALSE; if(local_color != NULL) { (local_color->details->num_resources)++; local_color->details->allocated_resources = g_list_append( local_color->details->allocated_resources,rsc); intersection = node_list_and( local_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); old_list = local_color->details->candidate_nodes; pe_free_shallow(old_list); local_color->details->candidate_nodes = intersection; crm_debug_3("Colored resource %s with new color %d", rsc->id, native_data->color->id); crm_action_debug_3( print_resource("Colored Resource", rsc, TRUE)); } else { pe_err("local color was NULL"); } return; } void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, const char *id, GListPtr nodes) { node_t *node_rh = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); node_rh = pe_find_node(native_data->allowed_nodes, id); if(node_rh == NULL) { pe_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons->weight <= -INFINITY) { pe_err("Constraint %s mixes +/- INFINITY", cons->id); } else if(node_rh->weight <= -INFINITY && cons->weight >= INFINITY) { pe_err("Constraint %s mixes +/- INFINITY", cons->id); } if(node_rh->fixed) { /* warning */ crm_debug_2("Constraint %s is irrelevant as the" " weight of node %s is fixed as %f.", cons->id, node_rh->details->uname, node_rh->weight); return; } if(cons->weight >= INFINITY && cons->weight <= -INFINITY) { crm_debug_3("Constraint %s (%f): node %s weight %f.", cons->id, cons->weight, node_rh->details->uname, node_rh->weight); } else if(cons->weight <= -INFINITY) { crm_debug_3("Constraint %s (-INFINITY): node %s weight %f.", cons->id, node_rh->details->uname, node_rh->weight); } else { crm_debug_3("Constraint %s (+INFINITY): node %s weight %f.", cons->id, node_rh->details->uname, node_rh->weight); } node_rh->weight = merge_weights(node_rh->weight, cons->weight); if(node_rh->weight < 0) { node_rh->fixed = TRUE; } crm_action_debug_3(print_node("Updated", node_rh, FALSE)); return; } gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; GListPtr result = NULL; color_t *color_lh = NULL; color_t *color_rh = NULL; GListPtr candidate_nodes_lh = NULL; GListPtr candidate_nodes_rh = NULL; gboolean matched = FALSE; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); color_lh = native_data_lh->color; color_rh = native_data_rh->color; if(constraint->strength == pecs_must_not) { matched = TRUE; } if(rsc_lh->provisional || rsc_rh->provisional) { return FALSE; } if(color_lh->details->pending && color_rh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = color_rh->details->candidate_nodes; } else if(color_lh->details->pending == FALSE && color_rh->details->pending == FALSE) { if(color_lh == NULL && color_rh == NULL) { return matched; } else if(color_lh == NULL || color_rh == NULL) { return !matched; } else if(color_lh->details->chosen_node == NULL && color_rh->details->chosen_node == NULL) { return matched; } else if(color_lh->details->chosen_node == NULL || color_rh->details->chosen_node == NULL) { return !matched; } else if(safe_str_eq( color_lh->details->chosen_node->details->id, color_rh->details->chosen_node->details->id)) { return matched; } return !matched; } else if(color_lh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = g_list_append( NULL, color_rh->details->chosen_node); } else if(color_rh->details->pending) { candidate_nodes_rh = color_rh->details->candidate_nodes; candidate_nodes_lh = g_list_append( NULL, color_lh->details->chosen_node); } result = node_list_and(candidate_nodes_lh, candidate_nodes_rh, TRUE); if(g_list_length(result) == 0 && constraint->strength == pecs_must) { /* free result */ return TRUE; } return FALSE; } /* * Remove any nodes with a -ve weight */ void filter_nodes(resource_t *rsc) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); crm_action_debug_3(print_resource("Filtering nodes for", rsc, FALSE)); slist_iter( node, node_t, native_data->allowed_nodes, lpc, if(node == NULL) { pe_err("Invalid NULL node"); } else if(node->weight < 0.0 || node->details->shutdown || node->details->online == FALSE || node->details->type == node_ping) { crm_action_debug_3(print_node("Removing", node, FALSE)); native_data->allowed_nodes = g_list_remove(native_data->allowed_nodes, node); crm_free(node); lpc = -1; /* restart the loop */ } ); } rsc_state_t native_resource_state(resource_t *rsc) { enum action_tasks task = no_action; rsc_state_t state = rsc_state_unknown; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); task = text2task(action->task); if(action->optional) { continue; } if(task == stop_rsc) { if(state == rsc_state_starting) { state = rsc_state_restart; break; } else { state = rsc_state_stopping; } } else if(task == start_rsc) { if(state == rsc_state_stopping) { state = rsc_state_restart; break; } else { state = rsc_state_starting; } } ); if(native_data->running_on != NULL) { node_t *chosen = NULL; node_t *node = native_data->running_on->data; if(native_data->color != NULL) { chosen = native_data->color->details->chosen_node; } if(state == rsc_state_unknown) { state = rsc_state_active; } else if(state == rsc_state_restart) { CRM_DEV_ASSERT(chosen != NULL && node != NULL); if(crm_assert_failed) { crm_err("State for %s is unreliable", rsc->id); } else if(safe_str_neq(node->details->id, chosen->details->id)) { state = rsc_state_move; } } } else if(state == rsc_state_unknown) { state = rsc_state_stopped; } return state; } + void -native_create_notify_element( - resource_t *rsc, action_t *op, crm_data_t *parent, - const char *tagname, pe_working_set_t *data_set) +native_create_notify_element(resource_t *rsc, action_t *op, crm_data_t *parent, + pe_working_set_t *data_set) { -/* char *key = NULL; */ - int trigger_id = -1; - crm_data_t *trigger = NULL; - - node_t *node = NULL; node_t *next = NULL; node_t *current = NULL; - enum action_tasks task = text2task(op->task); + enum action_tasks task; rsc_state_t state = rsc->fns->state(rsc); native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(native_data->color != NULL) { next = native_data->color->details->chosen_node; } if(native_data->running_on != NULL) { current = native_data->running_on->data; } + + if(op->pre_notify == NULL || op->post_notify == NULL) { + /* no notifications required */ + crm_debug_4("No notificaitons required for %s", op->task); + return; + } + + crm_debug_2("Notificaitons required for %s", op->task); + + task = text2task(op->task); - node = next; switch(state) { case rsc_state_active: - case rsc_state_restart: + pe_pre_notify(rsc, current, op, parent, data_set); + pe_post_notify(rsc, current, op, parent, data_set); + register_state(rsc, op, current, parent); break; case rsc_state_move: if(task == stop_rsc) { - node = current; - } + pe_pre_notify(rsc, current, op,parent,data_set); + register_activity(rsc, op, current, parent); + } else { + pe_post_notify(rsc, next, op, parent, data_set); + register_activity(rsc, op, next, parent); + } break; - case rsc_state_starting: + case rsc_state_restart: + register_activity(rsc, op, current, parent); if(task == stop_rsc) { - node = NULL; + pe_pre_notify(rsc, current, op, parent, data_set); + } else { + pe_post_notify(rsc, current,op,parent,data_set); } break; - case rsc_state_stopping: - node = current; + case rsc_state_starting: if(task != stop_rsc) { - node = NULL; + register_activity(rsc, op, next, parent); + pe_post_notify(rsc, next, op, parent, data_set); } break; - case rsc_state_stopped: - node = NULL; + case rsc_state_stopping: + if(task == stop_rsc) { + register_activity(rsc, op, current, parent); + pe_pre_notify(rsc, current, op,parent,data_set); + } break; + case rsc_state_stopped: case rsc_state_unknown: - node = NULL; + return; break; } +} - if(node == NULL) { - crm_debug_2("No %s created for %s: %s (%s)", - tagname, op->uuid, rsc->id, rsc_state2text(state)); - return; - } - crm_debug_2("Creating %s for %s: %s (%s)", - tagname, op->uuid, rsc->id, rsc_state2text(state)); +void +register_activity( + resource_t *rsc, action_t *op, node_t *node, crm_data_t *parent) +{ + crm_data_t *target = NULL; +/* const char *value = NULL; */ + +/* value = g_hash_table_lookup(op->extra, "notify_type"); */ +/* if(safe_str_neq(value, "pre")) { */ +/* /\* only add once *\/ */ +/* return; */ +/* } */ + + CRM_DEV_ASSERT(node != NULL); - if(safe_str_neq(tagname, "target")) { - trigger_id = data_set->action_id++; + if(find_entity(parent, op->task, rsc->id) != NULL) { + /* only add once */ + return; } -/* key = generate_notify_key(rsc->id, op->task, 0); */ + crm_debug_3("Creating entry for %s: %s (%s)",op->uuid,rsc->id,op->task); + + target = create_xml_node(parent, op->task); + crm_xml_add(target, XML_ATTR_ID, rsc->id); + crm_xml_add(target, XML_LRM_ATTR_TARGET, node->details->uname); + crm_xml_add(target, XML_LRM_ATTR_TARGET_UUID, node->details->id); +} - trigger = create_xml_node(parent, tagname); - if(trigger_id != -1) { - crm_xml_add_int(trigger, XML_ATTR_ID, trigger_id); - } else { - crm_xml_add_int(trigger, XML_ATTR_ID, op->id); +void +register_state( + resource_t *rsc, action_t *op, node_t *node, crm_data_t *parent) +{ + crm_data_t *target = NULL; +/* const char *value = NULL; */ + +/* value = g_hash_table_lookup(op->extra, "notify_type"); */ +/* if(safe_str_neq(value, "pre")) { */ +/* /\* only add once *\/ */ +/* return; */ +/* } */ + + CRM_DEV_ASSERT(node != NULL); + + if(find_entity(parent, "peer", rsc->id) != NULL) { + /* only add once */ + return; } - crm_xml_add(trigger, XML_LRM_ATTR_RSCID, rsc->id); + crm_debug_3("Creating peer entry for %s: %s (%s)", + op->uuid, rsc->id, op->task); + + target = create_xml_node(parent, "peer"); + crm_xml_add(target, XML_ATTR_ID, rsc->id); + crm_xml_add(target, XML_LRM_ATTR_TARGET, node->details->uname); + crm_xml_add(target, XML_LRM_ATTR_TARGET_UUID, node->details->id); +} - crm_xml_add(trigger, XML_LRM_ATTR_TASK, op->task); - crm_xml_add(trigger, XML_LRM_ATTR_TARGET, node->details->uname); - crm_xml_add(trigger, XML_LRM_ATTR_TASK_UUID, op->uuid); - crm_xml_add(trigger, XML_LRM_ATTR_TARGET_UUID, node->details->id); +static void dup_attr(gpointer key, gpointer value, gpointer user_data) +{ + g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); +} - if(trigger_id != -1) { -/* crm_xml_add(trigger, "notify_task", notify_task); */ - crm_xml_add(trigger, "allow_fail", "false"); +static void +pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm, + crm_data_t *parent, pe_working_set_t *data_set) +{ + char *key = NULL; + action_t *trigger = NULL; + action_wrapper_t *wrapper = NULL; + const char *value = NULL; + const char *task = NULL; + + if(op == NULL || confirm == NULL) { + return; } + + CRM_DEV_ASSERT(node != NULL); + + value = g_hash_table_lookup(op->extra, "notify_type"); + task = g_hash_table_lookup(op->extra, "notify_operation"); + + crm_debug_2("Creating actions for %s: %s (%s-%s)", + op->uuid, rsc->id, value, task); + + key = generate_notify_key(rsc->id, value, task); + + trigger = custom_action( + rsc, key, op->task, node, op->optional, data_set); + g_hash_table_foreach(op->extra, dup_attr, trigger->extra); + trigger->extra_xml = parent; + + /* pseudo_notify before notify */ + crm_debug_3("Ordering %s before %s (%d->%d)", + op->uuid, trigger->uuid, trigger->id, op->id); + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = op; + wrapper->type = pe_ordering_manditory; + + trigger->actions_before = g_list_append( + trigger->actions_before, wrapper); + + wrapper = NULL; + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = trigger; + wrapper->type = pe_ordering_manditory; + op->actions_after = g_list_append( + op->actions_after, wrapper); + + /* notify before pseudo_notified */ + crm_debug_3("Ordering %s before %s (%d->%d)", + trigger->uuid, confirm->uuid, confirm->id, trigger->id); + value = g_hash_table_lookup(op->extra, "notify_confirm"); + if(crm_is_true(value)) { + wrapper = NULL; + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = trigger; + wrapper->type = pe_ordering_manditory; + confirm->actions_before = g_list_append( + confirm->actions_before, wrapper); + + wrapper = NULL; + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = confirm; + wrapper->type = pe_ordering_manditory; + trigger->actions_after = g_list_append( + trigger->actions_after, wrapper); + } } + +void +pe_pre_notify(resource_t *rsc, node_t *node, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set) +{ + pe_notify(rsc, node, op->pre_notify, op->pre_notified, + parent, data_set); +} + +void +pe_post_notify(resource_t *rsc, node_t *node, action_t *op, + crm_data_t *parent, pe_working_set_t *data_set) +{ + pe_notify(rsc, node, op->post_notify, op->post_notified, + parent, data_set); +} + diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h index ea3a4455b8..1f0891c907 100644 --- a/crm/pengine/pengine.h +++ b/crm/pengine/pengine.h @@ -1,420 +1,427 @@ -/* $Id: pengine.h,v 1.79 2005/08/08 13:07:52 andrew Exp $ */ +/* $Id: pengine.h,v 1.80 2005/08/10 08:55:04 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 PENGINE__H #define PENGINE__H #include typedef struct node_s node_t; typedef struct color_s color_t; typedef struct rsc_to_node_s rsc_to_node_t; typedef struct rsc_colocation_s rsc_colocation_t; typedef struct resource_s resource_t; typedef struct lrm_agent_s lrm_agent_t; typedef struct order_constraint_s order_constraint_t; typedef struct action_s action_t; typedef struct action_wrapper_s action_wrapper_t; #include #include #include #include /* * The man pages for both curses and ncurses suggest inclusion of "curses.h". * We believe the following to be acceptable and portable. */ #if defined(HAVE_NCURSES_H) # include # define CURSES_ENABLED 1 #elif defined(HAVE_CURSES_H) # include # define CURSES_ENABLED 1 #else # define CURSES_ENABLED 0 #endif typedef enum no_quorum_policy_e { no_quorum_freeze, no_quorum_stop, no_quorum_ignore } no_quorum_policy_t; typedef enum rsc_state_e { rsc_state_unknown, rsc_state_active, rsc_state_stopped, rsc_state_starting, rsc_state_stopping, rsc_state_restart, rsc_state_move } rsc_state_t; typedef struct pe_working_set_s { crm_data_t *input; /* options extracted from the input */ char *dc_uuid; node_t *dc_node; gboolean have_quorum; gboolean stonith_enabled; gboolean symmetric_cluster; int default_resource_stickiness; no_quorum_policy_t no_quorum_policy; /* intermediate steps */ color_t *no_color; GListPtr nodes; GListPtr resources; GListPtr placement_constraints; GListPtr ordering_constraints; GListPtr colors; GListPtr actions; /* stats */ int num_synapse; int max_valid_nodes; int order_id; int action_id; int color_id; /* final output */ crm_data_t *graph; } pe_working_set_t; #include enum con_type { type_none, rsc_colocation, rsc_to_node, rsc_to_attr, base_weight }; enum node_type { node_ping, node_member }; enum con_strength { pecs_ignore, pecs_must, pecs_must_not, pecs_startstop }; enum action_tasks { no_action, monitor_rsc, stop_rsc, stopped_rsc, start_rsc, started_rsc, action_notify, + action_notified, shutdown_crm, stonith_node }; enum rsc_recovery_type { recovery_stop_start, recovery_stop_only, recovery_block }; enum rsc_start_requirement { rsc_req_nothing, rsc_req_quorum, rsc_req_stonith }; enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; enum pe_restart { pe_restart_restart, pe_restart_ignore }; enum pe_ordering { pe_ordering_manditory, pe_ordering_restart, pe_ordering_recover, pe_ordering_postnotify, pe_ordering_optional }; struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean unclean; gboolean shutdown; gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { float weight; gboolean fixed; struct node_shared_s *details; }; struct color_shared_s { int id; float highest_priority; GListPtr candidate_nodes; /* node_t* */ GListPtr allocated_resources; /* resources_t* */ node_t *chosen_node; gboolean pending; int num_resources; }; struct color_s { int id; struct color_shared_s *details; float local_weight; }; struct rsc_colocation_s { const char *id; resource_t *rsc_lh; resource_t *rsc_rh; enum con_strength strength; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; float weight; GListPtr node_list_rh; /* node_t* */ }; struct lrm_agent_s { const char *class; const char *type; const char *version; }; struct resource_s { const char *id; crm_data_t *xml; crm_data_t *ops_xml; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; enum rsc_recovery_type recovery_type; enum pe_restart restart_type; float priority; float stickiness; float effective_priority; gboolean notify; gboolean is_managed; gboolean start_pending; gboolean recover; gboolean starting; gboolean stopping; gboolean runnable; gboolean provisional; gboolean unclean; GListPtr candidate_colors; /* color_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr actions; /* action_t* */ GHashTable * parameters; }; struct action_wrapper_s { enum pe_ordering type; action_t *action; }; enum action_fail_response { action_fail_nothing, action_fail_block, action_fail_stop, action_fail_fence }; struct action_s { int id; resource_t *rsc; void *rsc_opaque; node_t *node; const char *task; char *uuid; crm_data_t *op_entry; gboolean pseudo; gboolean runnable; gboolean optional; gboolean failure_is_fatal; enum rsc_start_requirement needs; enum action_fail_response on_fail; gboolean dumped; gboolean processed; + + action_t *pre_notify; + action_t *pre_notified; + action_t *post_notify; + action_t *post_notified; + int seen_count; GHashTable *extra; crm_data_t *extra_xml; GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; struct order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; extern gboolean stage0(pe_working_set_t *data_set); extern gboolean stage1(pe_working_set_t *data_set); extern gboolean stage2(pe_working_set_t *data_set); extern gboolean stage3(pe_working_set_t *data_set); extern gboolean stage4(pe_working_set_t *data_set); extern gboolean stage5(pe_working_set_t *data_set); extern gboolean stage6(pe_working_set_t *data_set); extern gboolean stage7(pe_working_set_t *data_set); extern gboolean stage8(pe_working_set_t *data_set); extern gboolean summary(GListPtr resources); extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data); extern gboolean process_pe_message( HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender); extern gboolean unpack_constraints( crm_data_t *xml_constraints, pe_working_set_t *data_set); extern gboolean unpack_resources( crm_data_t *xml_resources, pe_working_set_t *data_set); extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set); extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set); extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set); extern gboolean apply_placement_constraints(pe_working_set_t *data_set); extern void color_resource(resource_t *lh_resource, pe_working_set_t *data_set); extern gboolean choose_node_from_list(color_t *color); extern gboolean update_action_states(GListPtr actions); extern gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean stonith_constraints( node_t *node, action_t *stonith_op, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean custom_action_order( resource_t *lh_rsc, char *lh_task, action_t *lh_action, resource_t *rh_rsc, char *rh_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set); #define order_start_start(rsc1,rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_stop_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define order_restart(rsc1) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc1, start_key(rsc1), NULL, \ pe_ordering_restart, data_set) #define order_stop_start(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_start_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define pe_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } #define pe_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); extern gboolean process_colored_constraints(resource_t *rsc); extern void graph_element_from_action( action_t *action, pe_working_set_t *data_set); extern void set_working_set_defaults(pe_working_set_t *data_set); extern void cleanup_calculations(pe_working_set_t *data_set); extern const char* transition_idle_timeout; extern gboolean was_processing_error; extern gboolean was_processing_warning; #endif diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c index 1044e9fa36..8f7bb9e245 100644 --- a/crm/pengine/ptest.c +++ b/crm/pengine/ptest.c @@ -1,253 +1,260 @@ -/* $Id: ptest.c,v 1.58 2005/08/10 08:30:19 andrew Exp $ */ +/* $Id: ptest.c,v 1.59 2005/08/10 08:55:03 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?X:wD:" #ifdef HAVE_GETOPT_H # include #endif #include #include #include gboolean inhibit_exit = FALSE; extern crm_data_t * do_calculations( pe_working_set_t *data_set, crm_data_t *xml_input); extern void cleanup_calculations(pe_working_set_t *data_set); FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write("digraph \"g\" {"); dot_write(" size = \"30,30\""); /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } int main(int argc, char **argv) { + gboolean optional = FALSE; pe_working_set_t data_set; crm_data_t * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; const char *xml_file = NULL; const char *dot_file = NULL; cl_log_set_entity("ptest"); cl_log_set_facility(LOG_USER); set_crm_log_level(LOG_CRIT-1); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {F_CRM_DATA, 1, 0, 'X'}, {"help", 0, 0, 0}, {0, 0, 0, 0} }; #endif #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; #endif case 'w': inhibit_exit = TRUE; break; case 'X': xml_file = crm_strdup(optarg); break; case 'D': dot_file = crm_strdup(optarg); break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); cib_object = file2xml(xml_strm); } else { cib_object = stdin2xml(); } #ifdef MCHECK mtrace(); #endif CRM_DEV_ASSERT(cib_object != NULL); crm_zero_mem_stats(NULL); do_calculations(&data_set, cib_object); msg_buffer = dump_xml_formatted(data_set.graph); fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); crm_free(msg_buffer); dot_strm = fopen(dot_file, "w"); init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, if(action->dumped == FALSE) { if(action->optional) { dot_write("\"%s\" [ style=\"dashed\" color=\"%s\" fontcolor=\"%s\" ]", action->uuid, "blue", action->pseudo?"orange":"black"); } else { CRM_DEV_ASSERT(action->runnable == FALSE); - dot_write("\"%s\" [ fontcolor=\"%s\" ]", + dot_write("\"%s\" [ fillcolor=\"%s\" ]", action->uuid, "red"); } } else { - dot_write("\"%s\" [ tooltip=\"%s\" color=\"%s\" fontcolor=\"%s\" ]", + dot_write("\"%s\" [ tooltip=\"%s\" style=bold color=\"%s\" fontcolor=\"%s\" ]", action->uuid, action->pseudo?"":action->node?action->node->details->uname:"", "green", action->pseudo?"orange":"black"); } ); slist_iter( action, action_t, data_set.actions, lpc, + optional = FALSE; slist_iter( before, action_wrapper_t, action->actions_before, lpc2, - dot_write("\"%s\" -> \"%s\"", - before->action->uuid, action->uuid); + if(action->dumped && before->action->dumped) { + } else if(action->optional || before->action->optional) { + optional = TRUE; + } + dot_write("\"%s\" -> \"%s\" [ style = %s]", + before->action->uuid, action->uuid, + optional?"dashed":"bold"); ); ); dot_write("}"); cleanup_calculations(&data_set); crm_mem_stats(NULL); CRM_DEV_ASSERT(crm_mem_stats(NULL) == FALSE); #ifdef MCHECK muntrace(); #endif free_xml(cib_object); /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } return 0; } diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c index 0c4f1b6416..3635c48ea9 100644 --- a/crm/pengine/utils.c +++ b/crm/pengine/utils.c @@ -1,1582 +1,1587 @@ -/* $Id: utils.c,v 1.98 2005/08/08 13:07:52 andrew Exp $ */ +/* $Id: utils.c,v 1.99 2005/08/10 08:55:04 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 void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set); /* only for rsc_colocation constraints */ rsc_colocation_t * invert_constraint(rsc_colocation_t *constraint) { rsc_colocation_t *inverted_con = NULL; crm_debug_3("Inverting constraint"); if(constraint == NULL) { pe_err("Cannot invert NULL constraint"); return NULL; } crm_malloc0(inverted_con, sizeof(rsc_colocation_t)); if(inverted_con == NULL) { return NULL; } inverted_con->id = constraint->id; inverted_con->strength = constraint->strength; /* swap the direction */ inverted_con->rsc_lh = constraint->rsc_rh; inverted_con->rsc_rh = constraint->rsc_lh; crm_action_debug_3( print_rsc_colocation("Inverted constraint", inverted_con, FALSE)); return inverted_con; } /* are the contents of list1 and list2 equal * nodes with weight < 0 are ignored if filter == TRUE * * slow but linear * */ gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node; GListPtr lhs = list1; GListPtr rhs = list2; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node(rhs, node->details->uname); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); lhs = list2; rhs = list1; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node(rhs, node->details->uname); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); return TRUE; } /* the intersection of list1 and list2 */ GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; unsigned lpc = 0; for(lpc = 0; lpc < g_list_length(list1); lpc++) { node_t *node = (node_t*)g_list_nth_data(list1, lpc); node_t *other_node = pe_find_node(list2, node->details->uname); node_t *new_node = NULL; if(other_node != NULL) { new_node = node_copy(node); } if(new_node != NULL) { new_node->weight = merge_weights( new_node->weight, other_node->weight); if(filter && new_node->weight < 0) { crm_free(new_node); new_node = NULL; } } if(new_node != NULL) { result = g_list_append(result, new_node); } } return result; } /* list1 - list2 */ GListPtr node_list_minus(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *other_node = pe_find_node(list2, node->details->uname); node_t *new_node = NULL; if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Minus result len: %d", g_list_length(result)); return result; } /* list1 + list2 - (intersection of list1 and list2) */ GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node(list2, node->details->uname); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); slist_iter( node, node_t, list2, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node(list1, node->details->uname); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Xor result len: %d", g_list_length(result)); return result; } GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node = NULL; GListPtr result = NULL; gboolean needs_filter = FALSE; result = node_list_dup(list1, filter); slist_iter( node, node_t, list2, lpc, if(node == NULL) { continue; } other_node = (node_t*)pe_find_node( result, node->details->uname); if(other_node != NULL) { other_node->weight = merge_weights( other_node->weight, node->weight); if(filter && node->weight < 0) { needs_filter = TRUE; } } else if(filter == FALSE || node->weight >= 0) { node_t *new_node = node_copy(node); result = g_list_append(result, new_node); } ); /* not the neatest way, but the most expedient for now */ if(filter && needs_filter) { GListPtr old_result = result; result = node_list_dup(old_result, filter); pe_free_shallow_adv(old_result, TRUE); } return result; } GListPtr node_list_dup(GListPtr list1, gboolean filter) { GListPtr result = NULL; slist_iter( this_node, node_t, list1, lpc, node_t *new_node = NULL; if(filter && this_node->weight < 0) { continue; } new_node = node_copy(this_node); if(new_node != NULL) { result = g_list_append(result, new_node); } ); return result; } node_t * node_copy(node_t *this_node) { node_t *new_node = NULL; CRM_DEV_ASSERT(this_node != NULL); if(this_node == NULL) { pe_err("Failed copy of node."); return NULL; } crm_malloc0(new_node, sizeof(node_t)); CRM_DEV_ASSERT(new_node != NULL); if(new_node == NULL) { return NULL; } crm_debug_5("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; return new_node; } /* * Create a new color with the contents of "nodes" as the list of * possible nodes that resources with this color can be run on. * * Typically, when creating a color you will provide the node list from * the resource you will first assign the color to. * * If "colors" != NULL, it will be added to that list * If "resources" != NULL, it will be added to every provisional resource * in that list */ color_t * create_color( pe_working_set_t *data_set, resource_t *resource, GListPtr node_list) { color_t *new_color = NULL; crm_debug_5("Creating color"); crm_malloc0(new_color, sizeof(color_t)); if(new_color == NULL) { return NULL; } new_color->id = data_set->color_id++; new_color->local_weight = 1.0; crm_debug_5("Creating color details"); crm_malloc0(new_color->details, sizeof(struct color_shared_s)); if(new_color->details == NULL) { crm_free(new_color); return NULL; } new_color->details->id = new_color->id; new_color->details->highest_priority = -1; new_color->details->chosen_node = NULL; new_color->details->candidate_nodes = NULL; new_color->details->allocated_resources = NULL; new_color->details->pending = TRUE; if(resource != NULL) { crm_debug_5("populating node list"); new_color->details->highest_priority = resource->priority; new_color->details->candidate_nodes = node_list_dup(node_list, TRUE); } crm_action_debug_3(print_color("Created color", new_color, TRUE)); CRM_DEV_ASSERT(data_set != NULL); if(crm_assert_failed == FALSE) { data_set->colors = g_list_append(data_set->colors, new_color); } return new_color; } color_t * copy_color(color_t *a_color) { color_t *color_copy = NULL; if(a_color == NULL) { pe_err("Cannot copy NULL"); return NULL; } crm_malloc0(color_copy, sizeof(color_t)); if(color_copy != NULL) { color_copy->id = a_color->id; color_copy->details = a_color->details; color_copy->local_weight = 1.0; } return color_copy; } resource_t * pe_find_resource(GListPtr rsc_list, const char *id) { unsigned lpc = 0; resource_t *rsc = NULL; resource_t *child_rsc = NULL; crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list)); for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); if(rsc != NULL && safe_str_eq(rsc->id, id)){ crm_debug_4("Found a match for %s", id); return rsc; } } for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); child_rsc = rsc->fns->find_child(rsc, id); if(child_rsc != NULL) { crm_debug_4("Found a match for %s in %s", id, rsc->id); return child_rsc; } } /* error */ return NULL; } node_t * pe_find_node(GListPtr nodes, const char *uname) { unsigned lpc = 0; node_t *node = NULL; for(lpc = 0; lpc < g_list_length(nodes); lpc++) { node = g_list_nth_data(nodes, lpc); if(node != NULL && safe_str_eq(node->details->uname, uname)) { return node; } } /* error */ return NULL; } node_t * pe_find_node_id(GListPtr nodes, const char *id) { unsigned lpc = 0; node_t *node = NULL; for(lpc = 0; lpc < g_list_length(nodes); lpc++) { node = g_list_nth_data(nodes, lpc); if(safe_str_eq(node->details->id, id)) { return node; } } /* error */ return NULL; } gint gslist_color_compare(gconstpointer a, gconstpointer b); color_t * find_color(GListPtr candidate_colors, color_t *other_color) { GListPtr tmp = g_list_find_custom(candidate_colors, other_color, gslist_color_compare); if(tmp != NULL) { return (color_t *)tmp->data; } return NULL; } gint gslist_color_compare(gconstpointer a, gconstpointer b) { const color_t *color_a = (const color_t*)a; const color_t *color_b = (const color_t*)b; /* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */ if(a == b) { return 0; } else if(a == NULL || b == NULL) { return 1; } else if(color_a->id == color_b->id) { return 0; } return 1; } gint sort_rsc_priority(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL && b == NULL) { return 0; } if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(resource1->priority > resource2->priority) { return -1; } if(resource1->priority < resource2->priority) { return 1; } return 0; } /* lowest to highest */ gint sort_action_id(gconstpointer a, gconstpointer b) { const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(action_wrapper1->action->id > action_wrapper2->action->id) { return -1; } if(action_wrapper1->action->id < action_wrapper2->action->id) { return 1; } return 0; } gint sort_cons_strength(gconstpointer a, gconstpointer b) { const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(rsc_constraint1->strength > rsc_constraint2->strength) { return 1; } if(rsc_constraint1->strength < rsc_constraint2->strength) { return -1; } return 0; } gint sort_color_weight(gconstpointer a, gconstpointer b) { const color_t *color1 = (const color_t*)a; const color_t *color2 = (const color_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(color1->local_weight > color2->local_weight) { return -1; } if(color1->local_weight < color2->local_weight) { return 1; } return 0; } /* return -1 if 'a' is more preferred * return 1 if 'b' is more preferred */ gint sort_node_weight(gconstpointer a, gconstpointer b) { const node_t *node1 = (const node_t*)a; const node_t *node2 = (const node_t*)b; float node1_weight = 0; float node2_weight = 0; if(a == NULL) { return 1; } if(b == NULL) { return -1; } node1_weight = node1->weight; node2_weight = node2->weight; if(node1->details->unclean || node1->details->shutdown) { node1_weight = -INFINITY; } if(node2->details->unclean || node2->details->shutdown) { node2_weight = -INFINITY; } if(node1_weight > node2_weight) { crm_debug_4("%s (%f) > %s (%f) : weight", node1->details->id, node1_weight, node2->details->id, node2_weight); return -1; } if(node1_weight < node2_weight) { crm_debug_4("%s (%f) < %s (%f) : weight", node1->details->id, node1_weight, node2->details->id, node2_weight); return 1; } /* now try to balance resources across the cluster */ if(node1->details->num_resources < node2->details->num_resources) { crm_debug_4("%s (%d) < %s (%d) : resources", node1->details->id, node1->details->num_resources, node2->details->id, node2->details->num_resources); return -1; } else if(node1->details->num_resources > node2->details->num_resources) { crm_debug_4("%s (%d) > %s (%d) : resources", node1->details->id, node1->details->num_resources, node2->details->id, node2->details->num_resources); return 1; } crm_debug_4("%s = %s", node1->details->id, node2->details->id); return 0; } action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, pe_working_set_t *data_set) { action_t *action = NULL; GListPtr possible_matches = NULL; CRM_DEV_ASSERT(key != NULL); if(crm_assert_failed) { return NULL; } CRM_DEV_ASSERT(task != NULL); if(crm_assert_failed) { return NULL; } if(rsc != NULL) { possible_matches = find_actions(rsc->actions, key, on_node); } if(possible_matches != NULL) { crm_free(key); if(g_list_length(possible_matches) > 1) { pe_warn("Action %s for %s on %s exists %d times", task, rsc?rsc->id:"", on_node?on_node->details->uname:"", g_list_length(possible_matches)); } action = g_list_nth_data(possible_matches, 0); crm_debug_4("Found existing action (%d) %s for %s on %s", action->id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); } if(action == NULL) { crm_debug_2("Creating action %d: %s for %s on %s", data_set->action_id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); crm_malloc0(action, sizeof(action_t)); if(action != NULL) { action->id = data_set->action_id++; action->rsc = rsc; action->task = task; action->node = on_node; action->actions_before = NULL; action->actions_after = NULL; action->failure_is_fatal = TRUE; action->pseudo = FALSE; action->dumped = FALSE; action->runnable = TRUE; action->processed = FALSE; action->optional = TRUE; action->seen_count = 0; action->extra = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); data_set->actions = g_list_append( data_set->actions, action); action->uuid = key; if(rsc != NULL) { action->op_entry = find_rsc_op_entry(rsc, key); unpack_operation( action, action->op_entry, data_set); rsc->actions = g_list_append( rsc->actions, action); } crm_debug_4("Action %d created", action->id); } } if(optional == FALSE) { crm_debug_2("Action %d marked manditory", action->id); action->optional = FALSE; } if(rsc != NULL) { if(action->node != NULL) { unpack_instance_attributes( action->op_entry, action->node, action->extra, NULL, 0); } if(action->node == NULL) { action->runnable = FALSE; } else if(action->node->details->online == FALSE) { pe_warn("Action %d %s for %s on %s is unrunnable", action->id, task, rsc?rsc->id:"", action->node?action->node->details->uname:""); action->runnable = FALSE; } else if(action->needs == rsc_req_nothing) { crm_debug_2("Action doesnt require anything"); action->runnable = TRUE; #if 0 /* * No point checking this * - if we dont have quorum we cant stonith anyway */ } else if(action->needs == rsc_req_stonith) { crm_debug_2("Action requires only stonith"); action->runnable = TRUE; #endif } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_stop) { action->runnable = FALSE; crm_warn("%s resource %s\t(%s) (cancelled : quorum)", action->task, rsc->id, action->node->details->uname); } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_freeze) { crm_debug_2("Check resource is already active"); if(rsc->fns->active(rsc, TRUE) == FALSE) { action->runnable = FALSE; crm_warn("%s resource %s\t(%s) (cancelled : quorum freeze)", action->task, rsc->id, action->node->details->uname); } } else { crm_debug_2("Action is runnable"); action->runnable = TRUE; } switch(text2task(action->task)) { case stop_rsc: rsc->stopping = TRUE; break; case start_rsc: rsc->starting = FALSE; if(action->runnable) { rsc->starting = TRUE; } break; default: break; } } return action; } void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set) { int lpc = 0; const char *value = NULL; const char *fields[] = { "interval", "timeout", "start_delay", }; CRM_DEV_ASSERT(action->rsc != NULL); if(xml_obj != NULL) { value = crm_element_value(xml_obj, "prereq"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) { value = crm_element_value(action->rsc->xml, "start_prereq"); } if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) { /* todo: integrate stop as an option? */ action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(safe_str_eq(value, "nothing")) { action->needs = rsc_req_nothing; } else if(safe_str_eq(value, "quorum")) { action->needs = rsc_req_quorum; } else if(safe_str_eq(value, "fencing")) { action->needs = rsc_req_stonith; } else if(data_set->no_quorum_policy == no_quorum_ignore) { action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(data_set->no_quorum_policy == no_quorum_freeze && data_set->stonith_enabled) { action->needs = rsc_req_stonith; value = "fencing (default)"; } else { action->needs = rsc_req_quorum; value = "quorum (default)"; } crm_debug_2("\tAction %s requires: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "on_fail"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { value = crm_element_value(action->rsc->xml, "on_stopfail"); } if(value == NULL) { } else if(safe_str_eq(value, "fence")) { action->on_fail = action_fail_fence; value = "node fencing"; } else if(safe_str_eq(value, "stop")) { action->on_fail = action_fail_stop; value = "resource stop"; } else if(safe_str_eq(value, "nothing")) { action->on_fail = action_fail_nothing; } else if(safe_str_eq(value, "block")) { action->on_fail = action_fail_block; } else if(safe_str_eq(value, "ignore")) { action->on_fail = action_fail_nothing; value = "nothing"; } else { pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value); value = NULL; } /* defaults */ if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { if(data_set->stonith_enabled) { action->on_fail = action_fail_fence; value = "resource fence (default)"; } else { action->on_fail = action_fail_block; value = "resource block (default)"; } } else if(value == NULL) { action->on_fail = action_fail_stop; value = "resource stop (default)"; } crm_debug_2("\t%s failure results in: %s", action->task, value); if(xml_obj == NULL) { return; } for(;lpc < DIMOF(fields); lpc++) { value = crm_element_value(xml_obj, fields[lpc]); add_hash_param(action->extra, fields[lpc], value); } /* if(safe_str_eq(native_data->agent->class, "stonith")) { */ /* if(rsc->start_needs == rsc_req_stonith) { */ /* pe_err("Stonith resources (eg. %s) cannot require" */ /* " fencing to start", rsc->id); */ /* } */ /* rsc->start_needs = rsc_req_quorum; */ /* } */ } crm_data_t * find_rsc_op_entry(resource_t *rsc, const char *key) { const char *name = NULL; const char *interval = NULL; char *match_key = NULL; crm_data_t *op = NULL; xml_child_iter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); interval = crm_element_value(operation, "interval"); match_key = generate_op_key(rsc->id,name,crm_get_msec(interval)); crm_debug_2("Matching %s with %s", key, match_key); if(safe_str_eq(key, match_key)) { op = operation; } crm_free(match_key); if(op != NULL) { break; } ); crm_debug_2("No matching for %s", key); return op; } const char * strength2text(enum con_strength strength) { const char *result = ""; switch(strength) { case pecs_ignore: result = "ignore"; break; case pecs_must: result = XML_STRENGTH_VAL_MUST; break; case pecs_must_not: result = XML_STRENGTH_VAL_MUSTNOT; break; case pecs_startstop: result = "start/stop"; break; } return result; } const char * ordering_type2text(enum pe_ordering type) { const char *result = ""; switch(type) { case pe_ordering_manditory: result = "manditory"; break; case pe_ordering_restart: result = "restart"; break; case pe_ordering_recover: result = "recover"; break; case pe_ordering_optional: result = "optional"; break; case pe_ordering_postnotify: result = "post_notify"; break; } return result; } enum action_tasks text2task(const char *task) { if(safe_str_eq(task, CRMD_ACTION_STOP)) { return stop_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) { return stopped_rsc; } else if(safe_str_eq(task, CRMD_ACTION_START)) { return start_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STARTED)) { return started_rsc; } else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) { return shutdown_crm; } else if(safe_str_eq(task, CRM_OP_FENCE)) { return stonith_node; } else if(safe_str_eq(task, CRMD_ACTION_MON)) { return monitor_rsc; } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { return action_notify; + } else if(safe_str_eq(task, CRMD_ACTION_NOTIFIED)) { + return action_notified; } pe_err("Unsupported action: %s", task); return no_action; } const char * task2text(enum action_tasks task) { const char *result = ""; switch(task) { case no_action: result = "no_action"; break; case stop_rsc: result = CRMD_ACTION_STOP; break; case stopped_rsc: result = CRMD_ACTION_STOPPED; break; case start_rsc: result = CRMD_ACTION_START; break; case started_rsc: result = CRMD_ACTION_STARTED; break; case shutdown_crm: result = CRM_OP_SHUTDOWN; break; case stonith_node: result = CRM_OP_FENCE; break; case monitor_rsc: result = CRMD_ACTION_MON; break; case action_notify: result = CRMD_ACTION_NOTIFY; break; + case action_notified: + result = CRMD_ACTION_NOTIFIED; + break; } return result; } const char * rsc_state2text(rsc_state_t state) { const char *result = ""; switch(state) { case rsc_state_active: result = "active"; break; case rsc_state_restart: result = "restart"; break; case rsc_state_move: result = "move"; break; case rsc_state_starting: result = "starting"; break; case rsc_state_stopping: result = "stopping"; break; case rsc_state_stopped: result = "stopped"; break; case rsc_state_unknown: result = "unknown"; break; } return result; } void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%sNode %s: (weight=%f, fixed=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", node->details->uname, node->weight, node->fixed?"True":"False"); if(details && node != NULL && node->details != NULL) { char *pe_mutable = crm_strdup("\t\t"); crm_debug_4("\t\t===Node Attributes"); g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable); crm_free(pe_mutable); crm_debug_4("\t\t=== Resources"); slist_iter( rsc, resource_t, node->details->running_rsc, lpc, print_resource("\t\t", rsc, FALSE); ); } } /* * Used by the HashTable for-loop */ void print_str_str(gpointer key, gpointer value, gpointer user_data) { crm_debug_4("%s%s %s ==> %s", user_data==NULL?"":(char*)user_data, user_data==NULL?"":": ", (char*)key, (char*)value); } void print_color_details(const char *pre_text, struct color_shared_s *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: node=%s (from %d candidates)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->chosen_node==NULL?"":color->chosen_node->details->uname, g_list_length(color->candidate_nodes)); if(details) { slist_iter(node, node_t, color->candidate_nodes, lpc, print_node("\t", node, FALSE)); } } void print_color(const char *pre_text, color_t *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: (weight=%f, node=%s, possible=%d)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->local_weight, safe_val5("",color,details,chosen_node,details,uname), g_list_length(color->details->candidate_nodes)); if(details) { print_color_details("\t", color->details, details); } } void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", "rsc_to_node", cons->id, cons, g_list_length(cons->node_list_rh)); if(details == FALSE) { crm_debug_4("\t%s (score=%f : node placement rule)", safe_val3(NULL, cons, rsc_lh, id), cons->weight); slist_iter( node, node_t, cons->node_list_rh, lpc, print_node("\t\t-->", node, FALSE) ); } } void print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", XML_CONS_TAG_RSC_DEPEND, cons->id, cons); if(details == FALSE) { crm_debug_4("\t%s --> %s, %s", safe_val3(NULL, cons, rsc_lh, id), safe_val3(NULL, cons, rsc_rh, id), strength2text(cons->strength)); } } void print_resource(const char *pre_text, resource_t *rsc, gboolean details) { if(rsc == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } rsc->fns->dump(rsc, pre_text, details); } void print_action(const char *pre_text, action_t *action, gboolean details) { log_action(LOG_DEBUG_3, pre_text, action, details); } #define util_log(fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt) void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) { const char *node_uname = NULL; const char *node_uuid = NULL; if(action == NULL) { util_log("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(action->pseudo) { node_uname = NULL; node_uuid = NULL; } else if(action->node != NULL) { node_uname = action->node->details->uname; node_uuid = action->node->details->id; } else { node_uname = ""; node_uuid = NULL; } switch(text2task(action->task)) { case stonith_node: case shutdown_crm: crm_log_maybe(log_level, "%s%s%sAction %d: %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->task, node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; default: crm_log_maybe(log_level, "%s%s%sAction %d: %s %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->task, safe_val3("", action, rsc, id), node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; } if(details) { crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #if 1 crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions"); slist_iter( other, action_wrapper_t, action->actions_after, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #endif crm_log_maybe(log_level+1, "\t\t====== End"); } else { crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)", action->seen_count, g_list_length(action->actions_before), g_list_length(action->actions_after)); } } void pe_free_nodes(GListPtr nodes) { GListPtr iterator = nodes; while(iterator != NULL) { node_t *node = (node_t*)iterator->data; struct node_shared_s *details = node->details; iterator = iterator->next; crm_debug_5("deleting node"); crm_debug_5("%s is being deleted", details->uname); print_node("delete", node, FALSE); if(details != NULL) { if(details->attrs != NULL) { g_hash_table_destroy(details->attrs); } pe_free_shallow_adv(details->running_rsc, FALSE); crm_free(details); } crm_free(node); } if(nodes != NULL) { g_list_free(nodes); } } void pe_free_colors(GListPtr colors) { GListPtr iterator = colors; while(iterator != NULL) { color_t *color = (color_t *)iterator->data; struct color_shared_s *details = color->details; iterator = iterator->next; if(details != NULL) { pe_free_shallow(details->candidate_nodes); pe_free_shallow_adv(details->allocated_resources, FALSE); crm_free(details->chosen_node); crm_free(details); } crm_free(color); } if(colors != NULL) { g_list_free(colors); } } void pe_free_shallow(GListPtr alist) { pe_free_shallow_adv(alist, TRUE); } void pe_free_shallow_adv(GListPtr alist, gboolean with_data) { GListPtr item; GListPtr item_next = alist; while(item_next != NULL) { item = item_next; item_next = item_next->next; if(with_data) { /* crm_debug_5("freeing %p", item->data); */ crm_free(item->data); } item->data = NULL; item->next = NULL; g_list_free(item); } } void pe_free_resources(GListPtr resources) { resource_t *rsc = NULL; GListPtr iterator = resources; while(iterator != NULL) { iterator = iterator; rsc = (resource_t *)iterator->data; iterator = iterator->next; rsc->fns->free(rsc); } if(resources != NULL) { g_list_free(resources); } } void pe_free_actions(GListPtr actions) { GListPtr iterator = actions; while(iterator != NULL) { action_t *action = (action_t *)iterator->data; iterator = iterator->next; pe_free_shallow(action->actions_before);/* action_warpper_t* */ pe_free_shallow(action->actions_after); /* action_warpper_t* */ g_hash_table_destroy(action->extra); crm_free(action->uuid); crm_free(action); } if(actions != NULL) { g_list_free(actions); } } void pe_free_ordering(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { order_constraint_t *order = iterator->data; iterator = iterator->next; crm_free(order->lh_action_task); crm_free(order->rh_action_task); crm_free(order); } if(constraints != NULL) { g_list_free(constraints); } } void pe_free_rsc_colocation(rsc_colocation_t *cons) { if(cons != NULL) { crm_debug_4("Freeing constraint %s (%p)", cons->id, cons); crm_free(cons); } } void pe_free_rsc_to_node(rsc_to_node_t *cons) { if(cons != NULL) { pe_free_shallow(cons->node_list_rh); crm_free(cons); } } GListPtr find_actions(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; CRM_DEV_ASSERT(key != NULL); slist_iter( action, action_t, input, lpc, crm_debug_5("Matching %s against %s", key, action->uuid); if(safe_str_neq(key, action->uuid)) { continue; } else if(on_node == NULL) { result = g_list_append(result, action); } else if(action->node == NULL) { /* skip */ crm_debug_2("While looking for %s action on %s, " "found an unallocated one. Assigning" " it to the requested node...", key, on_node->details->uname); action->node = on_node; result = g_list_append(result, action); } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } ); return result; } void set_id(crm_data_t * xml_obj, const char *prefix, int child) { int id_len = 0; gboolean use_prefix = TRUE; gboolean use_child = TRUE; char *new_id = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); id_len = 1 + strlen(id); if(child > 999) { pe_err("Are you insane?!?" " The CRM does not support > 1000 children per resource"); return; } else if(child < 0) { use_child = FALSE; } else { id_len += 4; /* child */ } if(prefix == NULL || safe_str_eq(id, prefix)) { use_prefix = FALSE; } else { id_len += (1 + strlen(prefix)); } crm_malloc0(new_id, id_len); if(use_child) { snprintf(new_id, id_len, "%s%s%s:%d", use_prefix?prefix:"", use_prefix?":":"", id, child); } else { snprintf(new_id, id_len, "%s%s%s", use_prefix?prefix:"", use_prefix?":":"", id); } crm_xml_add(xml_obj, XML_ATTR_ID, new_id); crm_free(new_id); } float merge_weights(float w1, float w2) { float result = w1 + w2; if(w1 <= -INFINITY || w2 <= -INFINITY) { if(w1 >= INFINITY || w2 >= INFINITY) { pe_warn("-INFINITY + INFINITY == -INFINITY"); } return -INFINITY; } else if(w1 >= INFINITY || w2 >= INFINITY) { return INFINITY; } /* detect wrap-around */ if(result > 0) { if(w1 <= 0 && w2 < 0) { result = -INFINITY; } } else if(w1 > 0 && w2 > 0) { result = INFINITY; } /* detect +/- INFINITY */ if(result >= INFINITY) { result = INFINITY; } else if(result <= -INFINITY) { result = -INFINITY; } return result; } float char2score(const char *score) { float score_f = 0.0; if(score == NULL) { } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else { score_f = atof(score); if(score_f > 0 && score_f > INFINITY) { score_f = INFINITY; } else if(score_f < 0 && score_f < -INFINITY) { score_f = -INFINITY; } } return score_f; } diff --git a/include/crm/crm.h b/include/crm/crm.h index 394d45d058..ad1dbb2df9 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,297 +1,298 @@ -/* $Id: crm.h,v 1.70 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: crm.h,v 1.71 2005/08/10 08:55:04 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 #include #ifdef MCHECK #include #endif #include #ifndef CRM_DEV_BUILD # define CRM_DEV_BUILD 0 #endif #define ipc_call_diff_max_ms 5000 #define action_diff_warn_ms 5000 #define action_diff_max_ms 20000 #define fsa_diff_warn_ms 10000 #define fsa_diff_max_ms 30000 #include #define CRM_ASSERT(expr) if((expr) == FALSE) { \ do_crm_log(LOG_CRIT, __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ abort(); \ } extern gboolean crm_assert_failed; #define CRM_DEV_ASSERT(expr) crm_assert_failed = FALSE; \ if((expr) == FALSE) { \ crm_assert_failed = TRUE; \ do_crm_log(CRM_DEV_BUILD?LOG_CRIT:LOG_ERR, \ __FILE__, __PRETTY_FUNCTION__, \ "Triggered dev assert at %s:%d : %s", \ __FILE__, __LINE__, #expr); \ if(CRM_DEV_BUILD) { \ abort(); \ } \ } /* Clean these up at some point, some probably should be runtime options */ #define WORKING_DIR HA_VARLIBDIR"/heartbeat/crm" #define BIN_DIR HA_LIBDIR"/heartbeat" #define SOCKET_LEN 1024 #define APPNAME_LEN 256 #define MAX_IPC_FAIL 5 #define CIB_FILENAME WORKING_DIR"/cib.xml" #define CIB_BACKUP WORKING_DIR"/cib_backup.xml" #define CRM_VERSION "1.0" #define MSG_LOG 1 #define DOT_FSA_ACTIONS 1 #define DOT_ALL_FSA_INPUTS 1 /* #define FSA_TRACE 1 */ #define INFINITY_S "INFINITY" #define MINUS_INFINITY_S "-INFINITY" #define INFINITY 1000000.0 /* Sub-systems */ #define CRM_SYSTEM_DC "dc" #define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ #define CRM_SYSTEM_CIB "cib" #define CRM_SYSTEM_CRMD "crmd" #define CRM_SYSTEM_LRMD "lrmd" #define CRM_SYSTEM_PENGINE "pengine" #define CRM_SYSTEM_TENGINE "tengine" /* Valid operations */ #define CRM_OP_NOOP "noop" #define CRM_OP_JOIN_ANNOUNCE "join_announce" #define CRM_OP_JOIN_OFFER "join_offer" #define CRM_OP_JOIN_REQUEST "join_request" #define CRM_OP_JOIN_ACKNAK "join_ack_nack" #define CRM_OP_JOIN_CONFIRM "join_confirm" #define CRM_OP_DIE "die_no_respawn" #define CRM_OP_RETRIVE_CIB "retrieve_cib" #define CRM_OP_PING "ping" #define CRM_OP_VOTE "vote" #define CRM_OP_HELLO "hello" #define CRM_OP_HBEAT "dc_beat" #define CRM_OP_PECALC "pe_calc" #define CRM_OP_ABORT "abort" #define CRM_OP_QUIT "quit" #define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" #define CRM_OP_SHUTDOWN_REQ "req_shutdown" #define CRM_OP_SHUTDOWN "do_shutdown" #define CRM_OP_FENCE "stonith" #define CRM_OP_EVENTCC "event_cc" #define CRM_OP_TEABORT "te_abort" #define CRM_OP_TEABORTED "te_abort_confirmed" /* we asked */ #define CRM_OP_TE_HALT "te_halt" #define CRM_OP_TECOMPLETE "te_complete" #define CRM_OP_TETIMEOUT "te_timeout" #define CRM_OP_TRANSITION "transition" #define CRM_OP_REGISTER "register" #define CRM_OP_DEBUG_UP "debug_inc" #define CRM_OP_DEBUG_DOWN "debug_dec" #define CRMD_STATE_ACTIVE "member" #define CRMD_STATE_INACTIVE "down" #define CRMD_JOINSTATE_DOWN "down" #define CRMD_JOINSTATE_PENDING "pending" #define CRMD_JOINSTATE_MEMBER "member" #define CRMD_ACTION_START "start" #define CRMD_ACTION_STARTED "running" #define CRMD_ACTION_START_FAIL "start_failed" #define CRMD_ACTION_START_PENDING "starting" #define CRMD_ACTION_STOP "stop" #define CRMD_ACTION_STOPPED "stopped" #define CRMD_ACTION_STOP_FAIL "stop_failed" #define CRMD_ACTION_STOP_PENDING "stopping" #define CRMD_ACTION_NOTIFY "notify" +#define CRMD_ACTION_NOTIFIED "notified" #define CRMD_ACTION_MON "monitor" #define CRMD_ACTION_MON_PENDING CRMD_ACTION_STARTED #define CRMD_ACTION_MON_OK CRMD_ACTION_STARTED #define CRMD_ACTION_MON_FAIL "monitor_failed" /* #define CRMD_ACTION_GENERIC "pending" */ #define CRMD_ACTION_GENERIC_PENDING "pending" #define CRMD_ACTION_GENERIC_OK "complete" #define CRMD_ACTION_GENERIC_FAIL "pending_failed" typedef GList* GListPtr; #define crm_atoi(text, default) atoi(text?text:default) extern gboolean safe_str_eq(const char *a, const char *b); extern gboolean safe_str_neq(const char *a, const char *b); #define slist_iter(child, child_type, parent, counter, a) \ { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ int counter = 0; \ for(; __crm_iter_head != NULL; counter++) { \ child = __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ } #define LOG_DEBUG_2 LOG_DEBUG+1 #define LOG_DEBUG_3 LOG_DEBUG+2 #define LOG_DEBUG_4 LOG_DEBUG+3 #define LOG_DEBUG_5 LOG_DEBUG+4 #define LOG_DEBUG_6 LOG_DEBUG+5 #define LOG_MSG LOG_DEBUG_3 #define crm_crit(w...) do_crm_log(LOG_CRIT, __FILE__, __FUNCTION__, w) #define crm_err(w...) do_crm_log(LOG_ERR, __FILE__, __FUNCTION__, w) #define crm_warn(w...) do_crm_log(LOG_WARNING, __FILE__, __FUNCTION__, w) #define crm_notice(w...) do_crm_log(LOG_NOTICE, __FILE__, __FUNCTION__, w) #define crm_info(w...) do_crm_log(LOG_INFO, __FILE__, __FUNCTION__, w) #define crm_log_maybe(level, fmt...) if(crm_log_level >= level) { \ do_crm_log(level, __FILE__, __FUNCTION__, fmt); \ } #define crm_debug(fmt...) crm_log_maybe(LOG_DEBUG, fmt) #define crm_debug_2(fmt...) crm_log_maybe(LOG_DEBUG_2, fmt) /* If this is not a developmental build, give the compiler every chance to * optimize these away */ #if CRM_DEV_BUILD # define crm_debug_3(fmt...) crm_log_maybe(LOG_DEBUG_3, fmt) # define crm_debug_4(fmt...) crm_log_maybe(LOG_DEBUG_4, fmt) # define crm_debug_5(fmt...) crm_log_maybe(LOG_DEBUG_5, fmt) # define crm_debug_6(fmt...) crm_log_maybe(LOG_DEBUG_6, fmt) #else # define crm_debug_3(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_debug_4(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_debug_5(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } # define crm_debug_6(w...) if(0) { do_crm_log(LOG_DEBUG, NULL, NULL, w); } #endif extern void crm_log_message_adv( int level, const char *alt_debugfile, const HA_Message *msg); #define crm_log_message(level, msg) if(crm_log_level >= level) { \ crm_log_message_adv(level, NULL, msg); \ } #define crm_do_action(level, actions) if(crm_log_level >= level) { \ actions; \ } #define crm_action_info(x) crm_do_action(LOG_INFO, x) #define crm_action_debug(x) crm_do_action(LOG_DEBUG, x) #define crm_action_debug_2(x) crm_do_action(LOG_DEBUG_2, x) #define crm_action_debug_3(x) crm_do_action(LOG_DEBUG_3, x) #define crm_action_debug_4(x) crm_do_action(LOG_DEBUG_4, x) #define crm_log_xml(level, text, xml) if(crm_log_level >= level) { \ print_xml_formatted(level, __FUNCTION__, xml, text); \ } #define crm_log_xml_crit(xml, text) crm_log_xml(LOG_CRIT, text, xml) #define crm_log_xml_err(xml, text) crm_log_xml(LOG_ERR, text, xml) #define crm_log_xml_warn(xml, text) crm_log_xml(LOG_WARNING, text, xml) #define crm_log_xml_notice(xml, text) crm_log_xml(LOG_NOTICE, text, xml) #define crm_log_xml_info(xml, text) crm_log_xml(LOG_INFO, text, xml) #define crm_log_xml_debug(xml, text) crm_log_xml(LOG_DEBUG, text, xml) #define crm_log_xml_debug_2(xml, text) crm_log_xml(LOG_DEBUG_2, text, xml) #define crm_log_xml_debug_3(xml, text) crm_log_xml(LOG_DEBUG_3, text, xml) #define crm_log_xml_debug_4(xml, text) crm_log_xml(LOG_DEBUG_4, text, xml) #define crm_log_xml_debug_5(xml, text) crm_log_xml(LOG_DEBUG_5, text, xml) #define crm_str(x) (const char*)(x?x:"") #if CRM_USE_MALLOC # define crm_malloc0(new_obj,length) \ { \ new_obj = malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ exit(1); \ } else { \ memset(new_obj, 0, length); \ } \ } # define crm_free(x) if(x) { free(x); x=NULL; } # define crm_is_allocated(obj) obj?TRUE:FALSE #else # if CRM_DEV_BUILD # define crm_malloc0(new_obj,length) \ { \ if(new_obj) { \ crm_err("Potential memory leak:" \ " %s at %s:%d not NULL before alloc.", \ #new_obj, __FILE__, __LINE__); \ abort(); \ } \ new_obj = cl_malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ abort(); \ } \ memset(new_obj, 0, length); \ } #else # define crm_malloc0(new_obj,length) \ { \ new_obj = cl_malloc(length); \ if(new_obj == NULL) { \ crm_crit("Out of memory... exiting"); \ abort(); \ } \ memset(new_obj, 0, length); \ } # endif # define crm_free(x) if(x) { \ CRM_ASSERT(cl_is_allocated(x) == 1); \ cl_free(x); \ x=NULL; \ } # define crm_is_allocated(obj) cl_is_allocated(obj) #endif #define crm_msg_del(msg) if(msg != NULL) { ha_msg_del(msg); msg = NULL; } #endif diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h index 5b6e7fe95d..53a1f08184 100644 --- a/include/crm/msg_xml.h +++ b/include/crm/msg_xml.h @@ -1,223 +1,223 @@ -/* $Id: msg_xml.h,v 1.40 2005/08/08 12:09:33 andrew Exp $ */ +/* $Id: msg_xml.h,v 1.41 2005/08/10 08:55:04 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 XML_TAGS__H #define XML_TAGS__H #define F_CRM_TASK "crm_task" #define F_CRM_HOST_TO "crm_host_to" #define F_CRM_MSG_TYPE F_SUBTYPE #define F_CRM_SYS_TO "crm_sys_to" #define F_CRM_SYS_FROM "crm_sys_from" #define F_CRM_HOST_FROM F_ORIG #define F_CRM_REFERENCE XML_ATTR_REFERENCE #define F_CRM_VERSION XML_ATTR_VERSION #define F_CRM_ORIGIN "origin" #define F_CRM_JOIN_ID "join_id" /*---- Common tags/attrs */ #define XML_ATTR_TAGNAME F_XML_TAGNAME #define XML_ATTR_PARENT F_XML_PARENT #define XML_TAG_CIB "cib" #define XML_TAG_FAILED "failed" #define XML_ATTR_NUMPEERS "num_peers" #define XML_ATTR_HAVE_QUORUM "have_quorum" #define XML_ATTR_CCM_TRANSITION "ccm_transition" #define XML_ATTR_GENERATION "epoch" #define XML_ATTR_GENERATION_ADMIN "admin_epoch" #define XML_ATTR_NUMUPDATES "num_updates" #define XML_ATTR_TIMEOUT "timeout" #define XML_ATTR_TSTAMP "timestamp" #define XML_ATTR_VERSION "version" #define XML_ATTR_DESC "description" #define XML_ATTR_ID "id" #define XML_ATTR_TYPE "type" #define XML_ATTR_FILTER_TYPE "type_filter" #define XML_ATTR_FILTER_ID "id_filter" #define XML_ATTR_FILTER_PRIORITY "priority_filter" #define XML_ATTR_VERBOSE "verbose" #define XML_ATTR_OP "op" #define XML_ATTR_DC "is_dc" #define XML_ATTR_DC_UUID "dc_uuid" #define XML_ATTR_CIB_REVISION "cib_feature_revision" #define XML_ATTR_CIB_REVISION_MAX "cib_feature_revision_max" #define XML_BOOLEAN_TRUE "true" #define XML_BOOLEAN_FALSE "false" #define XML_BOOLEAN_YES XML_BOOLEAN_TRUE #define XML_BOOLEAN_NO XML_BOOLEAN_FALSE #define XML_TAG_OPTIONS "options" /*---- top level tags/attrs */ #define XML_MSG_TAG "crm_message" #define XML_MSG_TAG_DATA "msg_data" #define XML_ATTR_REQUEST "request" #define XML_ATTR_RESPONSE "response" #define XML_ATTR_UNAME "uname" #define XML_ATTR_UUID "id" #define XML_ATTR_REFERENCE "reference" #define XML_FAIL_TAG_RESOURCE "failed_resource" #define XML_FAILRES_ATTR_RESID "resource_id" #define XML_FAILRES_ATTR_REASON "reason" #define XML_FAILRES_ATTR_RESSTATUS "resource_status" #define XML_CRM_TAG_PING "ping_response" #define XML_PING_ATTR_STATUS "result" #define XML_PING_ATTR_SYSFROM "crm_subsystem" #define XML_TAG_FRAGMENT "cib_fragment" #define XML_ATTR_RESULT "result" #define XML_ATTR_SECTION "section" #define XML_FAIL_TAG_CIB "failed_update" #define XML_FAILCIB_ATTR_ID "id" #define XML_FAILCIB_ATTR_OBJTYPE "object_type" #define XML_FAILCIB_ATTR_OP "operation" #define XML_FAILCIB_ATTR_REASON "reason" /*---- CIB specific tags/attrs */ #define XML_CIB_TAG_SECTION_ALL "all" #define XML_CIB_TAG_CONFIGURATION "configuration" #define XML_CIB_TAG_STATUS "status" #define XML_CIB_TAG_RESOURCES "resources" #define XML_CIB_TAG_NODES "nodes" #define XML_CIB_TAG_CONSTRAINTS "constraints" #define XML_CIB_TAG_CRMCONFIG "crm_config" #define XML_CIB_TAG_STATE "node_state" #define XML_CIB_TAG_NODE "node" #define XML_CIB_TAG_CONSTRAINT "constraint" #define XML_CIB_TAG_NVPAIR "nvpair" #define XML_TAG_ATTR_SETS "instance_attributes" #define XML_TAG_ATTRS "attributes" #define XML_CIB_TAG_RESOURCE "primitive" #define XML_CIB_TAG_GROUP "group" #define XML_CIB_TAG_INCARNATION "clone" #define XML_RSC_ATTR_STOPFAIL "on_stopfail" #define XML_RSC_ATTR_RESTART "restart_type" #define XML_RSC_ATTR_START_TIMEOUT "start_timeout" #define XML_RSC_ATTR_STOP_TIMEOUT "stop_timeout" #define XML_RSC_ATTR_ORDERED "ordered" #define XML_RSC_ATTR_INTERLEAVE "interleave" #define XML_RSC_ATTR_INCARNATION "clone" #define XML_RSC_ATTR_INCARNATION_MAX "clone_max" #define XML_RSC_ATTR_INCARNATION_NODEMAX "clone_node_max" #define XML_CIB_TAG_LRM "lrm" #define XML_LRM_TAG_RESOURCES "lrm_resources" #define XML_LRM_TAG_RESOURCE "lrm_resource" #define XML_LRM_TAG_AGENTS "lrm_agents" #define XML_LRM_TAG_AGENT "lrm_agent" #define XML_LRM_TAG_RSC_OP "lrm_rsc_op" #define XML_AGENT_ATTR_CLASS "class" #define XML_AGENT_ATTR_PROVIDER "provider" #define XML_LRM_TAG_ATTRIBUTES "attributes" #define XML_CIB_ATTR_REPLACE "replace" #define XML_CIB_ATTR_SOURCE "source" #define XML_CIB_ATTR_HEALTH "health" #define XML_CIB_ATTR_WEIGHT "weight" #define XML_CIB_ATTR_PRIORITY "priority" #define XML_CIB_ATTR_CLEAR "clear_on" #define XML_CIB_ATTR_SOURCE "source" #define XML_CIB_ATTR_JOINSTATE "join" #define XML_CIB_ATTR_EXPSTATE "expected" #define XML_CIB_ATTR_INCCM "in_ccm" #define XML_CIB_ATTR_CRMDSTATE "crmd" #define XML_CIB_ATTR_HASTATE "ha" #define XML_CIB_ATTR_SHUTDOWN "shutdown" #define XML_CIB_ATTR_CLEAR_SHUTDOWN "clear_shutdown" #define XML_CIB_ATTR_STONITH "stonith" #define XML_CIB_ATTR_CLEAR_STONITH "clear_stonith" #define XML_LRM_ATTR_TASK "operation" -#define XML_LRM_ATTR_TASK_UUID "operation_uuid" +#define XML_LRM_ATTR_TASK_KEY "operation_key" #define XML_LRM_ATTR_TARGET "on_node" #define XML_LRM_ATTR_TARGET_UUID "on_node_uuid" #define XML_LRM_ATTR_RSCSTATE "rsc_state" #define XML_LRM_ATTR_RSCID "rsc_id" #define XML_LRM_ATTR_LASTOP "last_op" #define XML_LRM_ATTR_OPSTATUS "op_status" #define XML_LRM_ATTR_RC "rc_code" #define XML_LRM_ATTR_CALLID "call_id" #define XML_TAG_GRAPH "transition_graph" #define XML_GRAPH_TAG_RSC_OP "rsc_op" #define XML_GRAPH_TAG_PSEUDO_EVENT "pseudo_event" #define XML_GRAPH_TAG_CRM_EVENT "crm_event" #define XML_TAG_RULE "rule" #define XML_RULE_ATTR_SCORE "score" #define XML_RULE_ATTR_RESULT "result" #define XML_RULE_ATTR_BOOLEAN_OP "boolean_op" #define XML_TAG_EXPRESSION "expression" #define XML_EXPR_ATTR_ATTRIBUTE "attribute" #define XML_EXPR_ATTR_OPERATION "operation" #define XML_EXPR_ATTR_VALUE "value" #define XML_EXPR_ATTR_TYPE "type" #define XML_CONS_TAG_RSC_DEPEND "rsc_colocation" #define XML_CONS_TAG_RSC_ORDER "rsc_order" #define XML_CONS_TAG_RSC_LOCATION "rsc_location" #define XML_CONS_ATTR_FROM "from" #define XML_CONS_ATTR_TO "to" #define XML_CONS_ATTR_ACTION "action" #define XML_CONS_ATTR_SYMMETRICAL "symmetrical" #define XML_NVPAIR_ATTR_NAME "name" #define XML_NVPAIR_ATTR_VALUE "value" #define XML_STRENGTH_VAL_MUST "must" #define XML_STRENGTH_VAL_SHOULD "should" #define XML_STRENGTH_VAL_SHOULDNOT "should_not" #define XML_STRENGTH_VAL_MUSTNOT "must_not" #define XML_NODE_ATTR_STATE "state" #define XML_CONFIG_ATTR_DC_BEAT "dc_heartbeat" #define XML_CONFIG_ATTR_DC_DEADTIME "dc_deadtime" #define XML_CONFIG_ATTR_FORCE_QUIT "shutdown_escalation" #define XML_CONFIG_ATTR_REANNOUNCE "join_reannouce" #define XML_CIB_TAG_GENERATION_TUPPLE "generation_tuple" #define XML_ATTR_TRANSITION_MAGIC "transition_magic" #define XML_ATTR_TRANSITION_KEY "transition_key" #include #define ID(x) crm_element_value(x, XML_ATTR_ID) #define INSTANCE(x) crm_element_value(x, XML_CIB_ATTR_INSTANCE) #define TSTAMP(x) crm_element_value(x, XML_ATTR_TSTAMP) #define TYPE(x) crm_element_name(x) #endif