diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index fbf047fbb9..44bd4dc44b 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,1635 +1,1638 @@ /* * 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); gboolean is_rsc_active(const char *rsc_id); 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, HA_Message *request); 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); lrm_op_t *construct_op( crm_data_t *rsc_op, const char *rsc_id, const char *operation); void send_direct_ack(const char *to_host, const char *to_sys, lrm_op_t* op, const char *rsc_id); void free_recurring_op(gpointer value); 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; 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 }; 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 ""; } GCHSource *lrm_source = NULL; /* 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(lrm_source) { crm_debug("Removing LRM connection from MainLoop"); if(G_main_del_IPC_Channel(lrm_source) == FALSE) { crm_err("Could not remove LRM connection" " from MainLoop"); } lrm_source = NULL; } if(fsa_lrm_conn) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); crm_info("Disconnected from the LRM"); clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); fsa_lrm_conn = NULL; } /* TODO: Clean up the hashtable */ } if(action & A_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("Connecting to the LRM"); 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 */ lrm_source = 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); crm_debug("LRM connection established"); } 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("Making 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, if(is_rsc_active(rsc_id)) { crm_err("Resource %s was active at shutdown." " You may ignore this error if it is unmanaged.", rsc_id); /* do_lrm_rsc_op(NULL, rsc_id, CRMD_ACTION_STOP, NULL, 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; const char *caller_version = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return FALSE; } crm_debug_2("%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_3("Ignoring cancelled op"); return TRUE; } 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); } /* 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; } } xml_op = find_entity(xml_rsc, XML_LRM_TAG_RSC_OP, op_id); if(xml_op != NULL) { const char *old_status_s = crm_element_value( xml_op, XML_LRM_ATTR_OPSTATUS); int old_status = crm_parse_int(old_status_s, "-2"); int log_level = LOG_ERR; if(old_status_s == NULL) { crm_err("No value for "XML_LRM_ATTR_OPSTATUS); } else if(old_status == op->op_status) { /* safe to mask */ log_level = LOG_WARNING; } else if(old_status == LRM_OP_PENDING){ /* ??safe to mask?? */ /* log_level = LOG_WARNING; */ } crm_log_maybe(log_level, "Duplicate %s operations in get_cur_state()", op_id); crm_log_maybe(log_level+2, "New entry: %s %s (call=%d, status=%s)", op_id, op->user_data, op->call_id, op_status2text(op->op_status)); crm_log_xml(log_level+2, "Existing entry", xml_op); crm_free(op_id); return FALSE; } else { xml_op = create_xml_node(xml_rsc, XML_LRM_TAG_RSC_OP); } crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, op->op_type); crm_xml_add(xml_op, "origin", src); if(op->user_data == NULL) { op->user_data = generate_transition_key(-1, fsa_our_uname); } #if CRM_DEPRECATED_SINCE_2_0_3 caller_version = g_hash_table_lookup(op->params, XML_ATTR_CRM_VERSION); if(compare_version("1.0.3", caller_version) > 0) { CRM_CHECK(FALSE, ; ); fail_state = generate_transition_magic_v202( op->user_data, op->op_status); } else { fail_state = generate_transition_magic( op->user_data, op->op_status, op->rc); } #else fail_state = generate_transition_magic( op->user_data, op->op_status, op->rc); #endif 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_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); 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_free(tmp); tmp = crm_itoa(op->op_status); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, tmp); crm_free(tmp); set_node_tstamp(xml_op); #if 1 if(safe_str_neq(op->op_type, CRMD_ACTION_STOP)) { /* this will enable us to later determin that the * resource's parameters have changed and we should force * a restart * however it will come at the cost of a potentially much * larger CIB */ crm_data_t *args_xml = NULL; args_xml = create_xml_node(xml_op, XML_TAG_PARAMS); g_hash_table_foreach(op->params, hash2field, args_xml); } #endif return TRUE; } gboolean is_rsc_active(const char *rsc_id) { GList *op_list = NULL; gboolean active = FALSE; lrm_rsc_t *the_rsc = NULL; state_flag_t cur_state = 0; int max_call_id = -1; if(fsa_lrm_conn == NULL) { return FALSE; } the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rsc_id); crm_debug_2("Processing lrm_rsc_t entry %s", rsc_id); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); return FALSE; } op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_debug_3("\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); CRM_ASSERT(max_call_id <= op->call_id); if(safe_str_eq(op->op_type, CRMD_ACTION_STOP)) { active = FALSE; } else if(op->rc == EXECRA_NOT_RUNNING) { active = FALSE; } else { active = TRUE; } max_call_id = op->call_id; lrm_free_op(op); ); g_list_free(op_list); lrm_free_rsc(the_rsc); return active; } 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); crm_xml_add(xml_rsc, XML_ATTR_TYPE, the_rsc->type); crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, the_rsc->class); crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER,the_rsc->provider); 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_warn("lrm->get_cur_state() returned" " duplicate entries for call_id=%d", op->call_id); } max_call_id = op->call_id; found_op = TRUE; lrm_free_op(op); ); if(found_op == FALSE && g_list_length(op_list) != 0) { 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); lrm_free_rsc(the_rsc); ); g_list_free(lrm_list); return TRUE; } crm_data_t* do_lrm_query(gboolean is_replace) { gboolean shut_down = FALSE; crm_data_t *xml_result= NULL; crm_data_t *xml_state = NULL; crm_data_t *xml_data = NULL; crm_data_t *rsc_list = NULL; const char *exp_state = CRMD_JOINSTATE_MEMBER; if(is_set(fsa_input_register, R_SHUTDOWN)) { exp_state = CRMD_STATE_INACTIVE; shut_down = TRUE; } xml_state = create_node_state( fsa_our_uname, ACTIVESTATUS, XML_BOOLEAN_TRUE, ONLINESTATUS, CRMD_JOINSTATE_MEMBER, exp_state, !shut_down, __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, XML_CIB_TAG_STATUS); crm_log_xml_debug_3(xml_state, "Current state of the LRM"); return xml_result; } struct recurring_op_s { char *rsc_id; int call_id; }; static void cancel_monitor(lrm_rsc_t *rsc, const char *key) { struct recurring_op_s *existing_op = NULL; if(rsc == NULL) { crm_err("No resource to cancel and operation for"); return; } else if(key == NULL) { crm_err("No operation to cancel"); return; } existing_op = g_hash_table_lookup(monitors, key); if(existing_op != NULL) { crm_debug("Cancelling previous invocation of %s (%d)", key, existing_op->call_id); /* cancel it so we can then restart it without conflict */ if(rsc->ops->cancel_op(rsc, existing_op->call_id) != HA_OK) { crm_info("Couldn't cancel %s (%d)", key, existing_op->call_id); } else { g_hash_table_remove(monitors, key); } } else { crm_debug("No previous invocation of %s", key); } } /* static gboolean is_active(const char *rsc_id) { char *stop_id = NULL; const char *last_op = NULL; gboolean is_active = TRUE; last_op = g_hash_table_lookup(resources, rsc_id); stop_id = generate_op_key(rsc_id, CRMD_ACTION_STOP, 0); if(safe_str_eq(last_op, stop_id)) { is_active = FALSE; } crm_free(stop_id); return is_active; } */ /* 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 *from_sys = NULL; const char *from_host = 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); from_sys = cl_get_string(input->msg, F_CRM_SYS_FROM); if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { from_host = cl_get_string(input->msg, F_CRM_HOST_FROM); } crm_debug_2("LRM command from: %s", from_sys); if(safe_str_eq(crm_op, CRM_OP_LRM_DELETE)) { operation = CRMD_ACTION_DELETE; } else if(safe_str_eq(operation, CRM_OP_LRM_REFRESH)) { crm_op = CRM_OP_LRM_REFRESH; } else if(input->xml != NULL) { operation = crm_element_value(input->xml, XML_LRM_ATTR_TASK); } if(crm_op != NULL && safe_str_eq(crm_op, CRM_OP_LRM_REFRESH)) { enum cib_errors rc = cib_ok; crm_data_t *fragment = do_lrm_query(TRUE); crm_info("Forcing a local LRM refresh"); rc = fsa_cib_conn->cmds->update( fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, cib_quorum_override); free_xml(fragment); } else if(crm_op != NULL && safe_str_eq(crm_op, 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(safe_str_eq(operation, CRM_OP_PROBED) || safe_str_eq(crm_op, CRM_OP_REPROBE)) { char *attr_id = crm_concat("lrm-probe", fsa_our_uuid, '-'); char *attr_set = crm_concat("crmd-transient", fsa_our_uuid,'-'); const char *probed = XML_BOOLEAN_TRUE; if(safe_str_eq(crm_op, CRM_OP_REPROBE)) { probed = XML_BOOLEAN_FALSE; } update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_STATUS, fsa_our_uuid, attr_set, attr_id, CRM_OP_PROBED, probed); crm_free(attr_id); crm_free(attr_set); } else if(operation != NULL) { char rid[64]; lrm_rsc_t *rsc = NULL; const char *id_from_cib = NULL; crm_data_t *xml_rsc = find_xml_node( input->xml, XML_CIB_TAG_RESOURCE, TRUE); CRM_DEV_ASSERT(xml_rsc != NULL); if(crm_assert_failed) { crm_log_xml_err(input->xml, "Bad resource"); return I_NULL; } id_from_cib = crm_element_value(xml_rsc, XML_ATTR_ID); CRM_DEV_ASSERT(id_from_cib != NULL); if(crm_assert_failed) { crm_err("No value for %s in %s", XML_ATTR_ID, crm_element_name(xml_rsc)); 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; crm_debug_2("Retrieving %s from the LRM.", rid); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); if(safe_str_eq(operation, CRMD_ACTION_CANCEL)) { lrm_op_t* op = NULL; crm_data_t *params = NULL; const char *op_key = NULL; const char *op_task = NULL; crm_log_xml_debug(input->xml, "CancelOp"); op_key = crm_element_value(xml_rsc, "operation_key"); params = find_xml_node(input->xml, XML_TAG_ATTRS,TRUE); if(params != NULL) { op_task = crm_element_value(params, "task"); } op = construct_op(input->xml, id_from_cib, op_task); CRM_ASSERT(op != NULL); if(op_key == NULL) { crm_err("No operation to cancel"); crm_log_message(LOG_ERR, input->msg); } else if(rsc != NULL) { cancel_monitor(rsc, op_key); } op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; send_direct_ack(from_host, from_sys, op, id_from_cib); free_lrm_op(op); } else if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { int rc = HA_OK; lrm_op_t* op = NULL; op = construct_op(input->xml, id_from_cib, operation); CRM_ASSERT(op != NULL); op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; if(rsc == NULL) { crm_debug("Resource %s was already removed", id_from_cib); } else { crm_info("Removing resource %s from the LRM", rsc->id); rc = fsa_lrm_conn->lrm_ops->delete_rsc( fsa_lrm_conn, rid); if(rc != HA_OK) { crm_err("Failed to remove resource %s", rid); op->op_status = LRM_OP_ERROR; op->rc = EXECRA_UNKNOWN_ERROR; } } send_direct_ack(from_host, from_sys, op, id_from_cib); free_lrm_op(op); } else { next_input = do_lrm_rsc_op( rsc, rid, operation, input->xml, input->msg); } lrm_free_rsc(rsc); } 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; } lrm_op_t * construct_op(crm_data_t *rsc_op, const char *rsc_id, const char *operation) { lrm_op_t *op = NULL; const char *transition = NULL; CRM_DEV_ASSERT(rsc_id != NULL); crm_malloc0(op, sizeof(lrm_op_t)); op->op_type = crm_strdup(operation); op->op_status = LRM_OP_PENDING; op->rc = -1; op->rsc_id = crm_strdup(rsc_id); op->interval = 0; op->timeout = 0; op->start_delay = 0; op->app_name = crm_strdup(CRM_SYSTEM_CRMD); if(rsc_op == NULL) { CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); op->user_data = NULL; op->user_data_len = 0; /* the stop_all_resources() case * by definition there is no DC (or they'd be shutting * us down). * So we should put our version here. */ op->params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); g_hash_table_insert(op->params, crm_strdup(XML_ATTR_CRM_VERSION), crm_strdup(CRM_FEATURE_SET)); crm_debug_2("Constructed %s op for %s", operation, rsc_id); return op; } op->params = xml2list(rsc_op); #if CRM_DEPRECATED_SINCE_2_0_3 if(g_hash_table_lookup(op->params, XML_ATTR_CRM_VERSION) == NULL) { g_hash_table_destroy(op->params); op->params = xml2list_202(rsc_op); } #endif if(op->params == NULL) { CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); } op->interval = crm_parse_int( g_hash_table_lookup(op->params, "interval"), "0"); op->timeout = crm_parse_int( g_hash_table_lookup(op->params, "timeout"), "0"); op->start_delay = crm_parse_int( g_hash_table_lookup(op->params, "start_delay"), "0"); /* sanity */ if(op->interval < 0) { op->interval = 0; g_hash_table_replace( op->params, crm_strdup("interval"), crm_strdup("0")); } if(op->timeout < 0) { op->timeout = 0; g_hash_table_replace( op->params, crm_strdup("timeout"), crm_strdup("0")); } if(op->start_delay < 0) { op->start_delay = 0; g_hash_table_replace( op->params, crm_strdup("start_delay"), crm_strdup("0")); } transition = crm_element_value(rsc_op, XML_ATTR_TRANSITION_KEY); CRM_CHECK(transition != NULL, return op); op->user_data = crm_strdup(transition); op->user_data_len = 1+strlen(op->user_data); if(safe_str_eq(operation, CRMD_ACTION_START) || safe_str_eq(operation, CRMD_ACTION_STOP)) { char *interval_s = g_hash_table_lookup(op->params, "interval"); CRM_CHECK(op->interval == 0, return NULL); CRM_CHECK(interval_s == NULL, return NULL); } crm_debug_2("Constructed %s op for %s: interval=%d", operation, rsc_id, op->interval); return op; } void send_direct_ack(const char *to_host, const char *to_sys, lrm_op_t* op, const char *rsc_id) { HA_Message *reply = NULL; crm_data_t *update, *iter; crm_data_t *fragment; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return; } if(op->rsc_id == NULL) { CRM_DEV_ASSERT(rsc_id != NULL); op->rsc_id = crm_strdup(rsc_id); } if(to_sys == NULL) { to_sys = CRM_SYSTEM_TENGINE; } crm_info("ACK'ing resource op: %s for %s", op->op_type, op->rsc_id); update = create_node_state( fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); 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, XML_CIB_TAG_STATUS); reply = create_request(CRM_OP_INVOKE_LRM, fragment, to_host, to_sys, CRM_SYSTEM_LRMD, NULL); crm_debug("Sending ACK: %s", cl_get_string(reply, XML_ATTR_REFERENCE)); crm_log_xml_debug_2(update, "ACK Update"); crm_log_message_adv(LOG_DEBUG_3, "ACK Reply", reply); if(relay_message(reply, TRUE) == FALSE) { crm_log_message_adv(LOG_ERR, "Unable to route reply", reply); crm_msg_del(reply); } free_xml(fragment); free_xml(update); } enum crmd_fsa_input do_lrm_rsc_op(lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg, HA_Message *request) { 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) { crm_data_t *xml_rsc = find_xml_node( msg, XML_CIB_TAG_RESOURCE, TRUE); class = crm_element_value(xml_rsc, XML_AGENT_ATTR_CLASS); CRM_DEV_ASSERT(class != NULL); if(crm_assert_failed) { return I_NULL; } type = crm_element_value(xml_rsc, XML_ATTR_TYPE); CRM_DEV_ASSERT(type != NULL); if(crm_assert_failed) { return I_NULL; } provider = crm_element_value(xml_rsc, XML_AGENT_ATTR_PROVIDER); } 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(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("adding rsc %s before operation", rid); if(msg != NULL) { params = xml2list(msg); #if CRM_DEPRECATED_SINCE_2_0_3 if(g_hash_table_lookup( params, XML_ATTR_CRM_VERSION) == NULL) { g_hash_table_destroy(params); params = xml2list_202(msg); } #endif } 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); g_hash_table_destroy(params); } 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 */ op = construct_op(msg, rsc->id, operation); crm_info("Performing op %s on %s (interval=%dms)", operation, rid, op->interval); if((AM_I_DC == FALSE && fsa_state != S_NOT_DC) || (AM_I_DC && fsa_state != S_TRANSITION_ENGINE)) { if(safe_str_neq(operation, CRMD_ACTION_STOP)) { crm_info("Discarding attempt to perform action %s on %s" " in state %s", operation, rid, fsa_state2string(fsa_state)); op->rc = 99; op->op_status = LRM_OP_ERROR; send_direct_ack(NULL, NULL, op, rsc->id); free_lrm_op(op); crm_free(op_id); return I_NULL; } } op_id = generate_op_key(rsc->id, op->op_type, op->interval); if(op->interval > 0) { cancel_monitor(rsc, op_id); op->target_rc = CHANGED; } else { op->target_rc = EVERYTIME; } g_hash_table_replace(resources,crm_strdup(rsc->id), crm_strdup(op_id)); 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_2("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_2("Recording pending op: %s/%s %s", rsc->id, operation, 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); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { 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; /* in the CRM, this is always a string */ 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); 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 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; } static void update_failcount(lrm_op_t *op) { const char *probe_s = NULL; int op_status = LRM_OP_DONE; const char *target_rc_s = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_is_true(probe_s)) { return; } probe_s = g_hash_table_lookup(op->params, XML_ATTR_LRM_PROBE); if(crm_is_true(probe_s)) { return; } CRM_DEV_ASSERT(op->op_status != LRM_OP_PENDING); if(crm_assert_failed) { return; } CRM_DEV_ASSERT(op->op_status != LRM_OP_DONE); if(crm_assert_failed) { return; } op_status = op->op_status; target_rc_s = g_hash_table_lookup(op->params, XML_ATTR_TE_TARGET_RC); if(target_rc_s != NULL) { int target_rc = crm_parse_int(target_rc_s, NULL); if(target_rc == op->rc) { if(op_status != LRM_OP_DONE) { op_status = LRM_OP_DONE; } } else if(op_status != LRM_OP_ERROR) { op_status = LRM_OP_ERROR; } } if(op_status != LRM_OP_DONE) { char *attr_set = crm_concat("crmd-transient",fsa_our_uuid, '-'); char *attr_name = crm_concat("fail-count", op->rsc_id, '-'); char *attr_id = crm_concat(attr_name, fsa_our_uuid, '-'); + + crm_warn("Updating failcount for %s after failed %s: rc=%d", + op->rsc_id, op->op_type, op->rc); update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_STATUS, fsa_our_uuid, attr_set, attr_id, attr_name, XML_NVPAIR_ATTR_VALUE"++"); crm_free(attr_id); crm_free(attr_set); crm_free(attr_name); } } void do_update_resource(lrm_op_t* op) { /* */ int rc = cib_ok; crm_data_t *fragment; crm_data_t *update, *iter; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return; } update = create_node_state( fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); 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); if(op->interval == 0) { lrm_rsc_t *rsc = NULL; crm_debug_2("Updating %s resource definitions after %s op", op->rsc_id, op->op_type); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, op->rsc_id); crm_xml_add(iter, XML_ATTR_TYPE, rsc->type); crm_xml_add(iter, XML_AGENT_ATTR_CLASS, rsc->class); crm_xml_add(iter, XML_AGENT_ATTR_PROVIDER,rsc->provider); lrm_free_rsc(rsc); } build_operation_update(iter, op, __FUNCTION__, 0); fragment = create_cib_fragment(update, XML_CIB_TAG_STATUS); /* 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->update( 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; const char *probe_s = NULL; gboolean is_probe = FALSE; - int log_rsc_err = LOG_ERR; + int log_rsc_err = LOG_WARNING; gboolean set_failcount = FALSE; 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; } probe_s = g_hash_table_lookup(op->params, XML_ATTR_LRM_PROBE); is_probe = crm_is_true(probe_s); switch(op->op_status) { case LRM_OP_PENDING: /* this really shouldnt happen */ crm_err("LRM operation (%d) %s_%d on %s %s: %s", op->call_id, op->op_type, op->interval, crm_str(op->rsc_id), op_status2text(op->op_status), execra_code2string(op->rc)); break; case LRM_OP_ERROR: if(is_probe) { log_rsc_err = LOG_INFO; } else { set_failcount = TRUE; } crm_log_maybe(log_rsc_err, - "LRM operation (%d) %s_%d on %s %s: %s", + "LRM operation (%d) %s_%d on %s %s: (%d) %s", op->call_id, op->op_type, op->interval, crm_str(op->rsc_id), op_status2text(op->op_status), - execra_code2string(op->rc)); + op->rc, execra_code2string(op->rc)); crm_debug("Result: %s", op->output); break; case LRM_OP_CANCELLED: crm_warn("LRM operation (%d) %s_%d on %s %s", op->call_id, op->op_type, op->interval, crm_str(op->rsc_id), op_status2text(op->op_status)); return I_NULL; break; case LRM_OP_TIMEOUT: set_failcount = TRUE; 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_%d on %s %s", op->call_id, op->op_type, op->interval, crm_str(op->rsc_id), op_status2text(op->op_status)); break; case LRM_OP_NOTSUPPORTED: set_failcount = TRUE; crm_err("LRM operation (%d) %s_%d on %s %s", op->call_id, op->op_type, op->interval, crm_str(op->rsc_id), op_status2text(op->op_status)); break; case LRM_OP_DONE: crm_info("LRM operation (%d) %s_%d on %s %s", op->call_id, op->op_type, op->interval, 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(set_failcount) { update_failcount(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_2("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_info("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/pengine/native.c b/crm/pengine/native.c index 56182a8765..01f63bef72 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,2006 +1,2044 @@ -/* $Id: native.c,v 1.119 2006/03/27 10:03:55 andrew Exp $ */ +/* $Id: native.c,v 1.120 2006/03/27 15:53:10 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 #define DELETE_THEN_REFRESH 1 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_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, 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_notifications(resource_t *rsc, pe_working_set_t *data_set); void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); void pe_pre_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); void pe_post_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set); gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set); enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, }, /* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, }, /* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, }; gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, }, /* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, }, /* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, }, /* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, }, /* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, }, }; typedef struct native_variant_data_s { /* 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) { CRM_CHECK(node != NULL, return); slist_iter( a_node, node_t, rsc->running_on, lpc, CRM_CHECK(a_node != NULL, return); if(safe_str_eq(a_node->details->id, node->details->id)) { return; } ); rsc->running_on = g_list_append(rsc->running_on, node); if(rsc->variant == pe_native) { node->details->running_rsc = g_list_append( node->details->running_rsc, rsc); } if(rsc->variant != pe_native) { } else if(rsc->is_managed == FALSE) { crm_info("resource %s isnt managed", rsc->id); rsc2node_new( "not_managed_default", rsc, INFINITY, node, data_set); return; #if 0 } else if(rsc->failed) { crm_info("Skipping resource stickiness for failed resource %s", rsc->id); #endif } else if(rsc->stickiness > 0 || rsc->stickiness < 0) { rsc2node_new("stickiness", rsc, rsc->stickiness, node,data_set); crm_debug("Resource %s: preferring current location (%s/%s)", rsc->id, node->details->uname, node->details->id); } if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *class = crm_element_value( rsc->xml, XML_AGENT_ATTR_CLASS); /* these are errors because hardly any gets it right * at the moment and this way the might notice */ pe_err("Resource %s::%s:%s appears to be active on %d nodes.", class, type, rsc->id, g_list_length(rsc->running_on)); cl_log(LOG_ERR, "See %s for more information.", HAURL("v2/faq/resource_too_active")); if(rsc->recovery_type == recovery_stop_only) { native_assign_color(rsc, data_set->no_color); } else if(rsc->recovery_type == recovery_block) { rsc->is_managed = FALSE; } } else { crm_debug_2("Resource %s is active on: %s", rsc->id, node->details->uname); } if(rsc->parent != NULL) { native_add_running(rsc->parent, node, data_set); } } void native_unpack(resource_t *rsc, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(native_data, sizeof(native_variant_data_t)); rsc->allowed_nodes = NULL; rsc->running_on = NULL; rsc->variant_opaque = native_data; } resource_t * native_find_child(resource_t *rsc, const char *id) { return NULL; } GListPtr native_children(resource_t *rsc) { return NULL; } static void hash_copy_field(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; GHashTable *hash_copy = user_data; g_hash_table_insert(hash_copy, crm_strdup(name), crm_strdup(s_value)); } char * native_parameter( resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set) { char *value_copy = NULL; const char *value = NULL; CRM_CHECK(rsc != NULL, return NULL); crm_debug_2("Looking up %s in %s", name, rsc->id); if(create) { GHashTable *local_hash = NULL; if(node != NULL) { crm_debug_2("Creating hash with node %s", node->details->uname); } else { crm_debug_2("Creating default hash"); } local_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); g_hash_table_foreach( rsc->parameters, hash_copy_field, local_hash); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, node, local_hash, NULL, 0, data_set); value = g_hash_table_lookup(local_hash, name); if(value != NULL) { value_copy = crm_strdup(value); } g_hash_table_destroy(local_hash); } else { value = g_hash_table_lookup(rsc->parameters, name); if(value != NULL) { value_copy = crm_strdup(value); } } return value_copy; } int native_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; if(rsc->color) { crm_debug_4("Colored case"); num_nodes = num_allowed_nodes4color(rsc->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, rsc->allowed_nodes, lpc, crm_debug_3("Rsc %s Checking %s: %d", 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: %d", 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; } color_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *new_color = NULL; print_resource(LOG_DEBUG_2, "Coloring: ", rsc, FALSE); if(rsc->provisional == FALSE) { return rsc->color; } rsc->rsc_cons = g_list_sort( rsc->rsc_cons, sort_cons_strength); /*------ Pre-processing */ slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Pre-Processing constraint", constraint,FALSE)); rsc->fns->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); if( native_choose_color(rsc, data_set->no_color) ) { crm_debug_3("Colored resource %s with color %d", rsc->id, rsc->color->id); new_color = rsc->color; } else { if(rsc->allowed_nodes != NULL) { /* filter out nodes with a negative weight */ filter_nodes(rsc); new_color = create_color(data_set, rsc, rsc->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { pe_warn("Resource %s cannot run anywhere", rsc->id); print_resource(LOG_ERR, "No color: ", rsc, FALSE); native_assign_color(rsc, data_set->no_color); new_color = data_set->no_color; } } rsc->provisional = FALSE; /*------ Post-processing */ #if 1 slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Post-Processing constraint",constraint,FALSE)); rsc->fns->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); #endif print_resource(LOG_DEBUG_3, "Colored", rsc, TRUE); return new_color; } void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { char *key = NULL; const char *name = NULL; const char *value = NULL; + const char *interval = NULL; const char *node_uname = NULL; int interval_ms = 0; action_t *mon = NULL; 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_filter( rsc->ops_xml, operation, "op", - + name = crm_element_value(operation, "name"); - value = crm_element_value(operation, "interval"); - interval_ms = crm_get_msec(value); + interval = crm_element_value(operation, "interval"); + interval_ms = crm_get_msec(interval); if(interval_ms <= 0) { continue; } - value = crm_element_value(operation, "role"); - if(start != NULL && value != NULL - && text2role(value) != start->rsc->next_role) { - crm_debug_2("Skipping action %s::%s(%s) : %s", - start->rsc->id, name, value, - role2text(start->rsc->next_role)); - continue; - } - - key = generate_op_key(rsc->graph_name, name, interval_ms); if(start != NULL) { crm_debug_3("Marking %s %s due to %s", key, start->optional?"optional":"manditory", start->uuid); is_optional = start->optional; } else { crm_debug_2("Marking %s optional", key); is_optional = TRUE; } /* start a monitor for an already active resource */ possible_matches = find_actions_exact(rsc->actions, key, node); if(possible_matches == NULL) { is_optional = FALSE; crm_debug_3("Marking %s manditory: not active", key); } + + value = crm_element_value(operation, "role"); + if((rsc->next_role == RSC_ROLE_MASTER && value == NULL) + || (value != NULL && text2role(value) != rsc->next_role)) { + int log_level = LOG_DEBUG_2; + const char *foo = "Ignoring"; + if(is_optional) { + log_level = LOG_INFO; + foo = "Cancelling"; + /* its running : cancel it */ + + mon = custom_action( + rsc, crm_strdup(key), CRMD_ACTION_CANCEL, node, + FALSE, TRUE, data_set); + + mon->task = CRMD_ACTION_CANCEL; + add_hash_param(mon->extra, "interval", interval); + add_hash_param(mon->extra, "task", name); + + custom_action_order( + rsc, NULL, mon, + rsc, promote_key(rsc), NULL, + pe_ordering_optional, data_set); + + mon = NULL; + } + + crm_log_maybe(log_level, "%s action %s (%s vs. %s)", + foo , key, value?value:role2text(RSC_ROLE_SLAVE), + role2text(rsc->next_role)); + crm_free(key); + key = NULL; + continue; + } mon = custom_action(rsc, key, name, node, is_optional, TRUE, data_set); if(is_optional) { crm_debug("%s\t %s (optional)", crm_str(node_uname), mon->uuid); } if(start == NULL || start->runnable == FALSE) { crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_notice("%s\t %s", crm_str(node_uname),mon->uuid); } + custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_ordering_restart, data_set); + + if(rsc->next_role == RSC_ROLE_MASTER) { + char *running_master = crm_itoa(EXECRA_RUNNING_MASTER); + add_hash_param(mon->extra, XML_ATTR_TE_TARGET_RC, running_master); + custom_action_order( + rsc, promote_key(rsc), NULL, + rsc, NULL, mon, + pe_ordering_optional, data_set); + crm_free(running_master); + } ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; node_t *chosen = NULL; enum rsc_role_e role = RSC_ROLE_UNKNOWN; enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; if(rsc->color != NULL) { chosen = rsc->color->details->chosen_node; } unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, chosen, rsc->parameters, NULL, 0, data_set); crm_debug("%s: %s->%s", rsc->id, role2text(rsc->role), role2text(rsc->next_role)); if(g_list_length(rsc->running_on) > 1) { if(rsc->recovery_type == recovery_stop_start) { pe_err("Attempting recovery of resource %s", rsc->id); StopRsc(rsc, NULL, data_set); rsc->role = RSC_ROLE_STOPPED; } } else if(rsc->running_on != NULL) { node_t *current = rsc->running_on->data; NoRoleChange(rsc, current, chosen, data_set); } else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) { char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, NULL); slist_iter( action, action_t, possible_matches, lpc, action->optional = TRUE; /* action->pseudo = TRUE; */ ); crm_debug_2("Stopping a stopped resource"); crm_free(key); return; } role = rsc->role; while(role != rsc->next_role) { next_role = rsc_state_matrix[role][rsc->next_role]; crm_debug_2("Executing: %s->%s (%s)", role2text(role), role2text(next_role), rsc->id); if(rsc_action_matrix[role][next_role]( rsc, chosen, data_set) == FALSE) { break; } role = next_role; } if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) { start = start_action(rsc, chosen, TRUE); Recurring(rsc, start, chosen, data_set); } } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { order_restart(rsc); } void native_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(rsc_lh == 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; } crm_debug_2("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id); rsc_rh->fns->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); } static gboolean filter_colocation_constraint( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_debug_4("Skipping constraint type %d", constraint->strength); return FALSE; } if(constraint->state_lh != NULL && text2role(constraint->state_lh) != rsc_lh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } if(constraint->state_rh != NULL && text2role(constraint->state_rh) != rsc_rh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } return TRUE; } void native_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_check = FALSE; gboolean update_lh = FALSE; gboolean update_rh = FALSE; crm_debug_2("%sColocating %s with %s (%s)", constraint->strength == pecs_must?"":"Anti-", rsc_lh->id, rsc_rh->id, constraint->id); if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { return; } if(rsc_lh->provisional && rsc_rh->provisional) { if(constraint->strength == pecs_must) { /* update effective_priorities */ crm_debug_3("Priority update"); 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) && (!rsc_lh->color->details->pending) && (!rsc_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 && rsc_lh->color->details->pending == FALSE) { /* update _them_ : postproc color version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE && rsc_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; crm_debug_2("Applying %s (%s) to %s", constraint->id, role2text(constraint->role_filter), rsc->id); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } print_resource(LOG_DEBUG_3, "before update: ", rsc, TRUE); or_list = node_list_or( rsc->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(rsc->allowed_nodes); rsc->allowed_nodes = or_list; slist_iter(node_rh, node_t, constraint->node_list_rh, lpc, native_update_node_weight(rsc, constraint, node_rh, rsc->allowed_nodes) ); print_resource(LOG_DEBUG_3, "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) { slist_iter( a_node, node_t, rsc->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; } struct print_data_s { long options; void *print_data; }; static void native_print_attr(gpointer key, gpointer value, gpointer user_data) { long options = ((struct print_data_s*)user_data)->options; void *print_data = ((struct print_data_s*)user_data)->print_data; status_print("Option: %s = %s\n", (char*)key, (char*)value); } void native_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { node_t *node = NULL; const char *prov = crm_element_value(rsc->xml,XML_AGENT_ATTR_PROVIDER); if(rsc->running_on != NULL) { node = rsc->running_on->data; } if(options & pe_print_html) { if(rsc->is_managed == FALSE) { status_print(""); } else if(rsc->failed) { status_print(""); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) == 0) { status_print(""); } else if(g_list_length(rsc->running_on) > 1) { status_print(""); } else { status_print(""); } } if((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { const char *desc = NULL; desc = crm_element_value(rsc->xml, XML_ATTR_DESC); status_print("%s%s (%s%s%s:%s)%s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), crm_element_value(rsc->xml, XML_ATTR_TYPE), desc?": ":"", desc?desc:""); } else { - status_print("%s%s (%s%s%s:%s):\t%s%s", + status_print("%s%s (%s%s%s:%s):\t%s %s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), crm_element_value(rsc->xml, XML_ATTR_TYPE), - (rsc->variant!=pe_native)?"":node==NULL?"NOT ACTIVE":node->details->uname, + (rsc->variant!=pe_native)?"":role2text(rsc->role), + (rsc->variant!=pe_native)?"":node!=NULL?node->details->uname:"", rsc->is_managed?"":" (unmanaged) "); + #if CURSES_ENABLED if(options & pe_print_ncurses) { move(-1, 0); } #endif } if(options & pe_print_html) { status_print(" "); } if((options & pe_print_rsconly)) { } else if(g_list_length(rsc->running_on) > 1) { if(options & pe_print_html) { status_print("
    \n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("["); } slist_iter(node, node_t, rsc->running_on, lpc, if(options & pe_print_html) { status_print("
  • \n%s", node->details->uname); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\t%s", node->details->uname); } else if((options & pe_print_log)) { status_print("\t%d : %s", lpc, node->details->uname); } else { status_print("%s", node->details->uname); } if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print(" ]"); } } if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\n"); } if(options & pe_print_details) { struct print_data_s pdata; pdata.options = options; pdata.print_data = print_data; g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata); } if(options & pe_print_dev) { status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text, rsc->provisional?"provisional, ":"", rsc->runnable?"":"non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); status_print("%s\t%d candidate colors, %d allowed nodes," " %d rsc_cons", pre_text, g_list_length(rsc->candidate_colors), g_list_length(rsc->allowed_nodes), g_list_length(rsc->rsc_cons)); } if(options & pe_print_max_details) { status_print("%s\t=== Actions.\n", pre_text); slist_iter( action, action_t, rsc->actions, lpc, log_action(LOG_DEBUG_4, "\trsc action: ", action, FALSE); ); status_print("%s\t=== Colors\n", pre_text); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); status_print("%s\t=== Allowed Nodes\n", pre_text); slist_iter( node, node_t, rsc->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void native_free(resource_t *rsc) { crm_debug_4("Freeing Allowed Nodes"); crm_free(rsc->color); common_free(rsc); } void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { gboolean do_merge = FALSE; GListPtr old_list = NULL; GListPtr merged_node_list = NULL; int 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; crm_debug_2("Colocating %s with %s." " Update LHS: %s, Update RHS: %s", rsc_lh->id, rsc_rh->id, update_lh?"true":"false", update_rh?"true":"false"); if(rsc_lh->color && rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } else if(rsc_lh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->allowed_nodes, TRUE); } else if(rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->allowed_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } if(update_lh && rsc_rh != rsc_lh) { CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_lh->color); rsc_lh->runnable = rsc_rh->runnable; rsc_lh->provisional = rsc_rh->provisional; CRM_CHECK(rsc_rh->color != NULL, return); native_assign_color(rsc_lh, rsc_rh->color); } if(update_rh && rsc_rh != rsc_lh) { CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_rh->color); rsc_rh->runnable = rsc_lh->runnable; rsc_rh->provisional = rsc_lh->provisional; CRM_CHECK(rsc_lh->color != NULL, return); native_assign_color(rsc_rh, rsc_lh->color); } if((update_rh || update_lh) && do_merge) { crm_debug_4("Merging candidate nodes"); old_list = rsc_rh->color->details->candidate_nodes; rsc_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; crm_debug_4("Processing pecs_must_not constraint"); /* pecs_must_not */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_lh) { if(rsc_lh->provisional && color_rh != NULL) { color_lh = add_color(rsc_lh, color_rh); color_lh->local_weight = -INFINITY; crm_debug_2("LH: Removed color %d from resource %s", color_lh->id, rsc_lh->id); crm_action_debug_3( print_color("Removed LH", color_lh, FALSE)); print_resource(LOG_DEBUG_3, "Modified LH", rsc_lh,TRUE); } else if(rsc_lh->provisional) { } else if(color_lh && color_lh->details->pending) { node_t *node_lh = NULL; node_lh = pe_find_node_id( color_lh->details->candidate_nodes, safe_val5(NULL, color_rh, details, chosen_node, details, id)); if(node_lh != NULL) { node_lh->weight = -INFINITY; crm_debug_2("LH: Removed node %s from color %d", node_lh->details->uname, color_lh->id); crm_action_debug_3( print_node("Removed LH", node_lh, FALSE)); crm_action_debug_3( print_color("Modified LH", color_lh, FALSE)); } } else { /* error, rsc marked as unrunnable above */ pe_warn("lh else"); } } /* in case anything was modified */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_rh) { if(rsc_rh->provisional && color_lh != NULL) { color_rh = add_color(rsc_lh, color_lh); color_rh->local_weight = -INFINITY; crm_debug_2("RH: Removed color %d from resource %s", color_rh->id, rsc_rh->id); crm_action_debug_3( print_color("Removed RH", color_rh, FALSE)); print_resource(LOG_DEBUG_3, "Modified RH", rsc_rh, TRUE); } else if(rsc_rh->provisional) { } else if(color_rh && color_rh->details->pending) { node_t *node_rh = NULL; node_rh = pe_find_node_id( color_rh->details->candidate_nodes, safe_val5(NULL, color_lh, details, chosen_node, details, id)); if(node_rh != NULL) { node_rh->weight = -INFINITY; crm_debug_2("RH: Removed node %s from color %d", node_rh->details->uname, color_rh->id); crm_action_debug_3( print_node("Removed RH", node_rh, FALSE)); crm_action_debug_3( print_color("Modified RH", color_rh, FALSE)); } } 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; 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_2("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(this_color->local_weight < 0) { /* no valid color available */ crm_debug("no valid color available"); break; } else if(rsc->effective_priority < this_color->details->highest_priority) { minus = node_list_minus( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(minus); pe_free_shallow(minus); } else { intersection = node_list_and( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(intersection); pe_free_shallow(intersection); } if(len > 0) { crm_debug("Assigning color to %s", rsc->id); 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; rsc->provisional = FALSE; CRM_CHECK(local_color != NULL, return); local_color->details->allocated_resources = g_list_append(local_color->details->allocated_resources,rsc); if(rsc->variant == pe_native) { (local_color->details->num_resources)++; rsc->color = copy_color(local_color); crm_debug_3("Created intersection for color %d", local_color->id); intersection = node_list_and( local_color->details->candidate_nodes, rsc->allowed_nodes, FALSE); old_list = local_color->details->candidate_nodes; pe_free_shallow(old_list); local_color->details->candidate_nodes = intersection; } crm_debug_2("Colored resource %s with color %d", rsc->id, local_color->id); print_resource(LOG_DEBUG_3, "Colored Resource", rsc, TRUE); return; } void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, GListPtr nodes) { node_t *node_rh = NULL; CRM_CHECK(cons_node != NULL, return); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); if(node_rh == NULL) { pe_err("Node not found - adding %s to %s", cons_node->details->id, rsc->id); node_rh = node_copy(cons_node); rsc->allowed_nodes = g_list_append( rsc->allowed_nodes, node_rh); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); CRM_CHECK(node_rh != NULL, return); return; } CRM_CHECK(node_rh != NULL, return); if(node_rh == NULL) { pe_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons_node->weight <= -INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } else if(node_rh->details->shutdown == TRUE || node_rh->details->online == FALSE || node_rh->details->unclean == TRUE) { } else if(node_rh->weight <= -INFINITY && cons_node->weight >= INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } if(node_rh->fixed) { /* warning */ crm_debug_2("Constraint %s is irrelevant as the" " weight of node %s is fixed as %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); return; } node_rh->weight = merge_weights(node_rh->weight, cons_node->weight); if(node_rh->weight <= -INFINITY) { crm_debug_3("Constraint %s (-INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else if(node_rh->weight >= INFINITY) { crm_debug_3("Constraint %s (+INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else { crm_debug_3("Constraint %s (%d): node %s weight %d (%s).", cons->id, cons_node->weight, node_rh->details->uname, node_rh->weight, rsc->id); } 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) { 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; color_lh = rsc_lh->color; color_rh = rsc_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) { print_resource(LOG_DEBUG_3, "Filtering nodes for: ", rsc, FALSE); slist_iter( node, node_t, rsc->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)); rsc->allowed_nodes = g_list_remove(rsc->allowed_nodes, node); crm_free(node); lpc = -1; /* restart the loop */ } ); } enum rsc_role_e native_resource_state(resource_t *rsc) { if(rsc->next_role != RSC_ROLE_UNKNOWN) { return rsc->next_role; } if(rsc->role != RSC_ROLE_UNKNOWN) { return rsc->role; } return RSC_ROLE_STOPPED; } void create_notifications(resource_t *rsc, pe_working_set_t *data_set) { if(rsc->notify == FALSE) { return; } /* slist_iter( */ /* action, action_t, rsc->actions, lpc, */ /* ); */ } static void register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = node; switch(task) { case start_rsc: n_data->start = g_list_append(n_data->start, entry); break; case stop_rsc: n_data->stop = g_list_append(n_data->stop, entry); break; case action_promote: n_data->promote = g_list_append(n_data->promote, entry); break; case action_demote: n_data->demote = g_list_append(n_data->demote, entry); break; default: crm_err("Unsupported notify action: %s", task2text(task)); break; } } static void register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = on_node; crm_err("%s state: %s", rsc->id, role2text(rsc->next_role)); switch(rsc->next_role) { case RSC_ROLE_STOPPED: /* n_data->inactive = g_list_append(n_data->inactive, entry); */ crm_free(entry); break; case RSC_ROLE_STARTED: n_data->active = g_list_append(n_data->active, entry); break; case RSC_ROLE_SLAVE: n_data->slave = g_list_append(n_data->slave, entry); break; case RSC_ROLE_MASTER: n_data->master = g_list_append(n_data->master, entry); break; default: crm_err("Unsupported notify role"); break; } } void native_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { node_t *next_node = NULL; gboolean registered = FALSE; char *op_key = NULL; GListPtr possible_matches = NULL; enum action_tasks task = text2task(op->task); if(op->pre_notify == NULL || op->post_notify == NULL) { /* no notifications required */ crm_debug_4("No notificaitons required for %s", op->task); return; } next_node = rsc->color->details->chosen_node; op_key = generate_op_key(rsc->graph_name, op->task, 0); possible_matches = find_actions(rsc->actions, op_key, NULL); crm_debug_2("Creating notificaitons for: %s (%s->%s)", op->uuid, role2text(rsc->role), role2text(rsc->next_role)); if(rsc->role == rsc->next_role) { register_state(rsc, next_node, n_data); } slist_iter( local_op, action_t, possible_matches, lpc, local_op->notify_keys = n_data->keys; if(local_op->optional == FALSE) { registered = TRUE; register_activity(rsc, task, local_op->node, n_data); } ); /* stop / demote */ if(rsc->role != RSC_ROLE_STOPPED) { if(task == stop_rsc || task == action_demote) { slist_iter( current_node, node_t, rsc->running_on, lpc, pe_pre_notify(rsc, current_node, op, n_data, data_set); if(task == action_demote || registered == FALSE) { pe_post_notify(rsc, current_node, op, n_data, data_set); } ); } } /* start / promote */ if(rsc->next_role != RSC_ROLE_STOPPED) { CRM_CHECK(next_node != NULL, return); if(task == start_rsc || task == action_promote) { if(task != start_rsc || registered == FALSE) { pe_pre_notify(rsc, next_node, op, n_data, data_set); } pe_post_notify(rsc, next_node, op, n_data, data_set); } } crm_free(op_key); pe_free_shallow_adv(possible_matches, FALSE); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } static void pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm, notify_data_t *n_data, 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) { crm_debug_2("Op=%p confirm=%p", op, confirm); return; } CRM_CHECK(node != NULL, return); 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->graph_name, value, task); trigger = custom_action(rsc, key, op->task, node, op->optional, TRUE, data_set); g_hash_table_foreach(op->extra, dup_attr, trigger->extra); trigger->notify_keys = n_data->keys; /* 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); value = g_hash_table_lookup(op->extra, "notify_confirm"); if(crm_is_true(value)) { /* notify before pseudo_notified */ crm_debug_3("Ordering %s before %s (%d->%d)", trigger->uuid, confirm->uuid, confirm->id, trigger->id); 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, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->pre_notify, op->pre_notified, n_data, data_set); } void pe_post_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->post_notify, op->post_notified, n_data, data_set); } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; action_t *stop = NULL; crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role)); if(current == NULL || next == NULL) { return; } /* use StartRsc/StopRsc */ if(safe_str_neq(current->details->id, next->details->id)) { crm_notice("Move resource %s\t(%s -> %s)", rsc->id, current->details->uname, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } } else { if(rsc->failed) { crm_notice("Recover resource %s\t(%s)", rsc->id, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); /* /\* make the restart required *\/ */ /* order_stop_start(rsc, rsc, pe_ordering_manditory); */ } else if(rsc->start_pending) { start = start_action(rsc, next, TRUE); if(start->runnable) { /* wait for StartRsc() to be called */ rsc->role = RSC_ROLE_STOPPED; } else { /* wait for StopRsc() to be called */ rsc->next_role = RSC_ROLE_STOPPED; } } else { stop = stop_action(rsc, current, TRUE); start = start_action(rsc, next, TRUE); stop->optional = start->optional; if(start->runnable == FALSE) { rsc->next_role = RSC_ROLE_STOPPED; } else if(start->optional) { crm_notice("Leave resource %s\t(%s)", rsc->id, next->details->uname); } else { crm_notice("Restart resource %s\t(%s)", rsc->id, next->details->uname); } } } } gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *stop = NULL; crm_debug_2("Executing: %s", rsc->id); slist_iter( current, node_t, rsc->running_on, lpc, crm_notice(" %s\tStop %s", current->details->uname, rsc->id); stop = stop_action(rsc, current, FALSE); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } ); return TRUE; } gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { action_t *delete = NULL; action_t *refresh = NULL; char *stop = NULL; char *start = NULL; if(rsc->failed) { crm_debug_2("Resource %s not deleted from %s: failed", rsc->id, node->details->uname); return FALSE; } else if(node == NULL) { crm_debug_2("Resource %s not deleted: NULL node", rsc->id); return FALSE; } else if(node->details->unclean || node->details->online == FALSE) { crm_debug_2("Resource %s not deleted from %s: unrunnable", rsc->id, node->details->uname); return FALSE; } stop = stop_key(rsc); start = start_key(rsc); crm_notice("Removing %s from %s", rsc->id, node->details->uname); delete = delete_action(rsc, node); custom_action_order( rsc, stop, NULL, rsc, NULL, delete, pe_ordering_optional, data_set); custom_action_order( rsc, NULL, delete, rsc, start, NULL, pe_ordering_manditory, data_set); #if DELETE_THEN_REFRESH refresh = custom_action( NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, node, FALSE, TRUE, data_set); add_hash_param(refresh->extra, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order( rsc, NULL, delete, NULL, NULL, refresh, pe_ordering_optional, data_set); #endif return TRUE; } gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; crm_debug_2("Executing: %s", rsc->id); start = start_action(rsc, next, TRUE); if(start->runnable) { crm_notice(" %s\tStart %s", next->details->uname, rsc->id); start->optional = FALSE; } return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE); crm_notice("%s\tPromote %s", next->details->uname, rsc->id); promote_action(rsc, next, FALSE); return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); slist_iter( current, node_t, rsc->running_on, lpc, crm_notice("%s\tDeomote %s", next->details->uname, rsc->id); demote_action(rsc, current, FALSE); ); return TRUE; } gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); CRM_CHECK(FALSE, return FALSE); return FALSE; } gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); return FALSE; } gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { char *key = NULL; char *target_rc = NULL; action_t *probe = NULL; node_t *running = NULL; CRM_CHECK(node != NULL, return FALSE); if(rsc->orphan) { return FALSE; } running = pe_find_node_id(rsc->known_on, node->details->id); if(force == FALSE && running != NULL) { /* we already know the status of the resource on this node */ return FALSE; } target_rc = crm_itoa(EXECRA_NOT_RUNNING); key = generate_op_key(rsc->graph_name, CRMD_ACTION_STATUS, 0); probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node, FALSE, TRUE, data_set); crm_notice("%s: Created probe for %s", node->details->uname, rsc->id); g_hash_table_insert(probe->extra, crm_strdup(XML_ATTR_TE_TARGET_RC), target_rc); g_hash_table_insert(probe->extra, crm_strdup(XML_ATTR_LRM_PROBE), crm_strdup(XML_BOOLEAN_TRUE)); custom_action_order(rsc, NULL, probe, rsc, NULL, complete, pe_ordering_manditory, data_set); return TRUE; } diff --git a/crm/pengine/regression.sh b/crm/pengine/regression.sh index 6b4950d0e2..5196526deb 100755 --- a/crm/pengine/regression.sh +++ b/crm/pengine/regression.sh @@ -1,204 +1,207 @@ #!/bin/bash # 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 # . regression.core.sh create_mode="true" echo Generating test outputs for these tests... #do_test master-1 "Stopped -> Promote" echo "" echo Done. echo "" echo Performing the following tests... create_mode="false" echo "" do_test simple1 "Offline " do_test simple2 "Start " do_test simple3 "Start 2 " do_test simple4 "Start Failed" do_test simple6 "Stop Start " do_test simple7 "Shutdown " #do_test simple8 "Stonith " #do_test simple9 "Lower version" #do_test simple10 "Higher version" do_test simple11 "Priority (ne)" do_test simple12 "Priority (eq)" do_test simple8 "Stickiness" echo "" do_test date-1 "Dates" do_test comments "Comments" do_test params-0 "Params: No change" do_test params-1 "Params: Changed" do_test params-2 "Params: Resource definition" do_test orphan-0 "Orphan ignore" do_test orphan-1 "Orphan stop" do_test master-0 "Stopped -> Slave" do_test master-1 "Stopped -> Promote" do_test master-2 "Stopped -> Promote : notify" do_test master-3 "Stopped -> Promote : master location" +do_test master-4 "Started -> Promote : master location" +do_test master-5 "Promoted -> Promoted" +do_test master-6 "Promoted -> Promoted (2)" echo "" do_test rsc_dep1 "Must not " do_test rsc_dep3 "Must " do_test rsc_dep5 "Must not 3 " do_test rsc_dep7 "Must 3 " do_test rsc_dep10 "Must (but cant)" do_test rsc_dep2 "Must (running) " do_test rsc_dep8 "Must (running : alt) " do_test rsc_dep4 "Must (running + move)" echo "" do_test order1 "Order start 1 " do_test order2 "Order start 2 " do_test order3 "Order stop " do_test order4 "Order (multiple) " do_test order5 "Order (move) " do_test order6 "Order (move w/ restart) " #echo "" #do_test agent1 "version: lt (empty)" #do_test agent2 "version: eq " #do_test agent3 "version: gt " echo "" do_test attrs1 "string: eq (and) " do_test attrs2 "string: lt / gt (and)" do_test attrs3 "string: ne (or) " do_test attrs4 "string: exists " do_test attrs5 "string: not_exists " do_test attrs6 "is_dc: true " do_test attrs7 "is_dc: false " echo "" do_test mon-rsc-1 "Schedule Monitor - start" do_test mon-rsc-2 "Schedule Monitor - move " do_test mon-rsc-3 "Schedule Monitor - pending start " do_test mon-rsc-4 "Schedule Monitor - move/pending start" echo "" do_test rec-rsc-0 "Resource Recover - no start " do_test rec-rsc-1 "Resource Recover - start " do_test rec-rsc-2 "Resource Recover - monitor " do_test rec-rsc-3 "Resource Recover - stop - ignore" do_test rec-rsc-4 "Resource Recover - stop - block " do_test rec-rsc-5 "Resource Recover - stop - fence " do_test rec-rsc-6 "Resource Recover - multiple - restart" do_test rec-rsc-7 "Resource Recover - multiple - stop " do_test rec-rsc-8 "Resource Recover - multiple - block " echo "" do_test quorum-1 "No quorum - ignore" do_test quorum-2 "No quorum - freeze" do_test quorum-3 "No quorum - stop " do_test quorum-4 "No quorum - start anyway" do_test quorum-5 "No quorum - start anyway (group)" do_test quorum-6 "No quorum - start anyway (clone)" echo "" do_test rec-node-1 "Node Recover - Startup - no fence" do_test rec-node-2 "Node Recover - Startup - fence " do_test rec-node-3 "Node Recover - HA down - no fence" do_test rec-node-4 "Node Recover - HA down - fence " do_test rec-node-5 "Node Recover - CRM down - no fence" do_test rec-node-6 "Node Recover - CRM down - fence " do_test rec-node-7 "Node Recover - no quorum - ignore " do_test rec-node-8 "Node Recover - no quorum - freeze " do_test rec-node-9 "Node Recover - no quorum - stop " do_test rec-node-10 "Node Recover - no quorum - stop w/fence" do_test rec-node-11 "Node Recover - CRM down w/ group - fence " echo "" do_test multi1 "Multiple Active (stop/start)" #echo "" #do_test complex1 "Complex " echo "" do_test group1 "Group " do_test group2 "Group + Native " do_test group3 "Group + Group " do_test group4 "Group + Native (nothing)" do_test group5 "Group + Native (move) " do_test group6 "Group + Group (move) " do_test group7 "Group colocation" do_test group8 "Group anti-colocation" do_test group9 "Group recovery" do_test group10 "Group partial recovery" echo "" do_test inc0 "Incarnation start " do_test inc1 "Incarnation start order " do_test inc2 "Incarnation silent restart, stop, move " do_test inc3 "Inter-incarnation ordering, silent restart, stop, move" do_test inc4 "Inter-incarnation ordering, silent restart, stop, move (ordered)" do_test inc5 "Inter-incarnation ordering, silent restart, stop, move (restart 1)" do_test inc6 "Inter-incarnation ordering, silent restart, stop, move (restart 2)" do_test inc7 "Clone colocation" do_test inc8 "Clone anti-colocation" do_test inc9 "Non-unique clone" echo "" do_test managed-0 "Managed (reference)" do_test managed-1 "Not managed - down " do_test managed-2 "Not managed - up " echo "" do_test interleave-0 "Interleave (reference)" do_test interleave-1 "coloc - not interleaved" do_test interleave-2 "coloc - interleaved " do_test interleave-3 "coloc - interleaved (2)" echo "" do_test notify-0 "Notify reference" do_test notify-1 "Notify simple" do_test notify-2 "Notify simple, confirm" do_test notify-3 "Notify move, confirm" #do_test notify-2 "Notify - 764" echo "" do_test 594 "Bugzilla 594" do_test 662 "Bugzilla 662" do_test 696 "Bugzilla 696" do_test 726 "Bugzilla 726" do_test 735 "Bugzilla 735" do_test 764 "Bugzilla 764" do_test 797 "Bugzilla 797" do_test 829 "Bugzilla 829" do_test 994 "Bugzilla 994" do_test unrunnable-1 "Unrunnable" echo "" do_test bad1 "Bad node " do_test bad2 "Bad rsc " do_test bad3 "No rsc class " do_test bad4 "Bad data " do_test bad5 "Bad data " do_test bad6 "Bad lrm_rsc " echo "" test_results diff --git a/crm/pengine/testcases/master-4.dot b/crm/pengine/testcases/master-4.dot index 91f176fcfb..d3edcb746e 100644 --- a/crm/pengine/testcases/master-4.dot +++ b/crm/pengine/testcases/master-4.dot @@ -1,190 +1,193 @@ digraph "g" { size = "30,30" "rsc_c001n08_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_monitor_20000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] -"ocf_msdummy:0_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_monitor_5000 c001n08" [ style=bold color="green" fontcolor="black" ] "DcIPaddr_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_monitor_20000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:1_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "lsb_dummy_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_monitor_20000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_monitor_20000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "DcIPaddr_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "DcIPaddr_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "group-1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] "lsb_dummy_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "lsb_dummy_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n08_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n08_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "DoFencing_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] "ocf_msdummy:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:0_promote_0 c001n08" [ style=bold color="green" fontcolor="black" ] +"ocf_msdummy:0_monitor_6000 c001n08" [ style=bold color="green" fontcolor="black" ] "ocf_msdummy:1_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:1_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "master_rsc_1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_promote_0" [ style=bold color="green" fontcolor="orange" ] "master_rsc_1_promoted_0" [ style=bold color="green" fontcolor="orange" ] "master_rsc_1_demote_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_demoted_0" [ style="dashed" color="blue" fontcolor="orange" ] "rsc_c001n08_start_0 c001n08" -> "rsc_c001n08_monitor_5000 c001n08" [ style = dashed] "ocf_msdummy:3_start_0 c001n08" -> "ocf_msdummy:3_monitor_5000 c001n08" [ style = dashed] "child_DoFencing:0_start_0 c001n08" -> "child_DoFencing:0_monitor_20000 c001n08" [ style = dashed] -"ocf_msdummy:0_start_0 c001n08" -> "ocf_msdummy:0_monitor_5000 c001n08" [ style = dashed] "DcIPaddr_start_0 c001n08" -> "DcIPaddr_monitor_5000 c001n08" [ style = dashed] "ocf_msdummy:4_start_0 c001n03" -> "ocf_msdummy:4_monitor_5000 c001n03" [ style = dashed] "heartbeat_child_start_0 c001n03" -> "heartbeat_child_monitor_5000 c001n03" [ style = dashed] "ocf_child_start_0 c001n03" -> "ocf_child_monitor_5000 c001n03" [ style = dashed] "rsc_c001n03_start_0 c001n03" -> "rsc_c001n03_monitor_5000 c001n03" [ style = dashed] "child_DoFencing:1_start_0 c001n03" -> "child_DoFencing:1_monitor_20000 c001n03" [ style = dashed] "ocf_msdummy:1_start_0 c001n03" -> "ocf_msdummy:1_monitor_5000 c001n03" [ style = dashed] "ocf_msdummy:2_start_0 c001n01" -> "ocf_msdummy:2_monitor_5000 c001n01" [ style = dashed] "lsb_dummy_start_0 c001n01" -> "lsb_dummy_monitor_5000 c001n01" [ style = dashed] "ocf_msdummy:5_start_0 c001n01" -> "ocf_msdummy:5_monitor_5000 c001n01" [ style = dashed] "rsc_c001n01_start_0 c001n01" -> "rsc_c001n01_monitor_5000 c001n01" [ style = dashed] "child_DoFencing:2_start_0 c001n01" -> "child_DoFencing:2_monitor_20000 c001n01" [ style = dashed] "rsc_c001n02_start_0 c001n02" -> "rsc_c001n02_monitor_5000 c001n02" [ style = dashed] "child_DoFencing:3_start_0 c001n02" -> "child_DoFencing:3_monitor_20000 c001n02" [ style = dashed] "ocf_msdummy:6_start_0 c001n02" -> "ocf_msdummy:6_monitor_5000 c001n02" [ style = dashed] "ocf_msdummy:7_start_0 c001n02" -> "ocf_msdummy:7_monitor_5000 c001n02" [ style = dashed] "DcIPaddr_stop_0 c001n08" -> "DcIPaddr_start_0 c001n08" [ style = dashed] "heartbeat_child_stop_0 c001n03" -> "ocf_child_stop_0 c001n03" [ style = dashed] "ocf_child_stop_0 c001n03" -> "ocf_child_start_0 c001n03" [ style = dashed] "group-1_start_0" -> "ocf_child_start_0 c001n03" [ style = dashed] "group-1_stop_0" -> "heartbeat_child_stop_0 c001n03" [ style = dashed] "heartbeat_child_stop_0 c001n03" -> "heartbeat_child_start_0 c001n03" [ style = dashed] "ocf_child_start_0 c001n03" -> "heartbeat_child_start_0 c001n03" [ style = dashed] "group-1_stopped_0" -> "group-1_start_0" [ style = dashed] "group-1_start_0" -> "group-1_running_0" [ style = dashed] "heartbeat_child_start_0 c001n03" -> "group-1_running_0" [ style = dashed] "group-1_stop_0" -> "group-1_stopped_0" [ style = dashed] "ocf_child_stop_0 c001n03" -> "group-1_stopped_0" [ style = dashed] "lsb_dummy_stop_0 c001n01" -> "lsb_dummy_start_0 c001n01" [ style = dashed] "rsc_c001n08_stop_0 c001n08" -> "rsc_c001n08_start_0 c001n08" [ style = dashed] "rsc_c001n02_stop_0 c001n02" -> "rsc_c001n02_start_0 c001n02" [ style = dashed] "rsc_c001n03_stop_0 c001n03" -> "rsc_c001n03_start_0 c001n03" [ style = dashed] "rsc_c001n01_stop_0 c001n01" -> "rsc_c001n01_start_0 c001n01" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:0_stop_0 c001n08" [ style = dashed] "child_DoFencing:0_stop_0 c001n08" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:1_stop_0 c001n03" [ style = dashed] "child_DoFencing:1_stop_0 c001n03" -> "child_DoFencing:1_start_0 c001n03" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:1_start_0 c001n03" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:2_stop_0 c001n01" [ style = dashed] "child_DoFencing:2_stop_0 c001n01" -> "child_DoFencing:2_start_0 c001n01" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:2_start_0 c001n01" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:3_stop_0 c001n02" [ style = dashed] "child_DoFencing:3_stop_0 c001n02" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] "DoFencing_stopped_0" -> "DoFencing_start_0" [ style = dashed] "DoFencing_start_0" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:0_start_0 c001n08" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:1_start_0 c001n03" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:2_start_0 c001n01" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:3_start_0 c001n02" -> "DoFencing_running_0" [ style = dashed] "DoFencing_stop_0" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:0_stop_0 c001n08" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:1_stop_0 c001n03" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:2_stop_0 c001n01" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:3_stop_0 c001n02" -> "DoFencing_stopped_0" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:0_stop_0 c001n08" [ style = dashed] "ocf_msdummy:0_stop_0 c001n08" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] +"ocf_msdummy:0_monitor_5000 c001n08" -> "ocf_msdummy:0_promote_0 c001n08" [ style = bold] "master_rsc_1_promote_0" -> "ocf_msdummy:0_promote_0 c001n08" [ style = bold] +"ocf_msdummy:0_start_0 c001n08" -> "ocf_msdummy:0_monitor_6000 c001n08" [ style = dashed] +"ocf_msdummy:0_promote_0 c001n08" -> "ocf_msdummy:0_monitor_6000 c001n08" [ style = bold] "master_rsc_1_stop_0" -> "ocf_msdummy:1_stop_0 c001n03" [ style = dashed] "ocf_msdummy:1_stop_0 c001n03" -> "ocf_msdummy:1_start_0 c001n03" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:1_start_0 c001n03" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:2_stop_0 c001n01" [ style = dashed] "ocf_msdummy:2_stop_0 c001n01" -> "ocf_msdummy:2_start_0 c001n01" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:2_start_0 c001n01" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:3_stop_0 c001n08" [ style = dashed] "ocf_msdummy:3_stop_0 c001n08" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:4_stop_0 c001n03" [ style = dashed] "ocf_msdummy:4_stop_0 c001n03" -> "ocf_msdummy:4_start_0 c001n03" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:4_start_0 c001n03" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:5_stop_0 c001n01" [ style = dashed] "ocf_msdummy:5_stop_0 c001n01" -> "ocf_msdummy:5_start_0 c001n01" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:5_start_0 c001n01" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:6_stop_0 c001n02" [ style = dashed] "ocf_msdummy:6_stop_0 c001n02" -> "ocf_msdummy:6_start_0 c001n02" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:6_start_0 c001n02" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:7_stop_0 c001n02" [ style = dashed] "ocf_msdummy:7_stop_0 c001n02" -> "ocf_msdummy:7_start_0 c001n02" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:7_start_0 c001n02" [ style = dashed] "master_rsc_1_stopped_0" -> "master_rsc_1_start_0" [ style = dashed] "master_rsc_1_demoted_0" -> "master_rsc_1_start_0" [ style = dashed] "master_rsc_1_start_0" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:0_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:1_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:2_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:3_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:4_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:5_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:6_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:7_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] "master_rsc_1_demoted_0" -> "master_rsc_1_stop_0" [ style = dashed] "master_rsc_1_stop_0" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:0_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:1_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:2_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:3_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:4_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:5_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:6_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:7_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] "master_rsc_1_running_0" -> "master_rsc_1_promote_0" [ style = dashed] "ocf_msdummy:0_promote_0 c001n08" -> "master_rsc_1_promoted_0" [ style = bold] "master_rsc_1_demote_0" -> "master_rsc_1_demoted_0" [ style = dashed] } diff --git a/crm/pengine/testcases/master-4.exp b/crm/pengine/testcases/master-4.exp index f11a513192..ebabc30928 100644 --- a/crm/pengine/testcases/master-4.exp +++ b/crm/pengine/testcases/master-4.exp @@ -1,36 +1,61 @@ + + + + + + + + + - + + + + + + + + + + + + + + + + + - + - + - + - + diff --git a/crm/pengine/testcases/master-4.xml b/crm/pengine/testcases/master-4.xml index 790ff40865..ea4b1c5f69 100644 --- a/crm/pengine/testcases/master-4.xml +++ b/crm/pengine/testcases/master-4.xml @@ -1,565 +1,566 @@ + diff --git a/crm/pengine/testcases/master-4.dot b/crm/pengine/testcases/master-5.dot similarity index 96% copy from crm/pengine/testcases/master-4.dot copy to crm/pengine/testcases/master-5.dot index 91f176fcfb..613591a956 100644 --- a/crm/pengine/testcases/master-4.dot +++ b/crm/pengine/testcases/master-5.dot @@ -1,190 +1,187 @@ digraph "g" { size = "30,30" "rsc_c001n08_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_monitor_20000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] -"ocf_msdummy:0_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_monitor_6000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "DcIPaddr_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_monitor_20000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:1_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "lsb_dummy_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_monitor_20000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_monitor_20000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "DcIPaddr_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "DcIPaddr_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_child_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "heartbeat_child_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "group-1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "group-1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] "lsb_dummy_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "lsb_dummy_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n08_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n08_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n02_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n03_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "rsc_c001n01_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:1_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:2_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "child_DoFencing:3_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "DoFencing_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "DoFencing_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] "ocf_msdummy:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] -"ocf_msdummy:0_promote_0 c001n08" [ style=bold color="green" fontcolor="black" ] "ocf_msdummy:1_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:1_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:2_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:3_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:4_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:5_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:6_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "ocf_msdummy:7_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] "master_rsc_1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] -"master_rsc_1_promote_0" [ style=bold color="green" fontcolor="orange" ] -"master_rsc_1_promoted_0" [ style=bold color="green" fontcolor="orange" ] +"master_rsc_1_promote_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_promoted_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_demote_0" [ style="dashed" color="blue" fontcolor="orange" ] "master_rsc_1_demoted_0" [ style="dashed" color="blue" fontcolor="orange" ] "rsc_c001n08_start_0 c001n08" -> "rsc_c001n08_monitor_5000 c001n08" [ style = dashed] "ocf_msdummy:3_start_0 c001n08" -> "ocf_msdummy:3_monitor_5000 c001n08" [ style = dashed] "child_DoFencing:0_start_0 c001n08" -> "child_DoFencing:0_monitor_20000 c001n08" [ style = dashed] -"ocf_msdummy:0_start_0 c001n08" -> "ocf_msdummy:0_monitor_5000 c001n08" [ style = dashed] +"ocf_msdummy:0_start_0 c001n08" -> "ocf_msdummy:0_monitor_6000 c001n08" [ style = dashed] "DcIPaddr_start_0 c001n08" -> "DcIPaddr_monitor_5000 c001n08" [ style = dashed] "ocf_msdummy:4_start_0 c001n03" -> "ocf_msdummy:4_monitor_5000 c001n03" [ style = dashed] "heartbeat_child_start_0 c001n03" -> "heartbeat_child_monitor_5000 c001n03" [ style = dashed] "ocf_child_start_0 c001n03" -> "ocf_child_monitor_5000 c001n03" [ style = dashed] "rsc_c001n03_start_0 c001n03" -> "rsc_c001n03_monitor_5000 c001n03" [ style = dashed] "child_DoFencing:1_start_0 c001n03" -> "child_DoFencing:1_monitor_20000 c001n03" [ style = dashed] "ocf_msdummy:1_start_0 c001n03" -> "ocf_msdummy:1_monitor_5000 c001n03" [ style = dashed] "ocf_msdummy:2_start_0 c001n01" -> "ocf_msdummy:2_monitor_5000 c001n01" [ style = dashed] "lsb_dummy_start_0 c001n01" -> "lsb_dummy_monitor_5000 c001n01" [ style = dashed] "ocf_msdummy:5_start_0 c001n01" -> "ocf_msdummy:5_monitor_5000 c001n01" [ style = dashed] "rsc_c001n01_start_0 c001n01" -> "rsc_c001n01_monitor_5000 c001n01" [ style = dashed] "child_DoFencing:2_start_0 c001n01" -> "child_DoFencing:2_monitor_20000 c001n01" [ style = dashed] "rsc_c001n02_start_0 c001n02" -> "rsc_c001n02_monitor_5000 c001n02" [ style = dashed] "child_DoFencing:3_start_0 c001n02" -> "child_DoFencing:3_monitor_20000 c001n02" [ style = dashed] "ocf_msdummy:6_start_0 c001n02" -> "ocf_msdummy:6_monitor_5000 c001n02" [ style = dashed] "ocf_msdummy:7_start_0 c001n02" -> "ocf_msdummy:7_monitor_5000 c001n02" [ style = dashed] "DcIPaddr_stop_0 c001n08" -> "DcIPaddr_start_0 c001n08" [ style = dashed] "heartbeat_child_stop_0 c001n03" -> "ocf_child_stop_0 c001n03" [ style = dashed] "ocf_child_stop_0 c001n03" -> "ocf_child_start_0 c001n03" [ style = dashed] "group-1_start_0" -> "ocf_child_start_0 c001n03" [ style = dashed] "group-1_stop_0" -> "heartbeat_child_stop_0 c001n03" [ style = dashed] "heartbeat_child_stop_0 c001n03" -> "heartbeat_child_start_0 c001n03" [ style = dashed] "ocf_child_start_0 c001n03" -> "heartbeat_child_start_0 c001n03" [ style = dashed] "group-1_stopped_0" -> "group-1_start_0" [ style = dashed] "group-1_start_0" -> "group-1_running_0" [ style = dashed] "heartbeat_child_start_0 c001n03" -> "group-1_running_0" [ style = dashed] "group-1_stop_0" -> "group-1_stopped_0" [ style = dashed] "ocf_child_stop_0 c001n03" -> "group-1_stopped_0" [ style = dashed] "lsb_dummy_stop_0 c001n01" -> "lsb_dummy_start_0 c001n01" [ style = dashed] "rsc_c001n08_stop_0 c001n08" -> "rsc_c001n08_start_0 c001n08" [ style = dashed] "rsc_c001n02_stop_0 c001n02" -> "rsc_c001n02_start_0 c001n02" [ style = dashed] "rsc_c001n03_stop_0 c001n03" -> "rsc_c001n03_start_0 c001n03" [ style = dashed] "rsc_c001n01_stop_0 c001n01" -> "rsc_c001n01_start_0 c001n01" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:0_stop_0 c001n08" [ style = dashed] "child_DoFencing:0_stop_0 c001n08" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:1_stop_0 c001n03" [ style = dashed] "child_DoFencing:1_stop_0 c001n03" -> "child_DoFencing:1_start_0 c001n03" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:1_start_0 c001n03" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:2_stop_0 c001n01" [ style = dashed] "child_DoFencing:2_stop_0 c001n01" -> "child_DoFencing:2_start_0 c001n01" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:2_start_0 c001n01" [ style = dashed] "DoFencing_stop_0" -> "child_DoFencing:3_stop_0 c001n02" [ style = dashed] "child_DoFencing:3_stop_0 c001n02" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] "DoFencing_start_0" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] "DoFencing_stopped_0" -> "DoFencing_start_0" [ style = dashed] "DoFencing_start_0" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:0_start_0 c001n08" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:1_start_0 c001n03" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:2_start_0 c001n01" -> "DoFencing_running_0" [ style = dashed] "child_DoFencing:3_start_0 c001n02" -> "DoFencing_running_0" [ style = dashed] "DoFencing_stop_0" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:0_stop_0 c001n08" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:1_stop_0 c001n03" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:2_stop_0 c001n01" -> "DoFencing_stopped_0" [ style = dashed] "child_DoFencing:3_stop_0 c001n02" -> "DoFencing_stopped_0" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:0_stop_0 c001n08" [ style = dashed] "ocf_msdummy:0_stop_0 c001n08" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] -"master_rsc_1_promote_0" -> "ocf_msdummy:0_promote_0 c001n08" [ style = bold] "master_rsc_1_stop_0" -> "ocf_msdummy:1_stop_0 c001n03" [ style = dashed] "ocf_msdummy:1_stop_0 c001n03" -> "ocf_msdummy:1_start_0 c001n03" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:1_start_0 c001n03" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:2_stop_0 c001n01" [ style = dashed] "ocf_msdummy:2_stop_0 c001n01" -> "ocf_msdummy:2_start_0 c001n01" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:2_start_0 c001n01" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:3_stop_0 c001n08" [ style = dashed] "ocf_msdummy:3_stop_0 c001n08" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:4_stop_0 c001n03" [ style = dashed] "ocf_msdummy:4_stop_0 c001n03" -> "ocf_msdummy:4_start_0 c001n03" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:4_start_0 c001n03" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:5_stop_0 c001n01" [ style = dashed] "ocf_msdummy:5_stop_0 c001n01" -> "ocf_msdummy:5_start_0 c001n01" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:5_start_0 c001n01" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:6_stop_0 c001n02" [ style = dashed] "ocf_msdummy:6_stop_0 c001n02" -> "ocf_msdummy:6_start_0 c001n02" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:6_start_0 c001n02" [ style = dashed] "master_rsc_1_stop_0" -> "ocf_msdummy:7_stop_0 c001n02" [ style = dashed] "ocf_msdummy:7_stop_0 c001n02" -> "ocf_msdummy:7_start_0 c001n02" [ style = dashed] "master_rsc_1_start_0" -> "ocf_msdummy:7_start_0 c001n02" [ style = dashed] "master_rsc_1_stopped_0" -> "master_rsc_1_start_0" [ style = dashed] "master_rsc_1_demoted_0" -> "master_rsc_1_start_0" [ style = dashed] "master_rsc_1_start_0" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:0_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:1_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:2_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:3_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:4_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:5_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:6_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] "ocf_msdummy:7_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] "master_rsc_1_demoted_0" -> "master_rsc_1_stop_0" [ style = dashed] "master_rsc_1_stop_0" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:0_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:1_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:2_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:3_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:4_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:5_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:6_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] "ocf_msdummy:7_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] "master_rsc_1_running_0" -> "master_rsc_1_promote_0" [ style = dashed] -"ocf_msdummy:0_promote_0 c001n08" -> "master_rsc_1_promoted_0" [ style = bold] "master_rsc_1_demote_0" -> "master_rsc_1_demoted_0" [ style = dashed] } diff --git a/crm/pengine/testcases/master-5.exp b/crm/pengine/testcases/master-5.exp new file mode 100644 index 0000000000..140341affb --- /dev/null +++ b/crm/pengine/testcases/master-5.exp @@ -0,0 +1,2 @@ + + diff --git a/crm/pengine/testcases/master-4.xml b/crm/pengine/testcases/master-5.xml similarity index 98% copy from crm/pengine/testcases/master-4.xml copy to crm/pengine/testcases/master-5.xml index 790ff40865..0a19ef1f5f 100644 --- a/crm/pengine/testcases/master-4.xml +++ b/crm/pengine/testcases/master-5.xml @@ -1,565 +1,569 @@ + - + - - + + + + + diff --git a/crm/pengine/testcases/master-6.dot b/crm/pengine/testcases/master-6.dot new file mode 100644 index 0000000000..707b32b1d6 --- /dev/null +++ b/crm/pengine/testcases/master-6.dot @@ -0,0 +1,194 @@ +digraph "g" { + size = "30,30" +"rsc_c001n08_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:3_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n01_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:0_monitor_20000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_monitor_6000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"DcIPaddr_monitor_5000 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.181_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:1_monitor_20000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:1_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:2_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"lsb_dummy_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:5_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_monitor_5000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:2_monitor_20000 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n01_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_monitor_20000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:7_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:6_monitor_5000 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"DcIPaddr_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"DcIPaddr_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.181_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.181_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"group-1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] +"lsb_dummy_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"lsb_dummy_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n08_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n08_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n01_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n01_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:1_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:1_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:2_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:2_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"DoFencing_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] +"ocf_msdummy:0_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:1_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:1_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:2_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:2_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:3_stop_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:3_start_0 c001n08" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:5_stop_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:5_start_0 c001n03" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:6_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:6_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:7_stop_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:7_start_0 c001n01" [ style="dashed" color="blue" fontcolor="black" ] +"master_rsc_1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_promote_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_promoted_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_demote_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_demoted_0" [ style="dashed" color="blue" fontcolor="orange" ] +"rsc_c001n08_start_0 c001n08" -> "rsc_c001n08_monitor_5000 c001n08" [ style = dashed] +"ocf_msdummy:3_start_0 c001n08" -> "ocf_msdummy:3_monitor_5000 c001n08" [ style = dashed] +"child_DoFencing:0_start_0 c001n08" -> "child_DoFencing:0_monitor_20000 c001n08" [ style = dashed] +"ocf_msdummy:0_start_0 c001n08" -> "ocf_msdummy:0_monitor_6000 c001n08" [ style = dashed] +"DcIPaddr_start_0 c001n08" -> "DcIPaddr_monitor_5000 c001n08" [ style = dashed] +"ocf_192.168.100.181_start_0 c001n02" -> "ocf_192.168.100.181_monitor_5000 c001n02" [ style = dashed] +"ocf_msdummy:4_start_0 c001n02" -> "ocf_msdummy:4_monitor_5000 c001n02" [ style = dashed] +"ocf_192.168.100.183_start_0 c001n02" -> "ocf_192.168.100.183_monitor_5000 c001n02" [ style = dashed] +"rsc_c001n02_start_0 c001n02" -> "rsc_c001n02_monitor_5000 c001n02" [ style = dashed] +"child_DoFencing:1_start_0 c001n02" -> "child_DoFencing:1_monitor_20000 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_start_0 c001n02" -> "heartbeat_192.168.100.182_monitor_5000 c001n02" [ style = dashed] +"ocf_msdummy:1_start_0 c001n02" -> "ocf_msdummy:1_monitor_5000 c001n02" [ style = dashed] +"ocf_msdummy:2_start_0 c001n03" -> "ocf_msdummy:2_monitor_5000 c001n03" [ style = dashed] +"lsb_dummy_start_0 c001n03" -> "lsb_dummy_monitor_5000 c001n03" [ style = dashed] +"ocf_msdummy:5_start_0 c001n03" -> "ocf_msdummy:5_monitor_5000 c001n03" [ style = dashed] +"rsc_c001n03_start_0 c001n03" -> "rsc_c001n03_monitor_5000 c001n03" [ style = dashed] +"child_DoFencing:2_start_0 c001n03" -> "child_DoFencing:2_monitor_20000 c001n03" [ style = dashed] +"rsc_c001n01_start_0 c001n01" -> "rsc_c001n01_monitor_5000 c001n01" [ style = dashed] +"child_DoFencing:3_start_0 c001n01" -> "child_DoFencing:3_monitor_20000 c001n01" [ style = dashed] +"ocf_msdummy:7_start_0 c001n01" -> "ocf_msdummy:7_monitor_5000 c001n01" [ style = dashed] +"ocf_msdummy:6_start_0 c001n01" -> "ocf_msdummy:6_monitor_5000 c001n01" [ style = dashed] +"DcIPaddr_stop_0 c001n08" -> "DcIPaddr_start_0 c001n08" [ style = dashed] +"heartbeat_192.168.100.182_stop_0 c001n02" -> "ocf_192.168.100.181_stop_0 c001n02" [ style = dashed] +"ocf_192.168.100.181_stop_0 c001n02" -> "ocf_192.168.100.181_start_0 c001n02" [ style = dashed] +"group-1_start_0" -> "ocf_192.168.100.181_start_0 c001n02" [ style = dashed] +"ocf_192.168.100.183_stop_0 c001n02" -> "heartbeat_192.168.100.182_stop_0 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_stop_0 c001n02" -> "heartbeat_192.168.100.182_start_0 c001n02" [ style = dashed] +"ocf_192.168.100.181_start_0 c001n02" -> "heartbeat_192.168.100.182_start_0 c001n02" [ style = dashed] +"group-1_stop_0" -> "ocf_192.168.100.183_stop_0 c001n02" [ style = dashed] +"ocf_192.168.100.183_stop_0 c001n02" -> "ocf_192.168.100.183_start_0 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_start_0 c001n02" -> "ocf_192.168.100.183_start_0 c001n02" [ style = dashed] +"group-1_stopped_0" -> "group-1_start_0" [ style = dashed] +"group-1_start_0" -> "group-1_running_0" [ style = dashed] +"ocf_192.168.100.183_start_0 c001n02" -> "group-1_running_0" [ style = dashed] +"group-1_stop_0" -> "group-1_stopped_0" [ style = dashed] +"ocf_192.168.100.181_stop_0 c001n02" -> "group-1_stopped_0" [ style = dashed] +"lsb_dummy_stop_0 c001n03" -> "lsb_dummy_start_0 c001n03" [ style = dashed] +"rsc_c001n08_stop_0 c001n08" -> "rsc_c001n08_start_0 c001n08" [ style = dashed] +"rsc_c001n02_stop_0 c001n02" -> "rsc_c001n02_start_0 c001n02" [ style = dashed] +"rsc_c001n03_stop_0 c001n03" -> "rsc_c001n03_start_0 c001n03" [ style = dashed] +"rsc_c001n01_stop_0 c001n01" -> "rsc_c001n01_start_0 c001n01" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:0_stop_0 c001n08" [ style = dashed] +"child_DoFencing:0_stop_0 c001n08" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:0_start_0 c001n08" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:1_stop_0 c001n02" [ style = dashed] +"child_DoFencing:1_stop_0 c001n02" -> "child_DoFencing:1_start_0 c001n02" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:1_start_0 c001n02" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:2_stop_0 c001n03" [ style = dashed] +"child_DoFencing:2_stop_0 c001n03" -> "child_DoFencing:2_start_0 c001n03" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:2_start_0 c001n03" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:3_stop_0 c001n01" [ style = dashed] +"child_DoFencing:3_stop_0 c001n01" -> "child_DoFencing:3_start_0 c001n01" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:3_start_0 c001n01" [ style = dashed] +"DoFencing_stopped_0" -> "DoFencing_start_0" [ style = dashed] +"DoFencing_start_0" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:0_start_0 c001n08" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:1_start_0 c001n02" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:2_start_0 c001n03" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:3_start_0 c001n01" -> "DoFencing_running_0" [ style = dashed] +"DoFencing_stop_0" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:0_stop_0 c001n08" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:1_stop_0 c001n02" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:2_stop_0 c001n03" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:3_stop_0 c001n01" -> "DoFencing_stopped_0" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:0_stop_0 c001n08" [ style = dashed] +"ocf_msdummy:0_stop_0 c001n08" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:0_start_0 c001n08" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:1_stop_0 c001n02" [ style = dashed] +"ocf_msdummy:1_stop_0 c001n02" -> "ocf_msdummy:1_start_0 c001n02" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:1_start_0 c001n02" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:2_stop_0 c001n03" [ style = dashed] +"ocf_msdummy:2_stop_0 c001n03" -> "ocf_msdummy:2_start_0 c001n03" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:2_start_0 c001n03" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:3_stop_0 c001n08" [ style = dashed] +"ocf_msdummy:3_stop_0 c001n08" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:3_start_0 c001n08" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:4_stop_0 c001n02" [ style = dashed] +"ocf_msdummy:4_stop_0 c001n02" -> "ocf_msdummy:4_start_0 c001n02" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:4_start_0 c001n02" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:5_stop_0 c001n03" [ style = dashed] +"ocf_msdummy:5_stop_0 c001n03" -> "ocf_msdummy:5_start_0 c001n03" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:5_start_0 c001n03" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:6_stop_0 c001n01" [ style = dashed] +"ocf_msdummy:6_stop_0 c001n01" -> "ocf_msdummy:6_start_0 c001n01" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:6_start_0 c001n01" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:7_stop_0 c001n01" [ style = dashed] +"ocf_msdummy:7_stop_0 c001n01" -> "ocf_msdummy:7_start_0 c001n01" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:7_start_0 c001n01" [ style = dashed] +"master_rsc_1_stopped_0" -> "master_rsc_1_start_0" [ style = dashed] +"master_rsc_1_demoted_0" -> "master_rsc_1_start_0" [ style = dashed] +"master_rsc_1_start_0" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:0_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:1_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:2_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:3_start_0 c001n08" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:4_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:5_start_0 c001n03" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:6_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:7_start_0 c001n01" -> "master_rsc_1_running_0" [ style = dashed] +"master_rsc_1_demoted_0" -> "master_rsc_1_stop_0" [ style = dashed] +"master_rsc_1_stop_0" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:0_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:1_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:2_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:3_stop_0 c001n08" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:4_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:5_stop_0 c001n03" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:6_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:7_stop_0 c001n01" -> "master_rsc_1_stopped_0" [ style = dashed] +"master_rsc_1_running_0" -> "master_rsc_1_promote_0" [ style = dashed] +"master_rsc_1_demote_0" -> "master_rsc_1_demoted_0" [ style = dashed] +} diff --git a/crm/pengine/testcases/master-6.exp b/crm/pengine/testcases/master-6.exp new file mode 100644 index 0000000000..140341affb --- /dev/null +++ b/crm/pengine/testcases/master-6.exp @@ -0,0 +1,2 @@ + + diff --git a/crm/pengine/testcases/master-6.xml b/crm/pengine/testcases/master-6.xml new file mode 100644 index 0000000000..6bf46ad3f2 --- /dev/null +++ b/crm/pengine/testcases/master-6.xml @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/plugins/lrm/raexecocf.c b/lib/plugins/lrm/raexecocf.c index 819d489e2c..6f7c91a523 100644 --- a/lib/plugins/lrm/raexecocf.c +++ b/lib/plugins/lrm/raexecocf.c @@ -1,493 +1,493 @@ /* * 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 * * File: raexecocf.c * Author: Sun Jiang Dong * Copyright (c) 2004 International Business Machines * * This code implements the Resource Agent Plugin Module for LSB style. * It's a part of Local Resource Manager. Currently it's used by lrmd only. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Add it for compiling on OSX */ #include #include # define PIL_PLUGINTYPE RA_EXEC_TYPE # define PIL_PLUGINTYPE_S "RAExec" # define PIL_PLUGINLICENSE LICENSE_PUBDOM # define PIL_PLUGINLICENSEURL URL_PUBDOM # define PIL_PLUGIN ocf # define PIL_PLUGIN_S "ocf" /* * Are there multiple paths? Now according to OCF spec, the answer is 'no'. * But actually or for future? */ static const char * RA_PATH = OCF_RA_DIR; /* The begin of exported function list */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params); static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output); static int get_resource_list(GList ** rsc_info); static char* get_resource_meta(const char* rsc_type, const char* provider); static int get_provider_list(const char* ra_type, GList ** providers); /* The end of exported function list */ /* The begin of internal used function & data list */ #define HADEBUGVAL "HA_DEBUG" static void add_OCF_prefix(GHashTable * params, GHashTable * new_params); static void add_OCF_env_vars(GHashTable * env, const char * rsc_id, const char * rsc_type, const char * provider); static void add_prefix_foreach(gpointer key, gpointer value, gpointer user_data); static void hash_to_str(GHashTable * , GString *); static void hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data); static int raexec_setenv(GHashTable * env_params); static void set_env(gpointer key, gpointer value, gpointer user_data); static gboolean let_remove_eachitem(gpointer key, gpointer value, gpointer user_data); static int get_providers(const char* class_path, const char* op_type, GList ** providers); static void merge_string_list(GList** old, GList* new); static gint compare_str(gconstpointer a, gconstpointer b); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, map_ra_retvalue, get_resource_list, get_provider_list, get_resource_meta }; PIL_PLUGIN_BOILERPLATE2("1.0", Debug) static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static void* OurImports; static void* interfprivate; /* * Our plugin initialization and registration function * It gets called when the plugin gets loaded. */ PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports) { /* Force the compiler to do a little type checking */ (void)(PILPluginInitFun)PIL_PLUGIN_INIT; PluginImports = imports; OurPlugin = us; /* Register ourself as a plugin */ imports->register_plugin(us, &OurPIExports); /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, NULL, &OurInterface, &OurImports, interfprivate); } /* * The function to execute a RA. */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params) { uniform_ret_execra_t exit_value; char ra_pathname[RA_MAX_NAME_LENGTH]; GHashTable * tmp_for_setenv; GString * params_gstring; char * inherit_debuglevel = NULL; get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname); /* Setup environment correctly */ tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal); add_OCF_prefix(params, tmp_for_setenv); add_OCF_env_vars(tmp_for_setenv, rsc_id, rsc_type, provider); raexec_setenv(tmp_for_setenv); g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL); g_hash_table_destroy(tmp_for_setenv); /* let this log show only high loglevel. */ inherit_debuglevel = getenv(HADEBUGVAL); if ((inherit_debuglevel != NULL) && (atoi(inherit_debuglevel) > 1)) { params_gstring = g_string_new(""); hash_to_str(params, params_gstring); cl_log(LOG_DEBUG, "RA instance %s executing: OCF::%s %s. Parameters: " "{%s}", rsc_id, rsc_type, op_type, params_gstring->str); g_string_free(params_gstring, TRUE); } /* execute the RA */ execl(ra_pathname, ra_pathname, op_type, NULL); cl_perror("(%s:%s:%d) execl failed for %s" , __FILE__, __FUNCTION__, __LINE__, ra_pathname); switch (errno) { case ENOENT: /* No such file or directory */ case EISDIR: /* Is a directory */ exit_value = EXECRA_NO_RA; break; default: exit_value = EXECRA_EXEC_UNKNOWN_ERROR; } exit(exit_value); } static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) { /* Because the UNIFORM_RET_EXECRA is compatible with OCF standard, * no actual mapping except validating, which ensure the return code * will be in the range 0 to 7. Too strict? */ - if (ret_execra < 0 || ret_execra > 7) { + if (ret_execra < 0 || ret_execra > 9) { cl_log(LOG_WARNING, "mapped the invalid return code %d." , ret_execra); ret_execra = EXECRA_UNKNOWN_ERROR; } return ret_execra; } static gint compare_str(gconstpointer a, gconstpointer b) { return strncmp(a,b,RA_MAX_NAME_LENGTH); } static int get_resource_list(GList ** rsc_info) { struct dirent **namelist; GList* item; int file_num; char subdir[FILENAME_MAX+1]; if ( rsc_info == NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list"); return -2; } if ( *rsc_info != NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list."\ "will cause memory leak."); *rsc_info = NULL; } file_num = scandir(RA_PATH, &namelist, 0, alphasort); if (file_num < 0) { return -2; } while (file_num--) { GList* ra_subdir = NULL; struct stat prop; if ('.' == namelist[file_num]->d_name[0]) { free(namelist[file_num]); continue; } stat(namelist[file_num]->d_name, &prop); if (S_ISDIR(prop.st_mode)) { free(namelist[file_num]); continue; } snprintf(subdir,FILENAME_MAX,"%s/%s", RA_PATH, namelist[file_num]->d_name); get_runnable_list(subdir,&ra_subdir); merge_string_list(rsc_info,ra_subdir); while (NULL != (item = g_list_first(ra_subdir))) { ra_subdir = g_list_remove_link(ra_subdir, item); g_free(item->data); g_list_free_1(item); } free(namelist[file_num]); } free(namelist); return 0; } static void merge_string_list(GList** old, GList* new) { GList* item = NULL; char* newitem; for( item=g_list_first(new); NULL!=item; item=g_list_next(item)){ if (!g_list_find_custom(*old, item->data,compare_str)){ newitem = g_strndup(item->data,RA_MAX_NAME_LENGTH); *old = g_list_append(*old, newitem); } } } static int get_provider_list(const char* ra_type, GList ** providers) { int ret; ret = get_providers(RA_PATH, ra_type, providers); if (0>ret) { cl_log(LOG_ERR, "scandir failed in OCF RA plugin"); } return ret; } static char* get_resource_meta(const char* rsc_type, const char* provider) { const int BUFF_LEN=4096; int read_len = 0; char buff[BUFF_LEN]; char* data = NULL; GString* g_str_tmp = NULL; char ra_pathname[RA_MAX_NAME_LENGTH]; FILE* file = NULL; GHashTable * tmp_for_setenv; get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname); strncat(ra_pathname, " meta-data",RA_MAX_NAME_LENGTH); tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal); add_OCF_env_vars(tmp_for_setenv, "DUMMY_INSTANCE", rsc_type, provider); raexec_setenv(tmp_for_setenv); g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL); g_hash_table_destroy(tmp_for_setenv); file = popen(ra_pathname, "r"); if (NULL==file) { return NULL; } g_str_tmp = g_string_new(""); while(!feof(file)) { memset(buff, 0, BUFF_LEN); read_len = fread(buff, 1, BUFF_LEN, file); if (0len) { pclose(file); return NULL; } data = (char*)g_new(char, g_str_tmp->len+1); data[0] = data[g_str_tmp->len] = 0; strncpy(data, g_str_tmp->str, g_str_tmp->len); g_string_free(g_str_tmp, TRUE); pclose(file); return data; } static void add_OCF_prefix(GHashTable * env_params, GHashTable * new_env_params) { if (env_params) { g_hash_table_foreach(env_params, add_prefix_foreach, new_env_params); } } static void add_prefix_foreach(gpointer key, gpointer value, gpointer user_data) { const int MAX_LENGTH_OF_ENV = 50; int prefix = STRLEN_CONST("OCF_RESKEY_"); GHashTable * new_hashtable = (GHashTable *) user_data; char * newkey; int keylen = strnlen((char*)key, MAX_LENGTH_OF_ENV-prefix)+prefix+1; newkey = g_new(gchar, keylen); strncpy(newkey, "OCF_RESKEY_", keylen); strncat(newkey, key, keylen); g_hash_table_insert(new_hashtable, (gpointer)newkey, g_strdup(value)); } static void hash_to_str(GHashTable * params , GString * str) { if (params) { g_hash_table_foreach(params, hash_to_str_foreach, str); } } static void hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data) { char buffer_tmp[60]; GString * str = (GString *)user_data; snprintf(buffer_tmp, 60, "%s=%s ", (char *)key, (char *)value); str = g_string_append(str, buffer_tmp); } static gboolean let_remove_eachitem(gpointer key, gpointer value, gpointer user_data) { g_free(key); g_free(value); return TRUE; } static int raexec_setenv(GHashTable * env_params) { if (env_params) { g_hash_table_foreach(env_params, set_env, NULL); } return 0; } static void set_env(gpointer key, gpointer value, gpointer user_data) { if (setenv(key, value, 1) != 0) { cl_log(LOG_ERR, "setenv failed in raexecocf."); } } static int get_providers(const char* class_path, const char* ra_type, GList ** providers) { struct dirent **namelist; int file_num; if ( providers == NULL ) { cl_log(LOG_ERR, "Parameter error: get_providers"); return -2; } if ( *providers != NULL ) { cl_log(LOG_ERR, "Parameter error: get_providers."\ "will cause memory leak."); *providers = NULL; } file_num = scandir(class_path, &namelist, 0, alphasort); if (file_num < 0) { return -2; }else{ char tmp_buffer[FILENAME_MAX+1]; struct stat prop; while (file_num--) { if ('.' == namelist[file_num]->d_name[0]) { free(namelist[file_num]); continue; } stat(namelist[file_num]->d_name, &prop); if (S_ISDIR(prop.st_mode)) { free(namelist[file_num]); continue; } snprintf(tmp_buffer,FILENAME_MAX,"%s/%s/%s", class_path, namelist[file_num]->d_name, ra_type); if ( filtered(tmp_buffer) == TRUE ) { *providers = g_list_append(*providers, g_strdup(namelist[file_num]->d_name)); } free(namelist[file_num]); } free(namelist); } return g_list_length(*providers); } static void add_OCF_env_vars(GHashTable * env, const char * rsc_id, const char * rsc_type, const char * provider) { if ( env == NULL ) { cl_log(LOG_WARNING, "env should not be a NULL pointer."); return; } g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MAJOR"), g_strdup("1")); g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MINOR"), g_strdup("0")); g_hash_table_insert(env, g_strdup("OCF_ROOT"), g_strdup(OCF_ROOT_DIR)); if ( rsc_id != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_INSTANCE"), g_strdup(rsc_id)); } /* Currently the rsc_type=="the filename of the RA script/executable", * It seems always correct even in the furture. ;-) */ if ( rsc_type != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_TYPE"), g_strdup(rsc_type)); } /* Notes: this is not added to specification yet. Sept 10,2004 */ if ( provider != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_PROVIDER"), g_strdup(provider)); } }