diff --git a/crmd/lrm.c b/crmd/lrm.c index fcc7e6e643..83da735e21 100644 --- a/crmd/lrm.c +++ b/crmd/lrm.c @@ -1,1890 +1,1894 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define START_DELAY_THRESHOLD 5 * 60 * 1000 struct recurring_op_s { - char *rsc_id; - char *op_key; - int call_id; - int interval; - gboolean remove; - gboolean cancelled; + char *rsc_id; + char *op_key; + int call_id; + int interval; + gboolean remove; + gboolean cancelled; }; struct pending_deletion_op_s { char *rsc; ha_msg_input_t *input; }; struct delete_event_s { int rc; const char *rsc; }; char *make_stop_id(const char *rsc, int call_id); void cib_rsc_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data); gboolean build_operation_update( xmlNode *rsc_list, lrm_rsc_t *rsc, lrm_op_t *op, const char *src, int lpc, int level); gboolean build_active_RAs(xmlNode *rsc_list); gboolean is_rsc_active(const char *rsc_id); int do_update_resource(lrm_op_t *op); gboolean process_lrm_event(lrm_op_t *op); void do_lrm_rsc_op(lrm_rsc_t *rsc, const char *operation, xmlNode *msg, xmlNode *request); lrm_op_t *construct_op( - xmlNode *rsc_op, const char *rsc_id, const char *operation); + xmlNode *rsc_op, const char *rsc_id, const char *operation); void send_direct_ack(const char *to_host, const char *to_sys, lrm_rsc_t *rsc, lrm_op_t* op, const char *rsc_id); void free_recurring_op(gpointer value); void free_deletion_op(gpointer value); GHashTable *resources = NULL; GHashTable *pending_ops = NULL; GHashTable *deletion_ops = NULL; GCHSource *lrm_source = NULL; int num_lrm_register_fails = 0; int max_lrm_register_fails = 30; void lrm_connection_destroy(gpointer user_data) { if(is_set(fsa_input_register, R_LRM_CONNECTED)) { crm_crit("LRM Connection failed"); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } else { crm_info("LRM Connection disconnected"); } lrm_source = NULL; } /* A_LRM_CONNECT */ void 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) { - if(fsa_lrm_conn == NULL) { - register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); + if(fsa_lrm_conn == NULL) { + register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); + return; + } + + if(action & A_LRM_DISCONNECT) { + if(verify_stopped(cur_state, LOG_INFO) == FALSE) { + crmd_fsa_stall(NULL); return; } - - if(action & A_LRM_DISCONNECT) { - if(verify_stopped(cur_state, LOG_INFO) == FALSE) { - crmd_fsa_stall(NULL); - return; - } - if(is_set(fsa_input_register, R_LRM_CONNECTED)) { - clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); - fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); - crm_info("Disconnected from the LRM"); - } - - /* TODO: Clean up the hashtable */ + if(is_set(fsa_input_register, R_LRM_CONNECTED)) { + clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); + fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); + crm_info("Disconnected from the LRM"); } - if(action & A_LRM_CONNECT) { - int ret = HA_OK; + /* TODO: Clean up the hashtable */ + } + + if(action & A_LRM_CONNECT) { + int ret = HA_OK; - deletion_ops = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, free_deletion_op); + deletion_ops = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, free_deletion_op); - pending_ops = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, free_recurring_op); + pending_ops = 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 = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, g_hash_destroy_str); - 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) { + 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); + 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; - } - } + crm_timer_start(wait_timer); + crmd_fsa_stall(NULL); + return; + } + } - 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_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; - } + 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; + } - /* 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, - lrm_connection_destroy); - - set_bit_inplace(fsa_input_register, R_LRM_CONNECTED); - crm_debug("LRM connection established"); + /* 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, + lrm_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__); - } + if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { + crm_err("Unexpected action %s in %s", + fsa_action2string(action), __FUNCTION__); + } } static void ghash_print_pending(gpointer key, gpointer value, gpointer user_data) { - const char *stop_id = key; - int *log_level = user_data; - struct recurring_op_s *pending = value; - do_crm_log(*log_level, "Pending action: %s (%s)", stop_id, pending->op_key); + const char *stop_id = key; + int *log_level = user_data; + struct recurring_op_s *pending = value; + do_crm_log(*log_level, "Pending action: %s (%s)", stop_id, pending->op_key); } static void ghash_print_pending_for_rsc(gpointer key, gpointer value, gpointer user_data) { - const char *stop_id = key; - char *rsc = user_data; - struct recurring_op_s *pending = value; - if(safe_str_eq(rsc, pending->rsc_id)) { - do_crm_log(LOG_NOTICE, "%sction %s (%s) incomplete at shutdown", - pending->interval==0?"A":"Recurring a", stop_id, pending->op_key); - } + const char *stop_id = key; + char *rsc = user_data; + struct recurring_op_s *pending = value; + if(safe_str_eq(rsc, pending->rsc_id)) { + do_crm_log(LOG_NOTICE, "%sction %s (%s) incomplete at shutdown", + pending->interval==0?"A":"Recurring a", stop_id, pending->op_key); + } } static void ghash_count_pending(gpointer key, gpointer value, gpointer user_data) { - int *counter = user_data; - struct recurring_op_s *pending = value; + int *counter = user_data; + struct recurring_op_s *pending = value; - if(pending->interval > 0) { - /* Ignore recurring actions in the shutdown calculations */ - return; - } + if(pending->interval > 0) { + /* Ignore recurring actions in the shutdown calculations */ + return; + } - (*counter)++; + (*counter)++; } gboolean verify_stopped(enum crmd_fsa_state cur_state, int log_level) { - int counter = 0; - gboolean rc = TRUE; - GListPtr lrm_list = NULL; + int counter = 0; + GListPtr lpc = NULL; + gboolean rc = TRUE; + GListPtr lrm_list = NULL; - crm_debug("Checking for active resources before exit"); + crm_debug("Checking for active resources before exit"); - if(cur_state == S_TERMINATE) { - log_level = LOG_ERR; - } + if(cur_state == S_TERMINATE) { + log_level = LOG_ERR; + } - if(pending_ops) { - g_hash_table_foreach(pending_ops, ghash_count_pending, &counter); - } + if(pending_ops) { + g_hash_table_foreach(pending_ops, ghash_count_pending, &counter); + } - if(counter > 0) { - rc = FALSE; - do_crm_log(log_level, - "%d pending LRM operations at shutdown%s", - counter, cur_state == S_TERMINATE?"":"... waiting"); + if(counter > 0) { + rc = FALSE; + do_crm_log(log_level, + "%d pending LRM operations at shutdown%s", + counter, cur_state == S_TERMINATE?"":"... waiting"); - if(cur_state == S_TERMINATE || !is_set(fsa_input_register, R_SENT_RSC_STOP)) { - g_hash_table_foreach( - pending_ops, ghash_print_pending, &log_level); - } - goto bail; + if(cur_state == S_TERMINATE || !is_set(fsa_input_register, R_SENT_RSC_STOP)) { + g_hash_table_foreach( + pending_ops, ghash_print_pending, &log_level); } + goto bail; + } - if(is_set(fsa_input_register, R_LRM_CONNECTED)) { - lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); - } + if(is_set(fsa_input_register, R_LRM_CONNECTED)) { + 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) == FALSE) { - continue; - } + for(lpc = lrm_list; lpc != NULL; lpc = lpc->next) { + char *rsc_id = (char*)lpc->data; + if(is_rsc_active(rsc_id) == FALSE) { + continue; + } - crm_err("Resource %s was active at shutdown." - " You may ignore this error if it is unmanaged.", - rsc_id); + crm_err("Resource %s was active at shutdown." + " You may ignore this error if it is unmanaged.", + rsc_id); - g_hash_table_foreach( - pending_ops, ghash_print_pending_for_rsc, rsc_id); - ); + g_hash_table_foreach( + pending_ops, ghash_print_pending_for_rsc, rsc_id); + } - slist_destroy(char, rid, lrm_list, free(rid)); + slist_destroy(char, rid, lrm_list, free(rid)); bail: - set_bit_inplace(fsa_input_register, R_SENT_RSC_STOP); + set_bit_inplace(fsa_input_register, R_SENT_RSC_STOP); - if(cur_state == S_TERMINATE) { - rc = TRUE; - } + if(cur_state == S_TERMINATE) { + rc = TRUE; + } - return rc; + return rc; } static char * get_rsc_metadata(const char *type, const char *class, const char *provider) { - char *metadata = NULL; - CRM_CHECK(type != NULL, return NULL); - CRM_CHECK(class != NULL, return NULL); - if(provider == NULL) { - provider = "heartbeat"; - } + char *metadata = NULL; + CRM_CHECK(type != NULL, return NULL); + CRM_CHECK(class != NULL, return NULL); + if(provider == NULL) { + provider = "heartbeat"; + } - crm_debug_2("Retreiving metadata for %s::%s:%s", type, class, provider); - metadata = fsa_lrm_conn->lrm_ops->get_rsc_type_metadata( - fsa_lrm_conn, class, type, provider); + crm_debug_2("Retreiving metadata for %s::%s:%s", type, class, provider); + metadata = fsa_lrm_conn->lrm_ops->get_rsc_type_metadata( + fsa_lrm_conn, class, type, provider); - if(metadata) { - /* copy the metadata because the LRM likes using - * g_alloc instead of cl_malloc - */ - char *m_copy = crm_strdup(metadata); - g_free(metadata); - metadata = m_copy; + if(metadata) { + /* copy the metadata because the LRM likes using + * g_alloc instead of cl_malloc + */ + char *m_copy = crm_strdup(metadata); + g_free(metadata); + metadata = m_copy; - } else { - crm_warn("No metadata found for %s::%s:%s", type, class, provider); - } + } else { + crm_warn("No metadata found for %s::%s:%s", type, class, provider); + } - return metadata; + return metadata; } typedef struct reload_data_s { char *key; char *metadata; time_t last_query; gboolean can_reload; GListPtr restart_list; } reload_data_t; static void g_hash_destroy_reload(gpointer data) { reload_data_t *reload = data; crm_free(reload->key); crm_free(reload->metadata); slist_destroy(char, child, reload->restart_list, crm_free(child)); crm_free(reload); } GHashTable *reload_hash = NULL; static GListPtr get_rsc_restart_list(lrm_rsc_t *rsc, lrm_op_t *op) { - int len = 0; - char *key = NULL; - char *copy = NULL; - const char *value = NULL; - const char *provider = NULL; - - xmlNode *params = NULL; - xmlNode *actions = NULL; - xmlNode *metadata = NULL; - - time_t now = time(NULL); - reload_data_t *reload = NULL; + int len = 0; + char *key = NULL; + char *copy = NULL; + const char *value = NULL; + const char *provider = NULL; + + xmlNode *params = NULL; + xmlNode *actions = NULL; + xmlNode *metadata = NULL; + + time_t now = time(NULL); + reload_data_t *reload = NULL; - if(reload_hash == NULL) { - reload_hash = g_hash_table_new_full( - g_str_hash, g_str_equal, NULL, g_hash_destroy_reload); - } + if(reload_hash == NULL) { + reload_hash = g_hash_table_new_full( + g_str_hash, g_str_equal, NULL, g_hash_destroy_reload); + } - provider = rsc->provider; - if(provider == NULL) { - provider = "heartbeat"; - } + provider = rsc->provider; + if(provider == NULL) { + provider = "heartbeat"; + } - len = strlen(rsc->type) + strlen(rsc->class) + strlen(provider) + 4; - crm_malloc(key, len); - snprintf(key, len, "%s::%s:%s", rsc->type, rsc->class, provider); + len = strlen(rsc->type) + strlen(rsc->class) + strlen(provider) + 4; + crm_malloc(key, len); + snprintf(key, len, "%s::%s:%s", rsc->type, rsc->class, provider); - reload = g_hash_table_lookup(reload_hash, key); + reload = g_hash_table_lookup(reload_hash, key); - if(reload - && ((now - 9) > reload->last_query) - && safe_str_eq(op->op_type, RSC_START)) { - reload = NULL; /* re-query */ - } + if(reload + && ((now - 9) > reload->last_query) + && safe_str_eq(op->op_type, RSC_START)) { + reload = NULL; /* re-query */ + } - if(reload == NULL) { - crm_malloc0(reload, sizeof(reload_data_t)); - g_hash_table_replace(reload_hash, key, reload); - - reload->last_query = now; - reload->key = key; key = NULL; - reload->metadata = get_rsc_metadata(rsc->type, rsc->class, provider); - - metadata = string2xml(reload->metadata); - if(metadata == NULL) { - crm_err("Metadata for %s::%s:%s is not valid XML", - rsc->provider, rsc->class, rsc->type); - goto cleanup; - } + if(reload == NULL) { + crm_malloc0(reload, sizeof(reload_data_t)); + g_hash_table_replace(reload_hash, key, reload); + + reload->last_query = now; + reload->key = key; key = NULL; + reload->metadata = get_rsc_metadata(rsc->type, rsc->class, provider); + + metadata = string2xml(reload->metadata); + if(metadata == NULL) { + crm_err("Metadata for %s::%s:%s is not valid XML", + rsc->provider, rsc->class, rsc->type); + goto cleanup; + } - actions = find_xml_node(metadata, "actions", TRUE); - - xml_child_iter_filter( - actions, action, "action", - value = crm_element_value(action, "name"); - if(safe_str_eq("reload", value)) { - reload->can_reload = TRUE; - break; - } - ); + actions = find_xml_node(metadata, "actions", TRUE); - if(reload->can_reload == FALSE) { - goto cleanup; + xml_child_iter_filter( + actions, action, "action", + value = crm_element_value(action, "name"); + if(safe_str_eq("reload", value)) { + reload->can_reload = TRUE; + break; } + ); + + if(reload->can_reload == FALSE) { + goto cleanup; + } - params = find_xml_node(metadata, "parameters", TRUE); - xml_child_iter_filter( - params, param, "parameter", - value = crm_element_value(param, "unique"); - if(crm_is_true(value)) { - value = crm_element_value(param, "name"); - if(value == NULL) { - crm_err("%s: NULL param", key); - continue; - } - crm_debug("Attr %s is not reloadable", value); - copy = crm_strdup(value); - CRM_CHECK(copy != NULL, continue); - reload->restart_list = g_list_append(reload->restart_list, copy); + params = find_xml_node(metadata, "parameters", TRUE); + xml_child_iter_filter( + params, param, "parameter", + value = crm_element_value(param, "unique"); + if(crm_is_true(value)) { + value = crm_element_value(param, "name"); + if(value == NULL) { + crm_err("%s: NULL param", key); + continue; } - ); - } + crm_debug("Attr %s is not reloadable", value); + copy = crm_strdup(value); + CRM_CHECK(copy != NULL, continue); + reload->restart_list = g_list_append(reload->restart_list, copy); + } + ); + } cleanup: - crm_free(key); - free_xml(metadata); - return reload?reload->restart_list:NULL; + crm_free(key); + free_xml(metadata); + return reload?reload->restart_list:NULL; } static void append_restart_list(lrm_rsc_t *rsc, lrm_op_t *op, xmlNode *update, const char *version) { - int len = 0; - char *list = NULL; - char *digest = NULL; - const char *value = NULL; - gboolean non_empty = FALSE; - xmlNode *restart = NULL; - GListPtr restart_list = NULL; - - if(op->interval > 0) { - /* monitors are not reloadable */ - return; + int len = 0; + char *list = NULL; + char *digest = NULL; + const char *value = NULL; + gboolean non_empty = FALSE; + xmlNode *restart = NULL; + GListPtr restart_list = NULL; + GListPtr lpc = NULL; + + if(op->interval > 0) { + /* monitors are not reloadable */ + return; - } else if(op->params == NULL) { - crm_debug("%s has no parameters", ID(update)); - return; + } else if(op->params == NULL) { + crm_debug("%s has no parameters", ID(update)); + return; - } else if(rsc == NULL) { - return; + } else if(rsc == NULL) { + return; - } else if(crm_str_eq(CRMD_ACTION_START, op->op_type, TRUE) == FALSE) { - /* only starts are potentially reloadable */ - return; + } else if(crm_str_eq(CRMD_ACTION_START, op->op_type, TRUE) == FALSE) { + /* only starts are potentially reloadable */ + return; - } else if(compare_version("1.0.8", version) > 0) { - /* Caller version does not support reloads */ - return; - } + } else if(compare_version("1.0.8", version) > 0) { + /* Caller version does not support reloads */ + return; + } - restart_list = get_rsc_restart_list(rsc, op); - if(restart_list == NULL) { - /* Resource does not support reloads */ - return; - } + restart_list = get_rsc_restart_list(rsc, op); + if(restart_list == NULL) { + /* Resource does not support reloads */ + return; + } - restart = create_xml_node(NULL, XML_TAG_PARAMS); - slist_iter(param, const char, restart_list, lpc, - int start = len; - CRM_CHECK(param != NULL, continue); - value = g_hash_table_lookup(op->params, param); - if(value != NULL) { - non_empty = TRUE; - crm_xml_add(restart, param, value); - } - len += strlen(param) + 2; - crm_realloc(list, len+1); - sprintf(list+start, " %s ", param); - ); + restart = create_xml_node(NULL, XML_TAG_PARAMS); + for(lpc = restart_list; lpc != NULL; lpc = lpc->next) { + const char *param = (const char*)lpc->data; + + int start = len; + CRM_CHECK(param != NULL, continue); + value = g_hash_table_lookup(op->params, param); + if(value != NULL) { + non_empty = TRUE; + crm_xml_add(restart, param, value); + } + len += strlen(param) + 2; + crm_realloc(list, len+1); + sprintf(list+start, " %s ", param); + } - digest = calculate_operation_digest(restart, version); - crm_xml_add(update, XML_LRM_ATTR_OP_RESTART, list); - crm_xml_add(update, XML_LRM_ATTR_RESTART_DIGEST, digest); + digest = calculate_operation_digest(restart, version); + crm_xml_add(update, XML_LRM_ATTR_OP_RESTART, list); + crm_xml_add(update, XML_LRM_ATTR_RESTART_DIGEST, digest); #if 0 - crm_debug("%s: %s, %s", rsc->id, digest, list); - if(non_empty) { - crm_log_xml_debug(restart, "restart digest source"); - } + crm_debug("%s: %s, %s", rsc->id, digest, list); + if(non_empty) { + crm_log_xml_debug(restart, "restart digest source"); + } #endif - free_xml(restart); - crm_free(digest); - crm_free(list); + free_xml(restart); + crm_free(digest); + crm_free(list); } gboolean build_operation_update( xmlNode *parent, lrm_rsc_t *rsc, lrm_op_t *op, const char *src, int lpc, int level) { xmlNode *xml_op = NULL; const char *caller_version = CRM_FEATURE_SET; if(AM_I_DC) { } else if(fsa_our_dc_version != NULL) { caller_version = fsa_our_dc_version; } else if(op->params == NULL) { caller_version = fsa_our_dc_version; } else { /* there is a small risk in formerly mixed clusters that * it will be sub-optimal. * however with our upgrade policy, the update we send * should still be completely supported anyway */ caller_version = g_hash_table_lookup( op->params, XML_ATTR_CRM_VERSION); crm_warn("Falling back to operation originator version: %s", caller_version); } xml_op = create_operation_update(parent, op, caller_version, 0, src, level); if(xml_op) { append_restart_list(rsc, op, xml_op, caller_version); } 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; + GListPtr llpc = NULL; + 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; - } + if(fsa_lrm_conn == NULL) { + return FALSE; + } - the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rsc_id); + the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rsc_id); - crm_debug_3("Processing lrm_rsc_t entry %s", rsc_id); + crm_debug_3("Processing lrm_rsc_t entry %s", rsc_id); - if(the_rsc == NULL) { - crm_err("NULL resource returned from the LRM"); - return FALSE; - } + 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); + 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"); + crm_debug_3("\tcurrent state:%s",cur_state==LRM_RSC_IDLE?"Idle":"Busy"); - slist_iter( - op, lrm_op_t, op_list, llpc, + for(llpc = op_list; llpc != NULL; llpc = llpc->next) { + lrm_op_t *op = (lrm_op_t*)llpc->data; + crm_debug_2("Processing op %s_%d (%d) for %s (status=%d, rc=%d)", + op->op_type, op->interval, op->call_id, the_rsc->id, + op->op_status, op->rc); - crm_debug_2("Processing op %s_%d (%d) for %s (status=%d, rc=%d)", - op->op_type, op->interval, op->call_id, the_rsc->id, - op->op_status, op->rc); - - CRM_ASSERT(max_call_id <= op->call_id); - if(op->rc == EXECRA_OK - && safe_str_eq(op->op_type, CRMD_ACTION_STOP)) { - active = FALSE; + CRM_ASSERT(max_call_id <= op->call_id); + if(op->rc == EXECRA_OK + && safe_str_eq(op->op_type, CRMD_ACTION_STOP)) { + active = FALSE; - } else if(op->rc == EXECRA_OK - && safe_str_eq(op->op_type, CRMD_ACTION_MIGRATE)) { - /* a stricter check is too complex... - * leave that to the PE - */ - active = FALSE; + } else if(op->rc == EXECRA_OK + && safe_str_eq(op->op_type, CRMD_ACTION_MIGRATE)) { + /* a stricter check is too complex... + * leave that to the PE + */ + active = FALSE; - } else if(op->rc == EXECRA_NOT_RUNNING) { - active = FALSE; + } else if(op->rc == EXECRA_NOT_RUNNING) { + active = FALSE; - } else { - active = TRUE; - } + } else { + active = TRUE; + } - max_call_id = op->call_id; - lrm_free_op(op); - ); + max_call_id = op->call_id; + lrm_free_op(op); + } - g_list_free(op_list); - lrm_free_rsc(the_rsc); + g_list_free(op_list); + lrm_free_rsc(the_rsc); - return active; + return active; } gboolean build_active_RAs(xmlNode *rsc_list) { - GList *op_list = NULL; - GList *lrm_list = NULL; - gboolean found_op = FALSE; - state_flag_t cur_state = 0; + GListPtr lpc = NULL; + GListPtr llpc = NULL; + 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; + if(fsa_lrm_conn == NULL) { + return FALSE; + } + + lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); + + for(lpc = lrm_list; lpc != NULL; lpc = lpc->next) { + char *rid = (char*)lpc->data; + int max_call_id = -1; + xmlNode *xml_rsc = NULL; + lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); + + if(the_rsc == NULL) { + crm_err("NULL resource returned from the LRM: %s", rid); + continue; } - lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); + xml_rsc = create_xml_node(rsc_list, XML_LRM_TAG_RESOURCE); + 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); - slist_iter( - rid, char, lrm_list, lpc, + op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); - int max_call_id = -1; - xmlNode *xml_rsc = NULL; - lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); - - if(the_rsc == NULL) { - crm_err("NULL resource returned from the LRM: %s", rid); - continue; - } + for(llpc = op_list; llpc != NULL; llpc = llpc->next) { + lrm_op_t *op = (lrm_op_t*)llpc->data; + if(max_call_id < op->call_id) { + build_operation_update( + xml_rsc, the_rsc, op, __FUNCTION__, 0, LOG_DEBUG); + + } 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); - xml_rsc = create_xml_node(rsc_list, XML_LRM_TAG_RESOURCE); - 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); - - slist_iter( - op, lrm_op_t, op_list, llpc, - - if(max_call_id < op->call_id) { - build_operation_update( - xml_rsc, the_rsc, op, __FUNCTION__, llpc, LOG_DEBUG); - - } 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); - ); + } 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)); - } + 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(op_list); + lrm_free_rsc(the_rsc); + } - slist_destroy(char, rid, lrm_list, free(rid)); + slist_destroy(char, rid, lrm_list, free(rid)); - return TRUE; + return TRUE; } xmlNode* do_lrm_query(gboolean is_replace) { - gboolean shut_down = FALSE; - xmlNode *xml_result= NULL; - xmlNode *xml_state = NULL; - xmlNode *xml_data = NULL; - xmlNode *rsc_list = NULL; - const char *exp_state = CRMD_STATE_ACTIVE; - - if(is_set(fsa_input_register, R_SHUTDOWN)) { - exp_state = CRMD_STATE_INACTIVE; - shut_down = TRUE; - } + gboolean shut_down = FALSE; + xmlNode *xml_result= NULL; + xmlNode *xml_state = NULL; + xmlNode *xml_data = NULL; + xmlNode *rsc_list = NULL; + const char *exp_state = CRMD_STATE_ACTIVE; + + 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_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); - crm_xml_add(xml_data, XML_ATTR_ID, fsa_our_uuid); - rsc_list = create_xml_node(xml_data, XML_LRM_TAG_RESOURCES); + xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); + crm_xml_add(xml_data, XML_ATTR_ID, fsa_our_uuid); + 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); + /* Build a list of active (not always running) resources */ + build_active_RAs(rsc_list); - xml_result = create_cib_fragment(xml_state, XML_CIB_TAG_STATUS); - crm_log_xml_debug_3(xml_state, "Current state of the LRM"); - free_xml(xml_state); + xml_result = create_cib_fragment(xml_state, XML_CIB_TAG_STATUS); + crm_log_xml_debug_3(xml_state, "Current state of the LRM"); + free_xml(xml_state); - return xml_result; + return xml_result; } static void notify_deleted(ha_msg_input_t *input, const char *rsc_id, int rc) { lrm_op_t* op = NULL; const char *from_sys = crm_element_value(input->msg, F_CRM_SYS_FROM); const char *from_host = crm_element_value(input->msg, F_CRM_HOST_FROM); crm_info("Notifying %s on %s that %s was%s deleted", from_sys, from_host, rsc_id, rc==HA_OK?"":" not"); op = construct_op(input->xml, rsc_id, CRMD_ACTION_DELETE); CRM_ASSERT(op != NULL); if(rc == HA_OK) { op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; } else { op->op_status = LRM_OP_ERROR; op->rc = EXECRA_UNKNOWN_ERROR; } send_direct_ack(from_host, from_sys, NULL, op, rsc_id); free_lrm_op(op); if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { /* this isn't expected - trigger a new transition */ time_t now = time(NULL); char *now_s = crm_itoa(now); crm_debug("Triggering a refresh after %s deleted %s from the LRM", from_sys, rsc_id); update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL, "last-lrm-refresh", now_s, FALSE); crm_free(now_s); } } static gboolean lrm_remove_deleted_rsc( gpointer key, gpointer value, gpointer user_data) { struct delete_event_s *event = user_data; struct pending_deletion_op_s *op = value; if(safe_str_eq(event->rsc, op->rsc)) { notify_deleted(op->input, event->rsc, event->rc); return TRUE; } return FALSE; } static gboolean lrm_remove_deleted_op( gpointer key, gpointer value, gpointer user_data) { const char *rsc = user_data; struct recurring_op_s *pending = value; if(safe_str_eq(rsc, pending->rsc_id)) { crm_info("Removing op %s:%d for deleted resource %s", pending->op_key, pending->call_id, rsc); return TRUE; } return FALSE; } /* * Remove the rsc from the CIB * * Avoids refreshing the entire LRM section of this host */ #define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']" static void delete_rsc_entry(ha_msg_input_t *input, const char *rsc_id, int rc) { struct delete_event_s event; CRM_CHECK(rsc_id != NULL, return); if(rc == HA_OK) { char *rsc_xpath = NULL; char *rsc_id_copy = crm_strdup(rsc_id); int max = strlen(rsc_template) + strlen(rsc_id) + strlen(fsa_our_uname) + 1; crm_malloc0(rsc_xpath, max); snprintf(rsc_xpath, max, rsc_template, fsa_our_uname, rsc_id); CRM_CHECK(rsc_id != NULL, return); crm_debug("sync: Sending delete op for %s", rsc_id); fsa_cib_conn->cmds->delete( fsa_cib_conn, rsc_xpath, NULL, cib_quorum_override|cib_xpath); g_hash_table_foreach_remove(pending_ops, lrm_remove_deleted_op, rsc_id_copy); crm_free(rsc_id_copy); crm_free(rsc_xpath); } if(input) { notify_deleted(input, rsc_id, rc); } event.rc = rc; event.rsc = rsc_id; g_hash_table_foreach_remove(deletion_ops, lrm_remove_deleted_rsc, &event); } /* * Remove the op from the CIB * * Avoids refreshing the entire LRM section of this host */ #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']" #define op_call_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s' and @"XML_LRM_ATTR_CALLID"='%d']" static void delete_op_entry(lrm_op_t *op, const char *rsc_id, const char *key, int call_id) { - xmlNode *xml_top = NULL; - if(op != NULL) { - xml_top = create_xml_node(NULL, XML_LRM_TAG_RSC_OP); - crm_xml_add_int(xml_top, XML_LRM_ATTR_CALLID, op->call_id); - crm_xml_add(xml_top, XML_ATTR_TRANSITION_KEY, op->user_data); + xmlNode *xml_top = NULL; + if(op != NULL) { + xml_top = create_xml_node(NULL, XML_LRM_TAG_RSC_OP); + crm_xml_add_int(xml_top, XML_LRM_ATTR_CALLID, op->call_id); + crm_xml_add(xml_top, XML_ATTR_TRANSITION_KEY, op->user_data); - crm_debug("async: Sending delete op for %s_%s_%d (call=%d)", - op->rsc_id, op->op_type, op->interval, op->call_id); - - fsa_cib_conn->cmds->delete( - fsa_cib_conn, XML_CIB_TAG_STATUS, xml_top, cib_quorum_override); - - } else if (rsc_id != NULL && key != NULL) { - int max = 0; - char *op_xpath = NULL; - if(call_id > 0) { - max = strlen(op_call_template) + strlen(rsc_id) + strlen(fsa_our_uname) + strlen(key) + 10; - crm_malloc0(op_xpath, max); - snprintf(op_xpath, max, op_call_template, fsa_our_uname, rsc_id, key, call_id); - - } else { - max = strlen(op_template) + strlen(rsc_id) + strlen(fsa_our_uname) + strlen(key) + 1; - crm_malloc0(op_xpath, max); - snprintf(op_xpath, max, op_template, fsa_our_uname, rsc_id, key); - } - - crm_debug("sync: Sending delete op for %s (call=%d)", rsc_id, call_id); - fsa_cib_conn->cmds->delete( - fsa_cib_conn, op_xpath, NULL, cib_quorum_override|cib_xpath); + crm_debug("async: Sending delete op for %s_%s_%d (call=%d)", + op->rsc_id, op->op_type, op->interval, op->call_id); - crm_free(op_xpath); + fsa_cib_conn->cmds->delete( + fsa_cib_conn, XML_CIB_TAG_STATUS, xml_top, cib_quorum_override); + + } else if (rsc_id != NULL && key != NULL) { + int max = 0; + char *op_xpath = NULL; + if(call_id > 0) { + max = strlen(op_call_template) + strlen(rsc_id) + strlen(fsa_our_uname) + strlen(key) + 10; + crm_malloc0(op_xpath, max); + snprintf(op_xpath, max, op_call_template, fsa_our_uname, rsc_id, key, call_id); } else { - crm_err("Not enough information to delete op entry: rsc=%p key=%p", rsc_id, key); - return; + max = strlen(op_template) + strlen(rsc_id) + strlen(fsa_our_uname) + strlen(key) + 1; + crm_malloc0(op_xpath, max); + snprintf(op_xpath, max, op_template, fsa_our_uname, rsc_id, key); } + + crm_debug("sync: Sending delete op for %s (call=%d)", rsc_id, call_id); + fsa_cib_conn->cmds->delete( + fsa_cib_conn, op_xpath, NULL, cib_quorum_override|cib_xpath); + + crm_free(op_xpath); + + } else { + crm_err("Not enough information to delete op entry: rsc=%p key=%p", rsc_id, key); + return; + } - crm_log_xml_debug_2(xml_top, "op:cancel"); - free_xml(xml_top); + crm_log_xml_debug_2(xml_top, "op:cancel"); + free_xml(xml_top); } static gboolean cancel_op(lrm_rsc_t *rsc, const char *key, int op, gboolean remove) { - int rc = HA_OK; - struct recurring_op_s *pending = NULL; + int rc = HA_OK; + struct recurring_op_s *pending = NULL; - CRM_CHECK(op != 0, return FALSE); - CRM_CHECK(rsc != NULL, return FALSE); - if(key == NULL) { - key = make_stop_id(rsc->id, op); - } - pending = g_hash_table_lookup(pending_ops, key); + CRM_CHECK(op != 0, return FALSE); + CRM_CHECK(rsc != NULL, return FALSE); + if(key == NULL) { + key = make_stop_id(rsc->id, op); + } + pending = g_hash_table_lookup(pending_ops, key); - if(pending) { - if(remove && pending->remove == FALSE) { - pending->remove = TRUE; - crm_debug("Scheduling %s for removal", key); - } + if(pending) { + if(remove && pending->remove == FALSE) { + pending->remove = TRUE; + crm_debug("Scheduling %s for removal", key); + } - if(pending->cancelled) { - crm_debug("Operation %s already cancelled", key); - return TRUE; - } + if(pending->cancelled) { + crm_debug("Operation %s already cancelled", key); + return TRUE; + } - pending->cancelled = TRUE; + pending->cancelled = TRUE; - } else { - crm_info("No pending op found for %s", key); - } + } else { + crm_info("No pending op found for %s", key); + } - crm_debug("Cancelling op %d for %s (%s)", op, rsc->id, key); + crm_debug("Cancelling op %d for %s (%s)", op, rsc->id, key); - rc = rsc->ops->cancel_op(rsc, op); - if(rc == HA_OK) { - crm_debug("Op %d for %s (%s): cancelled", op, rsc->id, key); + rc = rsc->ops->cancel_op(rsc, op); + if(rc == HA_OK) { + crm_debug("Op %d for %s (%s): cancelled", op, rsc->id, key); #ifdef HAVE_LRM_OP_T_RSC_DELETED - } else if(rc == HA_RSCBUSY) { - crm_debug("Op %d for %s (%s): cancelation pending", op, rsc->id, key); + } else if(rc == HA_RSCBUSY) { + crm_debug("Op %d for %s (%s): cancelation pending", op, rsc->id, key); #endif - } else { - crm_debug("Op %d for %s (%s): Nothing to cancel", op, rsc->id, key); - /* The caller needs to make sure the entry is - * removed from the pending_ops list - * - * Usually by returning TRUE inside the worker function - * supplied to g_hash_table_foreach_remove() - * - * Not removing the entry from pending_ops will block - * the node from shutting down - */ - return FALSE; - } + } else { + crm_debug("Op %d for %s (%s): Nothing to cancel", op, rsc->id, key); + /* The caller needs to make sure the entry is + * removed from the pending_ops list + * + * Usually by returning TRUE inside the worker function + * supplied to g_hash_table_foreach_remove() + * + * Not removing the entry from pending_ops will block + * the node from shutting down + */ + return FALSE; + } - return TRUE; + return TRUE; } struct cancel_data { gboolean done; gboolean remove; const char *key; lrm_rsc_t *rsc; }; static gboolean cancel_action_by_key(gpointer key, gpointer value, gpointer user_data) { - struct cancel_data *data = user_data; - struct recurring_op_s *op = (struct recurring_op_s*)value; + struct cancel_data *data = user_data; + struct recurring_op_s *op = (struct recurring_op_s*)value; - if(safe_str_eq(op->op_key, data->key)) { - data->done = TRUE; - if (cancel_op(data->rsc, key, op->call_id, data->remove) == FALSE) { - return TRUE; - } + if(safe_str_eq(op->op_key, data->key)) { + data->done = TRUE; + if (cancel_op(data->rsc, key, op->call_id, data->remove) == FALSE) { + return TRUE; } - return FALSE; + } + return FALSE; } static gboolean cancel_op_key(lrm_rsc_t *rsc, const char *key, gboolean remove) { - struct cancel_data data; + struct cancel_data data; - CRM_CHECK(rsc != NULL, return FALSE); - CRM_CHECK(key != NULL, return FALSE); + CRM_CHECK(rsc != NULL, return FALSE); + CRM_CHECK(key != NULL, return FALSE); - data.key = key; - data.rsc = rsc; - data.done = FALSE; - data.remove = remove; + data.key = key; + data.rsc = rsc; + data.done = FALSE; + data.remove = remove; - g_hash_table_foreach_remove(pending_ops, cancel_action_by_key, &data); - return data.done; + g_hash_table_foreach_remove(pending_ops, cancel_action_by_key, &data); + return data.done; } static lrm_rsc_t * get_lrm_resource(xmlNode *resource, xmlNode *op_msg, gboolean do_create) { - char rid[RID_LEN]; - lrm_rsc_t *rsc = NULL; - const char *short_id = ID(resource); - const char *long_id = crm_element_value(resource, XML_ATTR_ID_LONG); + char rid[RID_LEN]; + lrm_rsc_t *rsc = NULL; + const char *short_id = ID(resource); + const char *long_id = crm_element_value(resource, XML_ATTR_ID_LONG); - crm_debug_2("Retrieving %s from the LRM.", short_id); - CRM_CHECK(short_id != NULL, return NULL); + crm_debug_2("Retrieving %s from the LRM.", short_id); + CRM_CHECK(short_id != NULL, return NULL); - if(rsc == NULL) { - /* check if its already there (short name) */ - strncpy(rid, short_id, RID_LEN); - rid[RID_LEN-1] = 0; - rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); - } - if(rsc == NULL && long_id != NULL) { - /* try the long name instead */ - strncpy(rid, long_id, RID_LEN); - rid[RID_LEN-1] = 0; - rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); - } + if(rsc == NULL) { + /* check if its already there (short name) */ + strncpy(rid, short_id, RID_LEN); + rid[RID_LEN-1] = 0; + rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); + } + if(rsc == NULL && long_id != NULL) { + /* try the long name instead */ + strncpy(rid, long_id, RID_LEN); + rid[RID_LEN-1] = 0; + rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); + } - if(rsc == NULL && do_create) { - /* add it to the LRM */ - const char *type = crm_element_value(resource, XML_ATTR_TYPE); - const char *class = crm_element_value(resource, XML_AGENT_ATTR_CLASS); - const char *provider = crm_element_value(resource, XML_AGENT_ATTR_PROVIDER); - GHashTable *params = xml2list(op_msg); + if(rsc == NULL && do_create) { + /* add it to the LRM */ + const char *type = crm_element_value(resource, XML_ATTR_TYPE); + const char *class = crm_element_value(resource, XML_AGENT_ATTR_CLASS); + const char *provider = crm_element_value(resource, XML_AGENT_ATTR_PROVIDER); + GHashTable *params = xml2list(op_msg); - CRM_CHECK(class != NULL, return NULL); - CRM_CHECK(type != NULL, return NULL); + CRM_CHECK(class != NULL, return NULL); + CRM_CHECK(type != NULL, return NULL); - crm_debug_2("Adding rsc %s before operation", short_id); - strncpy(rid, short_id, RID_LEN); - rid[RID_LEN-1] = 0; + crm_debug_2("Adding rsc %s before operation", short_id); + strncpy(rid, short_id, RID_LEN); + rid[RID_LEN-1] = 0; - if(g_hash_table_size(params) == 0) { - crm_log_xml_warn(op_msg, "EmptyParams"); - } + if(g_hash_table_size(params) == 0) { + crm_log_xml_warn(op_msg, "EmptyParams"); + } - if(params != NULL) { - g_hash_table_remove(params, CRM_META"_op_target_rc"); - } + if(params != NULL) { + g_hash_table_remove(params, CRM_META"_op_target_rc"); + } - fsa_lrm_conn->lrm_ops->add_rsc( - fsa_lrm_conn, rid, class, type, provider, params); + 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); + rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); + g_hash_table_destroy(params); - if(rsc == NULL) { - fsa_data_t *msg_data = NULL; - crm_err("Could not add resource %s to LRM", rid); - register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); - } + if(rsc == NULL) { + fsa_data_t *msg_data = NULL; + crm_err("Could not add resource %s to LRM", rid); + register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } - return rsc; + } + return rsc; } /* A_LRM_INVOKE */ void 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) { - gboolean done = FALSE; - gboolean create_rsc = TRUE; - const char *crm_op = NULL; - const char *from_sys = NULL; - const char *from_host = NULL; - const char *operation = NULL; - ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); - - crm_op = crm_element_value(input->msg, F_CRM_TASK); - from_sys = crm_element_value(input->msg, F_CRM_SYS_FROM); - if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { - from_host = crm_element_value(input->msg, F_CRM_HOST_FROM); - } + gboolean done = FALSE; + gboolean create_rsc = TRUE; + const char *crm_op = NULL; + const char *from_sys = NULL; + const char *from_host = NULL; + const char *operation = NULL; + ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); + + crm_op = crm_element_value(input->msg, F_CRM_TASK); + from_sys = crm_element_value(input->msg, F_CRM_SYS_FROM); + if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { + from_host = crm_element_value(input->msg, F_CRM_HOST_FROM); + } - crm_debug_2("LRM command from: %s", from_sys); + crm_debug_2("LRM command from: %s", from_sys); - if(safe_str_eq(crm_op, CRM_OP_LRM_DELETE)) { - operation = CRMD_ACTION_DELETE; + 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(safe_str_eq(operation, CRM_OP_LRM_REFRESH)) { + crm_op = CRM_OP_LRM_REFRESH; - } else if(safe_str_eq(crm_op, CRM_OP_LRM_FAIL)) { + } else if(safe_str_eq(crm_op, CRM_OP_LRM_FAIL)) { #if HAVE_STRUCT_LRM_OPS_FAIL_RSC - int rc = HA_OK; - lrm_op_t* op = NULL; + int rc = HA_OK; + lrm_op_t* op = NULL; - lrm_rsc_t *rsc = NULL; - xmlNode *xml_rsc = find_xml_node( - input->xml, XML_CIB_TAG_RESOURCE, TRUE); + lrm_rsc_t *rsc = NULL; + xmlNode *xml_rsc = find_xml_node( + input->xml, XML_CIB_TAG_RESOURCE, TRUE); - CRM_CHECK(xml_rsc != NULL, return); + CRM_CHECK(xml_rsc != NULL, return); - op = construct_op(input->xml, ID(xml_rsc), "fail"); - op->op_status = LRM_OP_ERROR; - op->rc = EXECRA_UNKNOWN_ERROR; - CRM_ASSERT(op != NULL); + op = construct_op(input->xml, ID(xml_rsc), "fail"); + op->op_status = LRM_OP_ERROR; + op->rc = EXECRA_UNKNOWN_ERROR; + CRM_ASSERT(op != NULL); - rsc = get_lrm_resource(xml_rsc, input->xml, create_rsc); - if(rsc) { - crm_info("Failing resource %s...", rsc->id); - - rc = fsa_lrm_conn->lrm_ops->fail_rsc(fsa_lrm_conn, rsc->id, 1, "do_lrm_invoke: Async failure"); - if(rc != HA_OK) { - crm_err("Could not initiate an asynchronous failure for %s (%d)", rsc->id, rc); - } else { - op->op_status = LRM_OP_DONE; - op->rc = EXECRA_OK; - } + rsc = get_lrm_resource(xml_rsc, input->xml, create_rsc); + if(rsc) { + crm_info("Failing resource %s...", rsc->id); + + rc = fsa_lrm_conn->lrm_ops->fail_rsc(fsa_lrm_conn, rsc->id, 1, "do_lrm_invoke: Async failure"); + if(rc != HA_OK) { + crm_err("Could not initiate an asynchronous failure for %s (%d)", rsc->id, rc); + } else { + op->op_status = LRM_OP_DONE; + op->rc = EXECRA_OK; + } - lrm_free_rsc(rsc); + lrm_free_rsc(rsc); - } else { - crm_info("Cannot find/create resource in order to fail it..."); - crm_log_xml_warn(input->msg, "bad input"); - } + } else { + crm_info("Cannot find/create resource in order to fail it..."); + crm_log_xml_warn(input->msg, "bad input"); + } - send_direct_ack(from_host, from_sys, NULL, op, ID(xml_rsc)); - free_lrm_op(op); - return; + send_direct_ack(from_host, from_sys, NULL, op, ID(xml_rsc)); + free_lrm_op(op); + return; #else - crm_info("Failing resource..."); - operation = "fail"; + crm_info("Failing resource..."); + operation = "fail"; #endif - } else if(input->xml != NULL) { - operation = crm_element_value(input->xml, XML_LRM_ATTR_TASK); - } + } else if(input->xml != NULL) { + operation = crm_element_value(input->xml, XML_LRM_ATTR_TASK); + } - if(safe_str_eq(crm_op, CRM_OP_LRM_REFRESH)) { - enum cib_errors rc = cib_ok; - xmlNode *fragment = do_lrm_query(TRUE); - crm_info("Forcing a local LRM refresh"); + if(safe_str_eq(crm_op, CRM_OP_LRM_REFRESH)) { + enum cib_errors rc = cib_ok; + xmlNode *fragment = do_lrm_query(TRUE); + crm_info("Forcing a local LRM refresh"); - fsa_cib_update(XML_CIB_TAG_STATUS, fragment, - cib_quorum_override, rc); - free_xml(fragment); + fsa_cib_update(XML_CIB_TAG_STATUS, fragment, + cib_quorum_override, rc); + free_xml(fragment); - } else if(safe_str_eq(crm_op, CRM_OP_LRM_QUERY)) { - xmlNode *data = do_lrm_query(FALSE); - xmlNode *reply = create_reply(input->msg, data); + } else if(safe_str_eq(crm_op, CRM_OP_LRM_QUERY)) { + xmlNode *data = do_lrm_query(FALSE); + xmlNode *reply = create_reply(input->msg, data); - if(relay_message(reply, TRUE) == FALSE) { - crm_err("Unable to route reply"); - crm_log_xml(LOG_ERR, "reply", reply); - } - free_xml(reply); - free_xml(data); - - } else if(safe_str_eq(operation, CRM_OP_PROBED) - || safe_str_eq(crm_op, CRM_OP_REPROBE)) { - int cib_options = cib_inhibit_notify; - const char *probed = XML_BOOLEAN_TRUE; - if(safe_str_eq(crm_op, CRM_OP_REPROBE)) { - cib_options = cib_none; - probed = XML_BOOLEAN_FALSE; - } + if(relay_message(reply, TRUE) == FALSE) { + crm_err("Unable to route reply"); + crm_log_xml(LOG_ERR, "reply", reply); + } + free_xml(reply); + free_xml(data); + + } else if(safe_str_eq(operation, CRM_OP_PROBED) + || safe_str_eq(crm_op, CRM_OP_REPROBE)) { + int cib_options = cib_inhibit_notify; + const char *probed = XML_BOOLEAN_TRUE; + if(safe_str_eq(crm_op, CRM_OP_REPROBE)) { + cib_options = cib_none; + probed = XML_BOOLEAN_FALSE; + } - update_attrd(NULL, CRM_OP_PROBED, probed); + update_attrd(NULL, CRM_OP_PROBED, probed); - } else if(operation != NULL) { - lrm_rsc_t *rsc = NULL; - xmlNode *params = NULL; - xmlNode *xml_rsc = find_xml_node( - input->xml, XML_CIB_TAG_RESOURCE, TRUE); + } else if(operation != NULL) { + lrm_rsc_t *rsc = NULL; + xmlNode *params = NULL; + xmlNode *xml_rsc = find_xml_node( + input->xml, XML_CIB_TAG_RESOURCE, TRUE); - CRM_CHECK(xml_rsc != NULL, return); + CRM_CHECK(xml_rsc != NULL, return); - /* only the first 16 chars are used by the LRM */ - params = find_xml_node(input->xml, XML_TAG_ATTRS, TRUE); + /* only the first 16 chars are used by the LRM */ + params = find_xml_node(input->xml, XML_TAG_ATTRS, TRUE); - if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { - create_rsc = FALSE; - } + if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { + create_rsc = FALSE; + } - rsc = get_lrm_resource(xml_rsc, input->xml, create_rsc); - - if(rsc == NULL && create_rsc) { - crm_err("Invalid resource definition"); - crm_log_xml_warn(input->msg, "bad input"); - - } else if(rsc == NULL) { - lrm_op_t* op = NULL; - crm_notice("Not creating resource for a %s event: %s", - operation, ID(input->xml)); - - op = construct_op(input->xml, ID(xml_rsc), operation); - op->op_status = LRM_OP_DONE; - op->rc = EXECRA_OK; - CRM_ASSERT(op != NULL); - send_direct_ack(from_host, from_sys, NULL, op, ID(xml_rsc)); - free_lrm_op(op); + rsc = get_lrm_resource(xml_rsc, input->xml, create_rsc); + + if(rsc == NULL && create_rsc) { + crm_err("Invalid resource definition"); + crm_log_xml_warn(input->msg, "bad input"); + + } else if(rsc == NULL) { + lrm_op_t* op = NULL; + crm_notice("Not creating resource for a %s event: %s", + operation, ID(input->xml)); + + op = construct_op(input->xml, ID(xml_rsc), operation); + op->op_status = LRM_OP_DONE; + op->rc = EXECRA_OK; + CRM_ASSERT(op != NULL); + send_direct_ack(from_host, from_sys, NULL, op, ID(xml_rsc)); + free_lrm_op(op); - } else if(safe_str_eq(operation, CRMD_ACTION_CANCEL)) { - lrm_op_t* op = NULL; - char *op_key = NULL; - char *meta_key = NULL; - int call = 0; - const char *call_id = NULL; - const char *op_task = NULL; - const char *op_interval = NULL; - - CRM_CHECK(params != NULL, - crm_log_xml_warn(input->xml, "Bad command"); - return); - - - meta_key = crm_meta_name(XML_LRM_ATTR_INTERVAL); - op_interval = crm_element_value(params, meta_key); - crm_free(meta_key); - - meta_key = crm_meta_name(XML_LRM_ATTR_TASK); - op_task = crm_element_value(params, meta_key); - crm_free(meta_key); - - meta_key = crm_meta_name(XML_LRM_ATTR_CALLID); - call_id = crm_element_value(params, meta_key); - crm_free(meta_key); - - CRM_CHECK(op_task != NULL, - crm_log_xml_warn(input->xml, "Bad command"); - return); - CRM_CHECK(op_interval != NULL, - crm_log_xml_warn(input->xml, "Bad command"); - return); - - op = construct_op(input->xml, rsc->id, op_task); - CRM_ASSERT(op != NULL); - op_key = generate_op_key( - rsc->id,op_task,crm_parse_int(op_interval,"0")); - - crm_debug("PE requested op %s (call=%s) be cancelled", - op_key, call_id?call_id:"NA"); - call = crm_parse_int(call_id, "0"); - if(call == 0) { - /* the normal case when the PE cancels a recurring op */ - done = cancel_op_key(rsc, op_key, TRUE); - - } else { - /* the normal case when the PE cancels an orphan op */ - done = cancel_op(rsc, NULL, call, TRUE); - } - - if(done == FALSE) { - crm_debug("Nothing known about operation %d for %s", call, op_key); - delete_op_entry(NULL, rsc->id, op_key, call); - - /* needed?? surely not otherwise the cancel_op_(_key) wouldn't - * have failed in the first place - */ - g_hash_table_remove(pending_ops, op_key); - } - - op->rc = EXECRA_OK; - op->op_status = LRM_OP_DONE; - send_direct_ack(from_host, from_sys, rsc, op, rsc->id); + } else if(safe_str_eq(operation, CRMD_ACTION_CANCEL)) { + lrm_op_t* op = NULL; + char *op_key = NULL; + char *meta_key = NULL; + int call = 0; + const char *call_id = NULL; + const char *op_task = NULL; + const char *op_interval = NULL; + + CRM_CHECK(params != NULL, + crm_log_xml_warn(input->xml, "Bad command"); + return); + + + meta_key = crm_meta_name(XML_LRM_ATTR_INTERVAL); + op_interval = crm_element_value(params, meta_key); + crm_free(meta_key); + + meta_key = crm_meta_name(XML_LRM_ATTR_TASK); + op_task = crm_element_value(params, meta_key); + crm_free(meta_key); + + meta_key = crm_meta_name(XML_LRM_ATTR_CALLID); + call_id = crm_element_value(params, meta_key); + crm_free(meta_key); + + CRM_CHECK(op_task != NULL, + crm_log_xml_warn(input->xml, "Bad command"); + return); + CRM_CHECK(op_interval != NULL, + crm_log_xml_warn(input->xml, "Bad command"); + return); + + op = construct_op(input->xml, rsc->id, op_task); + CRM_ASSERT(op != NULL); + op_key = generate_op_key( + rsc->id,op_task,crm_parse_int(op_interval,"0")); + + crm_debug("PE requested op %s (call=%s) be cancelled", + op_key, call_id?call_id:"NA"); + call = crm_parse_int(call_id, "0"); + if(call == 0) { + /* the normal case when the PE cancels a recurring op */ + done = cancel_op_key(rsc, op_key, TRUE); + + } else { + /* the normal case when the PE cancels an orphan op */ + done = cancel_op(rsc, NULL, call, TRUE); + } + + if(done == FALSE) { + crm_debug("Nothing known about operation %d for %s", call, op_key); + delete_op_entry(NULL, rsc->id, op_key, call); + + /* needed?? surely not otherwise the cancel_op_(_key) wouldn't + * have failed in the first place + */ + g_hash_table_remove(pending_ops, op_key); + } + + op->rc = EXECRA_OK; + op->op_status = LRM_OP_DONE; + send_direct_ack(from_host, from_sys, rsc, op, rsc->id); - crm_free(op_key); - free_lrm_op(op); + crm_free(op_key); + free_lrm_op(op); - } else if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { - int rc = HA_OK; + } else if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { + int rc = HA_OK; - CRM_ASSERT(rsc != NULL); - crm_info("Removing resource %s from the LRM", rsc->id); - rc = fsa_lrm_conn->lrm_ops->delete_rsc(fsa_lrm_conn, rsc->id); + CRM_ASSERT(rsc != NULL); + crm_info("Removing resource %s from the LRM", rsc->id); + rc = fsa_lrm_conn->lrm_ops->delete_rsc(fsa_lrm_conn, rsc->id); - if(rc == HA_OK) { - crm_info("Resource '%s' deleted for %s on %s", - rsc->id, from_sys, from_host); - delete_rsc_entry(input, rsc->id, rc); + if(rc == HA_OK) { + crm_info("Resource '%s' deleted for %s on %s", + rsc->id, from_sys, from_host); + delete_rsc_entry(input, rsc->id, rc); #ifdef HAVE_LRM_OP_T_RSC_DELETED - } else if(rc == HA_RSCBUSY) { - struct pending_deletion_op_s *op = NULL; - crm_info("Resource deletion scheduled for %s on %s", from_sys, from_host); + } else if(rc == HA_RSCBUSY) { + struct pending_deletion_op_s *op = NULL; + crm_info("Resource deletion scheduled for %s on %s", from_sys, from_host); - crm_malloc0(op, sizeof(struct pending_deletion_op_s)); - op->rsc = crm_strdup(rsc->id); - op->input = copy_ha_msg_input(input); - g_hash_table_insert( - deletion_ops, crm_element_value_copy(input->msg, XML_ATTR_REFERENCE), op); + crm_malloc0(op, sizeof(struct pending_deletion_op_s)); + op->rsc = crm_strdup(rsc->id); + op->input = copy_ha_msg_input(input); + g_hash_table_insert( + deletion_ops, crm_element_value_copy(input->msg, XML_ATTR_REFERENCE), op); #endif - } else { - crm_err("Deletion of resource '%s' for %s on %s failed: %d", - rsc->id, from_sys, from_host, rc); - delete_rsc_entry(input, rsc->id, rc); - } + } else { + crm_err("Deletion of resource '%s' for %s on %s failed: %d", + rsc->id, from_sys, from_host, rc); + delete_rsc_entry(input, rsc->id, rc); + } - } else if(rsc != NULL) { - do_lrm_rsc_op(rsc, operation, input->xml, input->msg); - } + } else if(rsc != NULL) { + do_lrm_rsc_op(rsc, operation, input->xml, input->msg); + } - lrm_free_rsc(rsc); + 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); - } + } 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); + } } lrm_op_t * construct_op(xmlNode *rsc_op, const char *rsc_id, const char *operation) { - lrm_op_t *op = NULL; - const char *op_delay = NULL; - const char *op_timeout = NULL; - const char *op_interval = NULL; - GHashTable *params = NULL; + lrm_op_t *op = NULL; + const char *op_delay = NULL; + const char *op_timeout = NULL; + const char *op_interval = NULL; + GHashTable *params = NULL; - const char *transition = NULL; - CRM_LOG_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->copyparams = 0; - op->app_name = crm_strdup(CRM_SYSTEM_CRMD); - - if(rsc_op == NULL) { - CRM_LOG_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); + const char *transition = NULL; + CRM_LOG_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->copyparams = 0; + op->app_name = crm_strdup(CRM_SYSTEM_CRMD); + + if(rsc_op == NULL) { + CRM_LOG_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)); + 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; - } + crm_debug_2("Constructed %s op for %s", operation, rsc_id); + return op; + } - params = xml2list(rsc_op); - g_hash_table_remove(params, CRM_META"_op_target_rc"); + params = xml2list(rsc_op); + g_hash_table_remove(params, CRM_META"_op_target_rc"); - op_delay = crm_meta_value(params, XML_OP_ATTR_START_DELAY); - op_timeout = crm_meta_value(params, XML_ATTR_TIMEOUT); - op_interval = crm_meta_value(params, XML_LRM_ATTR_INTERVAL); + op_delay = crm_meta_value(params, XML_OP_ATTR_START_DELAY); + op_timeout = crm_meta_value(params, XML_ATTR_TIMEOUT); + op_interval = crm_meta_value(params, XML_LRM_ATTR_INTERVAL); - op->interval = crm_parse_int(op_interval, "0"); - op->timeout = crm_parse_int(op_timeout, "0"); - op->start_delay = crm_parse_int(op_delay, "0"); + op->interval = crm_parse_int(op_interval, "0"); + op->timeout = crm_parse_int(op_timeout, "0"); + op->start_delay = crm_parse_int(op_delay, "0"); - if(safe_str_neq(operation, RSC_STOP)) { - op->params = params; + if(safe_str_neq(operation, RSC_STOP)) { + op->params = params; - } else { - /* Create a blank parameter list so that we stop the resource - * with the old attributes, not the new ones - */ - const char *version = g_hash_table_lookup(params, XML_ATTR_CRM_VERSION); + } else { + /* Create a blank parameter list so that we stop the resource + * with the old attributes, not the new ones + */ + const char *version = g_hash_table_lookup(params, XML_ATTR_CRM_VERSION); - op->params = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); + op->params = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, g_hash_destroy_str); - if(version) { - g_hash_table_insert(op->params, - crm_strdup(XML_ATTR_CRM_VERSION), - crm_strdup(version)); - } - g_hash_table_destroy(params); params = NULL; + if(version) { + g_hash_table_insert(op->params, + crm_strdup(XML_ATTR_CRM_VERSION), + crm_strdup(version)); } + g_hash_table_destroy(params); params = NULL; + } - /* sanity */ - if(op->interval < 0) { - op->interval = 0; - } - if(op->timeout <= 0) { - op->timeout = op->interval; - } - if(op->start_delay < 0) { - op->start_delay = 0; - } + /* sanity */ + if(op->interval < 0) { + op->interval = 0; + } + if(op->timeout <= 0) { + op->timeout = op->interval; + } + if(op->start_delay < 0) { + op->start_delay = 0; + } - transition = crm_element_value(rsc_op, XML_ATTR_TRANSITION_KEY); - CRM_CHECK(transition != NULL, return op); + 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); + op->user_data = crm_strdup(transition); + op->user_data_len = 1+strlen(op->user_data); - if(op->interval != 0) { - if(safe_str_eq(operation, CRMD_ACTION_START) - || safe_str_eq(operation, CRMD_ACTION_STOP)) { - crm_err("Start and Stop actions cannot have an interval: %d", op->interval); - op->interval = 0; - } + if(op->interval != 0) { + if(safe_str_eq(operation, CRMD_ACTION_START) + || safe_str_eq(operation, CRMD_ACTION_STOP)) { + crm_err("Start and Stop actions cannot have an interval: %d", op->interval); + op->interval = 0; } + } - /* reset the resource's parameters? */ - if(op->interval == 0) { - if(safe_str_eq(CRMD_ACTION_START, operation) - || safe_str_eq(CRMD_ACTION_STATUS, operation)) { - op->copyparams = 1; - } + /* reset the resource's parameters? */ + if(op->interval == 0) { + if(safe_str_eq(CRMD_ACTION_START, operation) + || safe_str_eq(CRMD_ACTION_STATUS, operation)) { + op->copyparams = 1; } + } - crm_debug_2("Constructed %s op for %s: interval=%d", - operation, rsc_id, op->interval); + crm_debug_2("Constructed %s op for %s: interval=%d", + operation, rsc_id, op->interval); - return op; + return op; } void send_direct_ack(const char *to_host, const char *to_sys, lrm_rsc_t *rsc, lrm_op_t* op, const char *rsc_id) { - xmlNode *reply = NULL; - xmlNode *update, *iter; - xmlNode *fragment; + xmlNode *reply = NULL; + xmlNode *update, *iter; + xmlNode *fragment; - CRM_CHECK(op != NULL, return); - if(op->rsc_id == NULL) { - CRM_LOG_ASSERT(rsc_id != NULL); - op->rsc_id = crm_strdup(rsc_id); - } - if(to_sys == NULL) { - to_sys = CRM_SYSTEM_TENGINE; - } - update = create_node_state( - fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); + CRM_CHECK(op != NULL, return); + if(op->rsc_id == NULL) { + CRM_LOG_ASSERT(rsc_id != NULL); + op->rsc_id = crm_strdup(rsc_id); + } + if(to_sys == NULL) { + to_sys = CRM_SYSTEM_TENGINE; + } + update = create_node_state( + fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); - iter = create_xml_node(update, XML_CIB_TAG_LRM); - crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); - iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); - iter = create_xml_node(iter, XML_LRM_TAG_RESOURCE); + iter = create_xml_node(update, XML_CIB_TAG_LRM); + crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); + 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); + crm_xml_add(iter, XML_ATTR_ID, op->rsc_id); - build_operation_update(iter, rsc, op, __FUNCTION__, 0, LOG_DEBUG); - fragment = create_cib_fragment(update, XML_CIB_TAG_STATUS); + build_operation_update(iter, rsc, op, __FUNCTION__, 0, LOG_DEBUG); + 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); + reply = create_request(CRM_OP_INVOKE_LRM, fragment, to_host, + to_sys, CRM_SYSTEM_LRMD, NULL); - crm_log_xml_debug_2(update, "ACK Update"); + crm_log_xml_debug_2(update, "ACK Update"); - crm_info("ACK'ing resource op %s_%s_%d from %s: %s", - op->rsc_id, op->op_type, op->interval, op->user_data, - crm_element_value(reply, XML_ATTR_REFERENCE)); + crm_info("ACK'ing resource op %s_%s_%d from %s: %s", + op->rsc_id, op->op_type, op->interval, op->user_data, + crm_element_value(reply, XML_ATTR_REFERENCE)); - if(relay_message(reply, TRUE) == FALSE) { - crm_log_xml(LOG_ERR, "Unable to route reply", reply); - } + if(relay_message(reply, TRUE) == FALSE) { + crm_log_xml(LOG_ERR, "Unable to route reply", reply); + } - free_xml(fragment); - free_xml(update); - free_xml(reply); + free_xml(fragment); + free_xml(update); + free_xml(reply); } static gboolean stop_recurring_action_by_rsc(gpointer key, gpointer value, gpointer user_data) { - lrm_rsc_t *rsc = user_data; - struct recurring_op_s *op = (struct recurring_op_s*)value; + lrm_rsc_t *rsc = user_data; + struct recurring_op_s *op = (struct recurring_op_s*)value; - if(op->interval != 0 && safe_str_eq(op->rsc_id, rsc->id)) { - if (cancel_op(rsc, key, op->call_id, FALSE) == FALSE) { - return TRUE; - } + if(op->interval != 0 && safe_str_eq(op->rsc_id, rsc->id)) { + if (cancel_op(rsc, key, op->call_id, FALSE) == FALSE) { + return TRUE; } + } - return FALSE; + return FALSE; } void do_lrm_rsc_op(lrm_rsc_t *rsc, const char *operation, xmlNode *msg, xmlNode *request) { - int call_id = 0; - char *op_id = NULL; - lrm_op_t* op = NULL; + int call_id = 0; + char *op_id = NULL; + lrm_op_t* op = NULL; - fsa_data_t *msg_data = NULL; - const char *transition = NULL; + fsa_data_t *msg_data = NULL; + const char *transition = NULL; - CRM_CHECK(rsc != NULL, return); + CRM_CHECK(rsc != NULL, return); - if(msg != NULL) { - transition = crm_element_value(msg, XML_ATTR_TRANSITION_KEY); - if(transition == NULL) { - crm_log_xml_err(msg, "Missing transition number"); - } + if(msg != NULL) { + transition = crm_element_value(msg, XML_ATTR_TRANSITION_KEY); + if(transition == NULL) { + crm_log_xml_err(msg, "Missing transition number"); } + } - op = construct_op(msg, rsc->id, operation); + op = construct_op(msg, rsc->id, operation); - /* stop the monitor before stopping the resource */ - if(crm_str_eq(operation, CRMD_ACTION_STOP, TRUE) - || crm_str_eq(operation, CRMD_ACTION_DEMOTE, TRUE) - || crm_str_eq(operation, CRMD_ACTION_PROMOTE, TRUE) - || crm_str_eq(operation, CRMD_ACTION_MIGRATE, TRUE)) { - g_hash_table_foreach_remove(pending_ops, stop_recurring_action_by_rsc, rsc); - } + /* stop the monitor before stopping the resource */ + if(crm_str_eq(operation, CRMD_ACTION_STOP, TRUE) + || crm_str_eq(operation, CRMD_ACTION_DEMOTE, TRUE) + || crm_str_eq(operation, CRMD_ACTION_PROMOTE, TRUE) + || crm_str_eq(operation, CRMD_ACTION_MIGRATE, TRUE)) { + g_hash_table_foreach_remove(pending_ops, stop_recurring_action_by_rsc, rsc); + } - /* now do the op */ - crm_info("Performing key=%s op=%s_%s_%d )", - transition, rsc->id, operation, op->interval); - - if(fsa_state != S_NOT_DC - && fsa_state != S_POLICY_ENGINE - && fsa_state != S_TRANSITION_ENGINE) { - if(safe_str_neq(operation, "fail") - && safe_str_neq(operation, CRMD_ACTION_STOP)) { - crm_info("Discarding attempt to perform action %s on %s" - " in state %s", operation, rsc->id, - fsa_state2string(fsa_state)); - op->rc = 99; - op->op_status = LRM_OP_ERROR; - send_direct_ack(NULL, NULL, rsc, op, rsc->id); - free_lrm_op(op); - crm_free(op_id); - return; - } + /* now do the op */ + crm_info("Performing key=%s op=%s_%s_%d )", + transition, rsc->id, operation, op->interval); + + if(fsa_state != S_NOT_DC + && fsa_state != S_POLICY_ENGINE + && fsa_state != S_TRANSITION_ENGINE) { + if(safe_str_neq(operation, "fail") + && safe_str_neq(operation, CRMD_ACTION_STOP)) { + crm_info("Discarding attempt to perform action %s on %s" + " in state %s", operation, rsc->id, + fsa_state2string(fsa_state)); + op->rc = 99; + op->op_status = LRM_OP_ERROR; + send_direct_ack(NULL, NULL, rsc, op, rsc->id); + free_lrm_op(op); + crm_free(op_id); + return; } + } - op_id = generate_op_key(rsc->id, op->op_type, op->interval); + op_id = generate_op_key(rsc->id, op->op_type, op->interval); - if(op->interval > 0) { - /* cancel it so we can then restart it without conflict */ - cancel_op_key(rsc, op_id, FALSE); - op->target_rc = CHANGED; + if(op->interval > 0) { + /* cancel it so we can then restart it without conflict */ + cancel_op_key(rsc, op_id, FALSE); + op->target_rc = CHANGED; - } else { - op->target_rc = EVERYTIME; - } + } 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); + 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, rsc->id, call_id); - register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); + if(call_id <= 0) { + crm_err("Operation %s on %s failed: %d", + operation, rsc->id, call_id); + register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); - } else { - /* record all operations so we can wait - * for them to complete during shutdown - */ - char *call_id_s = make_stop_id(rsc->id, call_id); - struct recurring_op_s *pending = NULL; - crm_malloc0(pending, sizeof(struct recurring_op_s)); - crm_debug_2("Recording pending op: %d - %s %s", call_id, op_id, call_id_s); + } else { + /* record all operations so we can wait + * for them to complete during shutdown + */ + char *call_id_s = make_stop_id(rsc->id, call_id); + struct recurring_op_s *pending = NULL; + crm_malloc0(pending, sizeof(struct recurring_op_s)); + crm_debug_2("Recording pending op: %d - %s %s", call_id, op_id, call_id_s); - pending->call_id = call_id; - pending->interval = op->interval; - pending->op_key = crm_strdup(op_id); - pending->rsc_id = crm_strdup(rsc->id); - g_hash_table_replace(pending_ops, call_id_s, pending); - - if(op->interval > 0 && op->start_delay > START_DELAY_THRESHOLD) { - char *uuid = NULL; - int dummy = 0, target_rc = 0; - crm_info("Faking confirmation of %s: execution postponed for over 5 minutes", op_id); + pending->call_id = call_id; + pending->interval = op->interval; + pending->op_key = crm_strdup(op_id); + pending->rsc_id = crm_strdup(rsc->id); + g_hash_table_replace(pending_ops, call_id_s, pending); + + if(op->interval > 0 && op->start_delay > START_DELAY_THRESHOLD) { + char *uuid = NULL; + int dummy = 0, target_rc = 0; + crm_info("Faking confirmation of %s: execution postponed for over 5 minutes", op_id); - decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &target_rc); - crm_free(uuid); + decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &target_rc); + crm_free(uuid); - op->rc = target_rc; - op->op_status = LRM_OP_DONE; - send_direct_ack(NULL, NULL, rsc, op, rsc->id); - } + op->rc = target_rc; + op->op_status = LRM_OP_DONE; + send_direct_ack(NULL, NULL, rsc, op, rsc->id); } + } - crm_free(op_id); - free_lrm_op(op); - return; + crm_free(op_id); + free_lrm_op(op); + return; } void free_deletion_op(gpointer value) { - struct pending_deletion_op_s *op = value; - crm_free(op->rsc); - delete_ha_msg_input(op->input); - crm_free(op); + struct pending_deletion_op_s *op = value; + crm_free(op->rsc); + delete_ha_msg_input(op->input); + crm_free(op); } void free_recurring_op(gpointer value) { - struct recurring_op_s *op = (struct recurring_op_s*)value; - crm_free(op->rsc_id); - crm_free(op->op_key); - crm_free(op); + struct recurring_op_s *op = (struct recurring_op_s*)value; + crm_free(op->rsc_id); + crm_free(op->op_key); + 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)); + 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; + lrm_op_t *op_copy = NULL; - CRM_CHECK(op != NULL, return NULL); - CRM_CHECK(op->rsc_id != NULL, return NULL); + CRM_CHECK(op != NULL, return NULL); + CRM_CHECK(op->rsc_id != NULL, return NULL); - crm_malloc0(op_copy, sizeof(lrm_op_t)); + 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); + 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; + 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); - } + /* 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); - } + /* 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; + return op_copy; } lrm_rsc_t * copy_lrm_rsc(const lrm_rsc_t *rsc) { - lrm_rsc_t *rsc_copy = NULL; + lrm_rsc_t *rsc_copy = NULL; - if(rsc == NULL) { - return NULL; - } + if(rsc == NULL) { + return NULL; + } - crm_malloc0(rsc_copy, sizeof(lrm_rsc_t)); + 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; + 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); - } + 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; + rsc_copy->params = NULL; + rsc_copy->ops = NULL; - return rsc_copy; + return rsc_copy; } void cib_rsc_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { switch(rc) { case cib_ok: case cib_diff_failed: case cib_diff_resync: crm_debug_2("Resource update %d complete: rc=%d", call_id, rc); break; default: crm_warn("Resource update %d failed: (rc=%d) %s", call_id, rc, cib_error2string(rc)); } } int do_update_resource(lrm_op_t* op) { /* - - - - - + + + + + */ - int rc = cib_ok; - lrm_rsc_t *rsc = NULL; - xmlNode *update, *iter = NULL; - int call_opt = cib_quorum_override; + int rc = cib_ok; + lrm_rsc_t *rsc = NULL; + xmlNode *update, *iter = NULL; + int call_opt = cib_quorum_override; - CRM_CHECK(op != NULL, return 0); + CRM_CHECK(op != NULL, return 0); - if(fsa_state == S_ELECTION || fsa_state == S_PENDING) { - crm_info("Sending update to local CIB in state: %s", fsa_state2string(fsa_state)); - call_opt |= cib_scope_local; - } + if(fsa_state == S_ELECTION || fsa_state == S_PENDING) { + crm_info("Sending update to local CIB in state: %s", fsa_state2string(fsa_state)); + call_opt |= cib_scope_local; + } - iter = create_xml_node(iter, XML_CIB_TAG_STATUS); update = iter; - iter = create_xml_node(iter, XML_CIB_TAG_STATE); + iter = create_xml_node(iter, XML_CIB_TAG_STATUS); update = iter; + iter = create_xml_node(iter, XML_CIB_TAG_STATE); - set_uuid(iter, XML_ATTR_UUID, fsa_our_uname); - crm_xml_add(iter, XML_ATTR_UNAME, fsa_our_uname); - crm_xml_add(iter, XML_ATTR_ORIGIN, __FUNCTION__); + set_uuid(iter, XML_ATTR_UUID, fsa_our_uname); + crm_xml_add(iter, XML_ATTR_UNAME, fsa_our_uname); + crm_xml_add(iter, XML_ATTR_ORIGIN, __FUNCTION__); - iter = create_xml_node(iter, XML_CIB_TAG_LRM); - crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); + iter = create_xml_node(iter, XML_CIB_TAG_LRM); + crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); - 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); + 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); - rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, op->rsc_id); - build_operation_update(iter, rsc, op, __FUNCTION__, 0, LOG_DEBUG); + rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, op->rsc_id); + build_operation_update(iter, rsc, op, __FUNCTION__, 0, LOG_DEBUG); - if(rsc) { - 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); - - CRM_CHECK(rsc->type != NULL, - crm_err("Resource %s has no value for type", op->rsc_id)); - CRM_CHECK(rsc->class != NULL, - crm_err("Resource %s has no value for class", op->rsc_id)); - lrm_free_rsc(rsc); + if(rsc) { + 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); - } else { - crm_warn("Resource %s no longer exists in the lrmd", op->rsc_id); - goto cleanup; - } + CRM_CHECK(rsc->type != NULL, + crm_err("Resource %s has no value for type", op->rsc_id)); + CRM_CHECK(rsc->class != NULL, + crm_err("Resource %s has no value for class", op->rsc_id)); + lrm_free_rsc(rsc); - /* 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 - */ - fsa_cib_update(XML_CIB_TAG_STATUS, update, call_opt, rc); + } else { + crm_warn("Resource %s no longer exists in the lrmd", op->rsc_id); + goto cleanup; + } + + /* 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 + */ + fsa_cib_update(XML_CIB_TAG_STATUS, update, call_opt, rc); - /* the return code is a call number, not an error code */ - crm_debug_2("Sent resource state update message: %d", rc); - fsa_cib_conn->cmds->register_callback( - fsa_cib_conn, rc, 60, FALSE, NULL, "cib_rsc_callback", cib_rsc_callback); + /* the return code is a call number, not an error code */ + crm_debug_2("Sent resource state update message: %d", rc); + fsa_cib_conn->cmds->register_callback( + fsa_cib_conn, rc, 60, FALSE, NULL, "cib_rsc_callback", cib_rsc_callback); cleanup: - free_xml(update); - return rc; + free_xml(update); + return rc; } void 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) { CRM_CHECK(FALSE, return); } gboolean process_lrm_event(lrm_op_t *op) { - char *op_id = NULL; - char *op_key = NULL; + char *op_id = NULL; + char *op_key = NULL; - int update_id = 0; - int log_level = LOG_ERR; - gboolean removed = FALSE; + int update_id = 0; + int log_level = LOG_ERR; + gboolean removed = FALSE; - struct recurring_op_s *pending = NULL; - CRM_CHECK(op != NULL, return FALSE); - CRM_CHECK(op->rsc_id != NULL, return FALSE); + struct recurring_op_s *pending = NULL; + CRM_CHECK(op != NULL, return FALSE); + CRM_CHECK(op->rsc_id != NULL, return FALSE); - op_key = generate_op_key(op->rsc_id, op->op_type, op->interval); + op_key = generate_op_key(op->rsc_id, op->op_type, op->interval); - switch(op->op_status) { - case LRM_OP_ERROR: - case LRM_OP_PENDING: - case LRM_OP_NOTSUPPORTED: - break; - case LRM_OP_CANCELLED: - log_level = LOG_INFO; - break; - case LRM_OP_DONE: - log_level = LOG_INFO; - break; - case LRM_OP_TIMEOUT: - log_level = LOG_DEBUG_3; - crm_err("LRM operation %s (%d) %s (timeout=%dms)", - op_key, op->call_id, - op_status2text(op->op_status), op->timeout); - break; - default: - crm_err("Mapping unknown status (%d) to ERROR", - op->op_status); - op->op_status = LRM_OP_ERROR; - } + switch(op->op_status) { + case LRM_OP_ERROR: + case LRM_OP_PENDING: + case LRM_OP_NOTSUPPORTED: + break; + case LRM_OP_CANCELLED: + log_level = LOG_INFO; + break; + case LRM_OP_DONE: + log_level = LOG_INFO; + break; + case LRM_OP_TIMEOUT: + log_level = LOG_DEBUG_3; + crm_err("LRM operation %s (%d) %s (timeout=%dms)", + op_key, op->call_id, + op_status2text(op->op_status), op->timeout); + break; + default: + crm_err("Mapping unknown status (%d) to ERROR", + op->op_status); + op->op_status = LRM_OP_ERROR; + } - if(op->op_status == LRM_OP_ERROR - && (op->rc == EXECRA_RUNNING_MASTER || op->rc == EXECRA_NOT_RUNNING)) { - /* Leave it up to the TE/PE to decide if this is an error */ - op->op_status = LRM_OP_DONE; - log_level = LOG_INFO; - } + if(op->op_status == LRM_OP_ERROR + && (op->rc == EXECRA_RUNNING_MASTER || op->rc == EXECRA_NOT_RUNNING)) { + /* Leave it up to the TE/PE to decide if this is an error */ + op->op_status = LRM_OP_DONE; + log_level = LOG_INFO; + } - op_id = make_stop_id(op->rsc_id, op->call_id); - pending = g_hash_table_lookup(pending_ops, op_id); + op_id = make_stop_id(op->rsc_id, op->call_id); + pending = g_hash_table_lookup(pending_ops, op_id); - if(op->op_status != LRM_OP_CANCELLED) { - update_id = do_update_resource(op); - if(op->interval != 0) { - goto out; - } + if(op->op_status != LRM_OP_CANCELLED) { + update_id = do_update_resource(op); + if(op->interval != 0) { + goto out; + } - } else if(op->interval == 0) { - /* This will occur when "crm resource cleanup" is called while actions are in-flight */ - crm_err("Op %s (call=%d): Cancelled", op_key, op->call_id); - send_direct_ack(NULL, NULL, NULL, op, op->rsc_id); + } else if(op->interval == 0) { + /* This will occur when "crm resource cleanup" is called while actions are in-flight */ + crm_err("Op %s (call=%d): Cancelled", op_key, op->call_id); + send_direct_ack(NULL, NULL, NULL, op, op->rsc_id); - } else if(pending == NULL) { - crm_err("Op %s (call=%d): No 'pending' entry", - op_key, op->call_id); + } else if(pending == NULL) { + crm_err("Op %s (call=%d): No 'pending' entry", + op_key, op->call_id); - } else if(op->user_data == NULL) { - crm_err("Op %s (call=%d): No user data", op_key, op->call_id); + } else if(op->user_data == NULL) { + crm_err("Op %s (call=%d): No user data", op_key, op->call_id); - } else if(pending->remove) { - delete_op_entry(op, op->rsc_id, op_key, op->call_id); + } else if(pending->remove) { + delete_op_entry(op, op->rsc_id, op_key, op->call_id); - } else { - /* Before a stop is called, no need to direct ack */ - crm_debug_2("Op %s (call=%d): no delete event required", op_key, op->call_id); - } + } else { + /* Before a stop is called, no need to direct ack */ + crm_debug_2("Op %s (call=%d): no delete event required", op_key, op->call_id); + } - if(g_hash_table_remove(pending_ops, op_id)) { - removed = TRUE; - crm_debug_2("Op %s (call=%d, stop-id=%s): Confirmed", op_key, op->call_id, op_id); - } + if(g_hash_table_remove(pending_ops, op_id)) { + removed = TRUE; + crm_debug_2("Op %s (call=%d, stop-id=%s): Confirmed", op_key, op->call_id, op_id); + } out: - if(op->op_status == LRM_OP_DONE) { - do_crm_log(log_level, + if(op->op_status == LRM_OP_DONE) { + do_crm_log(log_level, "LRM operation %s (call=%d, rc=%d, cib-update=%d, confirmed=%s) %s", op_key, op->call_id, op->rc, update_id, removed?"true":"false", execra_code2string(op->rc)); - } else { - do_crm_log(log_level, + } else { + do_crm_log(log_level, "LRM operation %s (call=%d, status=%d, cib-update=%d, confirmed=%s) %s", op_key, op->call_id, op->op_status, update_id, removed?"true":"false", op_status2text(op->op_status)); - } + } - if(op->rc != 0 && op->output != NULL) { - crm_info("Result: %s", op->output); - } else if(op->output != NULL) { - crm_debug("Result: %s", op->output); - } + if(op->rc != 0 && op->output != NULL) { + crm_info("Result: %s", op->output); + } else if(op->output != NULL) { + crm_debug("Result: %s", op->output); + } #ifdef HAVE_LRM_OP_T_RSC_DELETED - if(op->rsc_deleted) { - crm_info("Deletion of resource '%s' complete after %s", op->rsc_id, op_key); - delete_rsc_entry(NULL, op->rsc_id, HA_OK); - } + if(op->rsc_deleted) { + crm_info("Deletion of resource '%s' complete after %s", op->rsc_id, op_key); + delete_rsc_entry(NULL, op->rsc_id, HA_OK); + } #endif - /* If a shutdown was escalated while operations were pending, - * then the FSA will be stalled right now... allow it to continue - */ - mainloop_set_trigger(fsa_source); + /* If a shutdown was escalated while operations were pending, + * then the FSA will be stalled right now... allow it to continue + */ + mainloop_set_trigger(fsa_source); - crm_free(op_key); - crm_free(op_id); - return TRUE; + crm_free(op_key); + crm_free(op_id); + return TRUE; } 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; + 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; } diff --git a/crmd/messages.c b/crmd/messages.c index 0305db3d1a..84d1c414b2 100644 --- a/crmd/messages.c +++ b/crmd/messages.c @@ -1,1022 +1,1024 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GListPtr fsa_message_queue = NULL; extern void crm_shutdown(int nsig); void handle_response(xmlNode *stored_msg); enum crmd_fsa_input handle_request(xmlNode *stored_msg); enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg); gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data); #ifdef MSG_LOG # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x); \ - crm_log_xml(LOG_MSG, "router.log", msg); + crm_log_xml(LOG_MSG, "router.log", msg); #else # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x) #endif /* debug only, can wrap all it likes */ int last_data_id = 0; void register_fsa_error_adv( - enum crmd_fsa_cause cause, enum crmd_fsa_input input, - fsa_data_t *cur_data, void *new_data, const char *raised_from) + enum crmd_fsa_cause cause, enum crmd_fsa_input input, + fsa_data_t *cur_data, void *new_data, const char *raised_from) { - /* save the current actions if any */ - if(fsa_actions != A_NOTHING) { - register_fsa_input_adv( - cur_data?cur_data->fsa_cause:C_FSA_INTERNAL, - I_NULL, cur_data?cur_data->data:NULL, - fsa_actions, TRUE, __FUNCTION__); - } + /* save the current actions if any */ + if(fsa_actions != A_NOTHING) { + register_fsa_input_adv( + cur_data?cur_data->fsa_cause:C_FSA_INTERNAL, + I_NULL, cur_data?cur_data->data:NULL, + fsa_actions, TRUE, __FUNCTION__); + } - /* reset the action list */ - fsa_actions = A_NOTHING; + /* reset the action list */ + fsa_actions = A_NOTHING; - /* register the error */ - register_fsa_input_adv( - cause, input, new_data, A_NOTHING, TRUE, raised_from); + /* register the error */ + register_fsa_input_adv( + cause, input, new_data, A_NOTHING, TRUE, raised_from); } int register_fsa_input_adv( - enum crmd_fsa_cause cause, enum crmd_fsa_input input, - void *data, long long with_actions, - gboolean prepend, const char *raised_from) + enum crmd_fsa_cause cause, enum crmd_fsa_input input, + void *data, long long with_actions, + gboolean prepend, const char *raised_from) { - unsigned old_len = g_list_length(fsa_message_queue); - fsa_data_t *fsa_data = NULL; - - last_data_id++; - CRM_CHECK(raised_from != NULL, raised_from = ""); - - crm_debug_2("%s %s FSA input %d (%s) (cause=%s) %s data", - raised_from, prepend?"prepended":"appended",last_data_id, fsa_input2string(input), - fsa_cause2string(cause), data?"with":"without"); - - if(input == I_WAIT_FOR_EVENT) { - do_fsa_stall = TRUE; - crm_debug("Stalling the FSA pending further input: cause=%s", - fsa_cause2string(cause)); - if(old_len > 0) { - crm_warn("%s stalled the FSA with pending inputs", - raised_from); - fsa_dump_queue(LOG_DEBUG); - } - if(data == NULL) { - set_bit_inplace(fsa_actions, with_actions); - with_actions = A_NOTHING; - return 0; - } - crm_err("%s stalled the FSA with data - this may be broken", - raised_from); - } + unsigned old_len = g_list_length(fsa_message_queue); + fsa_data_t *fsa_data = NULL; - if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){ - /* no point doing anything */ - crm_err("Cannot add entry to queue: no input and no action"); - return 0; + last_data_id++; + CRM_CHECK(raised_from != NULL, raised_from = ""); + + crm_debug_2("%s %s FSA input %d (%s) (cause=%s) %s data", + raised_from, prepend?"prepended":"appended",last_data_id, fsa_input2string(input), + fsa_cause2string(cause), data?"with":"without"); + + if(input == I_WAIT_FOR_EVENT) { + do_fsa_stall = TRUE; + crm_debug("Stalling the FSA pending further input: cause=%s", + fsa_cause2string(cause)); + if(old_len > 0) { + crm_warn("%s stalled the FSA with pending inputs", + raised_from); + fsa_dump_queue(LOG_DEBUG); } - - crm_malloc0(fsa_data, sizeof(fsa_data_t)); - fsa_data->id = last_data_id; - fsa_data->fsa_input = input; - fsa_data->fsa_cause = cause; - fsa_data->origin = raised_from; - fsa_data->data = NULL; - fsa_data->data_type = fsa_dt_none; - fsa_data->actions = with_actions; - - if(with_actions != A_NOTHING) { - crm_debug_3("Adding actions %.16llx to input", with_actions); + if(data == NULL) { + set_bit_inplace(fsa_actions, with_actions); + with_actions = A_NOTHING; + return 0; } + crm_err("%s stalled the FSA with data - this may be broken", + raised_from); + } + + if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){ + /* no point doing anything */ + crm_err("Cannot add entry to queue: no input and no action"); + return 0; + } + + crm_malloc0(fsa_data, sizeof(fsa_data_t)); + fsa_data->id = last_data_id; + fsa_data->fsa_input = input; + fsa_data->fsa_cause = cause; + fsa_data->origin = raised_from; + fsa_data->data = NULL; + fsa_data->data_type = fsa_dt_none; + fsa_data->actions = with_actions; + + if(with_actions != A_NOTHING) { + crm_debug_3("Adding actions %.16llx to input", with_actions); + } - if(data != NULL) { - switch(cause) { - case C_FSA_INTERNAL: - case C_CRMD_STATUS_CALLBACK: - case C_IPC_MESSAGE: - case C_HA_MESSAGE: - crm_debug_3("Copying %s data from %s as a HA msg", - fsa_cause2string(cause), - raised_from); - CRM_CHECK(((ha_msg_input_t*)data)->msg != NULL, - crm_err("Bogus data from %s", raised_from)); - fsa_data->data = copy_ha_msg_input(data); - fsa_data->data_type = fsa_dt_ha_msg; - break; + if(data != NULL) { + switch(cause) { + case C_FSA_INTERNAL: + case C_CRMD_STATUS_CALLBACK: + case C_IPC_MESSAGE: + case C_HA_MESSAGE: + crm_debug_3("Copying %s data from %s as a HA msg", + fsa_cause2string(cause), + raised_from); + CRM_CHECK(((ha_msg_input_t*)data)->msg != NULL, + crm_err("Bogus data from %s", raised_from)); + fsa_data->data = copy_ha_msg_input(data); + fsa_data->data_type = fsa_dt_ha_msg; + break; - case C_LRM_OP_CALLBACK: - crm_debug_3("Copying %s data from %s as lrm_op_t", - fsa_cause2string(cause), - raised_from); - fsa_data->data = copy_lrm_op((lrm_op_t*)data); - fsa_data->data_type = fsa_dt_lrm; - break; + case C_LRM_OP_CALLBACK: + crm_debug_3("Copying %s data from %s as lrm_op_t", + fsa_cause2string(cause), + raised_from); + fsa_data->data = copy_lrm_op((lrm_op_t*)data); + fsa_data->data_type = fsa_dt_lrm; + break; - case C_CCM_CALLBACK: - case C_SUBSYSTEM_CONNECT: - case C_LRM_MONITOR_CALLBACK: - case C_TIMER_POPPED: - case C_SHUTDOWN: - case C_HEARTBEAT_FAILED: - case C_HA_DISCONNECT: - case C_ILLEGAL: - case C_UNKNOWN: - case C_STARTUP: - crm_err("Copying %s data (from %s)" - " not yet implemented", - fsa_cause2string(cause), raised_from); - exit(1); - break; - } - crm_debug_4("%s data copied", - fsa_cause2string(fsa_data->fsa_cause)); + case C_CCM_CALLBACK: + case C_SUBSYSTEM_CONNECT: + case C_LRM_MONITOR_CALLBACK: + case C_TIMER_POPPED: + case C_SHUTDOWN: + case C_HEARTBEAT_FAILED: + case C_HA_DISCONNECT: + case C_ILLEGAL: + case C_UNKNOWN: + case C_STARTUP: + crm_err("Copying %s data (from %s)" + " not yet implemented", + fsa_cause2string(cause), raised_from); + exit(1); + break; } + crm_debug_4("%s data copied", + fsa_cause2string(fsa_data->fsa_cause)); + } - /* make sure to free it properly later */ - if(prepend) { - crm_debug_2("Prepending input"); - fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data); - } else { - fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); - } + /* make sure to free it properly later */ + if(prepend) { + crm_debug_2("Prepending input"); + fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data); + } else { + fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); + } - crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue)); + crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue)); - fsa_dump_queue(LOG_DEBUG_2); + fsa_dump_queue(LOG_DEBUG_2); - if(old_len == g_list_length(fsa_message_queue)){ - crm_err("Couldnt add message to the queue"); - } + if(old_len == g_list_length(fsa_message_queue)){ + crm_err("Couldnt add message to the queue"); + } - if(fsa_source) { - crm_debug_3("Triggering FSA: %s", __FUNCTION__); - mainloop_set_trigger(fsa_source); - } - return last_data_id; + if(fsa_source) { + crm_debug_3("Triggering FSA: %s", __FUNCTION__); + mainloop_set_trigger(fsa_source); + } + return last_data_id; } void fsa_dump_queue(int log_level) { - if(log_level < (int)crm_log_level) { - return; - } - slist_iter( - data, fsa_data_t, fsa_message_queue, lpc, - do_crm_log(log_level, - "queue[%d(%d)]: input %s raised by %s()\t(cause=%s)", - lpc, data->id, fsa_input2string(data->fsa_input), - data->origin, fsa_cause2string(data->fsa_cause)); - ); + int offset = 0; + GListPtr lpc = NULL; + if(log_level < (int)crm_log_level) { + return; + } + for(lpc = fsa_message_queue; lpc != NULL; lpc = lpc->next) { + fsa_data_t *data = (fsa_data_t*)lpc->data; + do_crm_log(log_level, + "queue[%d(%d)]: input %s raised by %s()\t(cause=%s)", + offset++, data->id, fsa_input2string(data->fsa_input), + data->origin, fsa_cause2string(data->fsa_cause)); + } } ha_msg_input_t * copy_ha_msg_input(ha_msg_input_t *orig) { ha_msg_input_t *copy = NULL; xmlNodePtr data = NULL; if(orig != NULL) { crm_debug_4("Copy msg"); data = copy_xml(orig->msg); } else { crm_debug_3("No message to copy"); } copy = new_ha_msg_input(data); if(orig && orig->msg != NULL) { CRM_CHECK(copy->msg != NULL, crm_err("copy failed")); } return copy; } void delete_fsa_input(fsa_data_t *fsa_data) { - lrm_op_t *op = NULL; - xmlNode *foo = NULL; + lrm_op_t *op = NULL; + xmlNode *foo = NULL; - if(fsa_data == NULL) { - return; - } - crm_debug_4("About to free %s data", - fsa_cause2string(fsa_data->fsa_cause)); - - if(fsa_data->data != NULL) { - switch(fsa_data->data_type) { - case fsa_dt_ha_msg: - delete_ha_msg_input(fsa_data->data); - break; + if(fsa_data == NULL) { + return; + } + crm_debug_4("About to free %s data", + fsa_cause2string(fsa_data->fsa_cause)); + + if(fsa_data->data != NULL) { + switch(fsa_data->data_type) { + case fsa_dt_ha_msg: + delete_ha_msg_input(fsa_data->data); + break; - case fsa_dt_xml: - foo = fsa_data->data; - free_xml(foo); - break; + case fsa_dt_xml: + foo = fsa_data->data; + free_xml(foo); + break; - case fsa_dt_lrm: - op = (lrm_op_t*)fsa_data->data; - free_lrm_op(op); - break; + case fsa_dt_lrm: + op = (lrm_op_t*)fsa_data->data; + free_lrm_op(op); + break; - case fsa_dt_none: - if(fsa_data->data != NULL) { - crm_err("Dont know how to free %s data from %s", - fsa_cause2string(fsa_data->fsa_cause), - fsa_data->origin); - exit(1); - } - break; + case fsa_dt_none: + if(fsa_data->data != NULL) { + crm_err("Dont know how to free %s data from %s", + fsa_cause2string(fsa_data->fsa_cause), + fsa_data->origin); + exit(1); } - crm_debug_4("%s data freed", - fsa_cause2string(fsa_data->fsa_cause)); + break; } + crm_debug_4("%s data freed", + fsa_cause2string(fsa_data->fsa_cause)); + } - crm_free(fsa_data); + crm_free(fsa_data); } /* returns the next message */ fsa_data_t * get_message(void) { - fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); - fsa_message_queue = g_list_remove(fsa_message_queue, message); - crm_debug_2("Processing input %d", message->id); - return message; + fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); + fsa_message_queue = g_list_remove(fsa_message_queue, message); + crm_debug_2("Processing input %d", message->id); + return message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { - return (g_list_length(fsa_message_queue) > 0); + return (g_list_length(fsa_message_queue) > 0); } void * fsa_typed_data_adv( - fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller) + fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller) { - void *ret_val = NULL; - if(fsa_data == NULL) { - do_crm_log(LOG_ERR, "%s: No FSA data available", caller); + void *ret_val = NULL; + if(fsa_data == NULL) { + do_crm_log(LOG_ERR, "%s: No FSA data available", caller); - } else if(fsa_data->data == NULL) { - do_crm_log(LOG_ERR, "%s: No message data available. Origin: %s", - caller, fsa_data->origin); - - } else if(fsa_data->data_type != a_type) { - do_crm_log(LOG_CRIT, - "%s: Message data was the wrong type! %d vs. requested=%d." - " Origin: %s", caller, - fsa_data->data_type, a_type, fsa_data->origin); - CRM_ASSERT(fsa_data->data_type == a_type); - } else { - ret_val = fsa_data->data; - } + } else if(fsa_data->data == NULL) { + do_crm_log(LOG_ERR, "%s: No message data available. Origin: %s", + caller, fsa_data->origin); + + } else if(fsa_data->data_type != a_type) { + do_crm_log(LOG_CRIT, + "%s: Message data was the wrong type! %d vs. requested=%d." + " Origin: %s", caller, + fsa_data->data_type, a_type, fsa_data->origin); + CRM_ASSERT(fsa_data->data_type == a_type); + } else { + ret_val = fsa_data->data; + } - return ret_val; + return ret_val; } /* A_MSG_ROUTE */ void do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { - ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); - route_message(msg_data->fsa_cause, input->msg); + ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); + route_message(msg_data->fsa_cause, input->msg); } void route_message(enum crmd_fsa_cause cause, xmlNode *input) { - ha_msg_input_t fsa_input; - enum crmd_fsa_input result = I_NULL; + ha_msg_input_t fsa_input; + enum crmd_fsa_input result = I_NULL; - fsa_input.msg = input; - CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return); + fsa_input.msg = input; + CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return); - /* try passing the buck first */ - if(relay_message(input, cause==C_IPC_MESSAGE)) { - return; - } + /* try passing the buck first */ + if(relay_message(input, cause==C_IPC_MESSAGE)) { + return; + } - /* handle locally */ - result = handle_message(input); - - /* done or process later? */ - switch(result) { - case I_NULL: - case I_CIB_OP: - case I_ROUTER: - case I_NODE_JOIN: - case I_JOIN_REQUEST: - case I_JOIN_RESULT: - break; - default: - /* Defering local processing of message */ - register_fsa_input_later(cause, result, &fsa_input); - return; - } + /* handle locally */ + result = handle_message(input); + + /* done or process later? */ + switch(result) { + case I_NULL: + case I_CIB_OP: + case I_ROUTER: + case I_NODE_JOIN: + case I_JOIN_REQUEST: + case I_JOIN_RESULT: + break; + default: + /* Defering local processing of message */ + register_fsa_input_later(cause, result, &fsa_input); + return; + } - if(result != I_NULL) { - /* add to the front of the queue */ - register_fsa_input(cause, result, &fsa_input); - } + if(result != I_NULL) { + /* add to the front of the queue */ + register_fsa_input(cause, result, &fsa_input); + } } gboolean relay_message(xmlNode *msg, gboolean originated_locally) { - int dest = 1; - int is_for_dc = 0; - int is_for_dcib = 0; - int is_for_te = 0; - int is_for_crm = 0; - int is_for_cib = 0; - int is_local = 0; - gboolean processing_complete = FALSE; - const char *host_to = crm_element_value(msg, F_CRM_HOST_TO); - const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); - const char *sys_from= crm_element_value(msg, F_CRM_SYS_FROM); - const char *type = crm_element_value(msg, F_TYPE); - const char *msg_error = NULL; - - crm_debug_3("Routing message %s", - crm_element_value(msg, XML_ATTR_REFERENCE)); - - if(msg == NULL) { - msg_error = "Cannot route empty message"; - - } else if(safe_str_eq(CRM_OP_HELLO, - crm_element_value(msg, F_CRM_TASK))){ - /* quietly ignore */ - processing_complete = TRUE; - - } else if(safe_str_neq(type, T_CRM)) { - msg_error = "Bad message type"; - - } else if(sys_to == NULL) { - msg_error = "Bad message destination: no subsystem"; - } + int dest = 1; + int is_for_dc = 0; + int is_for_dcib = 0; + int is_for_te = 0; + int is_for_crm = 0; + int is_for_cib = 0; + int is_local = 0; + gboolean processing_complete = FALSE; + const char *host_to = crm_element_value(msg, F_CRM_HOST_TO); + const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); + const char *sys_from= crm_element_value(msg, F_CRM_SYS_FROM); + const char *type = crm_element_value(msg, F_TYPE); + const char *msg_error = NULL; + + crm_debug_3("Routing message %s", + crm_element_value(msg, XML_ATTR_REFERENCE)); + + if(msg == NULL) { + msg_error = "Cannot route empty message"; + + } else if(safe_str_eq(CRM_OP_HELLO, + crm_element_value(msg, F_CRM_TASK))){ + /* quietly ignore */ + processing_complete = TRUE; - if(msg_error != NULL) { - processing_complete = TRUE; - crm_err("%s", msg_error); - crm_log_xml(LOG_WARNING, "bad msg", msg); - } + } else if(safe_str_neq(type, T_CRM)) { + msg_error = "Bad message type"; - if(processing_complete) { - return TRUE; - } - + } else if(sys_to == NULL) { + msg_error = "Bad message destination: no subsystem"; + } + + if(msg_error != NULL) { processing_complete = TRUE; + crm_err("%s", msg_error); + crm_log_xml(LOG_WARNING, "bad msg", msg); + } + + if(processing_complete) { + return TRUE; + } + + processing_complete = TRUE; - is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0); - is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0); - is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0); - is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0); - is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0); + is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0); + is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0); + is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0); + is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0); + is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0); - is_local = 0; - if(host_to == NULL || strlen(host_to) == 0) { - if(is_for_dc || is_for_te) { - is_local = 0; + is_local = 0; + if(host_to == NULL || strlen(host_to) == 0) { + if(is_for_dc || is_for_te) { + is_local = 0; - } else if(is_for_crm && originated_locally) { - is_local = 0; + } else if(is_for_crm && originated_locally) { + is_local = 0; - } else { - is_local = 1; - } + } else { + is_local = 1; + } - } else if(safe_str_eq(fsa_our_uname, host_to)) { - is_local=1; - } - - if(is_for_dc || is_for_dcib || is_for_te) { - if(AM_I_DC && is_for_te) { - ROUTER_RESULT("Message result: Local relay"); - send_msg_via_ipc(msg, sys_to); + } else if(safe_str_eq(fsa_our_uname, host_to)) { + is_local=1; + } + + if(is_for_dc || is_for_dcib || is_for_te) { + if(AM_I_DC && is_for_te) { + ROUTER_RESULT("Message result: Local relay"); + send_msg_via_ipc(msg, sys_to); - } else if(AM_I_DC) { - ROUTER_RESULT("Message result: DC/CRMd process"); - processing_complete = FALSE; /* more to be done by caller */ - } else if(originated_locally - && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE) - && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) { - - /* Neither the TE or PE should be sending messages - * to DC's on other nodes - * - * By definition, if we are no longer the DC, then - * the PE or TE's data should be discarded - */ + } else if(AM_I_DC) { + ROUTER_RESULT("Message result: DC/CRMd process"); + processing_complete = FALSE; /* more to be done by caller */ + } else if(originated_locally + && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE) + && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) { + + /* Neither the TE or PE should be sending messages + * to DC's on other nodes + * + * By definition, if we are no longer the DC, then + * the PE or TE's data should be discarded + */ #if SUPPORT_COROSYNC - if(is_openais_cluster()) { - dest = text2msg_type(sys_to); - } + if(is_openais_cluster()) { + dest = text2msg_type(sys_to); + } #endif - ROUTER_RESULT("Message result: External relay to DC"); - send_cluster_message(host_to, dest, msg, TRUE); + ROUTER_RESULT("Message result: External relay to DC"); + send_cluster_message(host_to, dest, msg, TRUE); - } else { - /* discard */ - ROUTER_RESULT("Message result: Discard, not DC"); - } + } else { + /* discard */ + ROUTER_RESULT("Message result: Discard, not DC"); + } - } else if(is_local && (is_for_crm || is_for_cib)) { - ROUTER_RESULT("Message result: CRMd process"); - processing_complete = FALSE; /* more to be done by caller */ + } else if(is_local && (is_for_crm || is_for_cib)) { + ROUTER_RESULT("Message result: CRMd process"); + processing_complete = FALSE; /* more to be done by caller */ - } else if(is_local) { - ROUTER_RESULT("Message result: Local relay"); - send_msg_via_ipc(msg, sys_to); + } else if(is_local) { + ROUTER_RESULT("Message result: Local relay"); + send_msg_via_ipc(msg, sys_to); - } else { + } else { #if SUPPORT_COROSYNC - if(is_openais_cluster()) { - dest = text2msg_type(sys_to); - } -#endif - ROUTER_RESULT("Message result: External relay"); - send_cluster_message(host_to, dest, msg, TRUE); + if(is_openais_cluster()) { + dest = text2msg_type(sys_to); } +#endif + ROUTER_RESULT("Message result: External relay"); + send_cluster_message(host_to, dest, msg, TRUE); + } - return processing_complete; + return processing_complete; } gboolean crmd_authorize_message(xmlNode *client_msg, crmd_client_t *curr_client) { - /* check the best case first */ - const char *sys_from = crm_element_value(client_msg, F_CRM_SYS_FROM); - char *uuid = NULL; - char *client_name = NULL; - char *major_version = NULL; - char *minor_version = NULL; - const char *filtered_from; - gpointer table_key = NULL; - gboolean auth_result = FALSE; - struct crm_subsystem_s *the_subsystem = NULL; - gboolean can_reply = FALSE; /* no-one has registered with this id */ - - xmlNode *xml = NULL; - const char *op = crm_element_value(client_msg, F_CRM_TASK); - - if (safe_str_neq(CRM_OP_HELLO, op)) { - - if(sys_from == NULL) { - crm_warn("Message [%s] was had no value for %s... discarding", - crm_element_value(client_msg, XML_ATTR_REFERENCE), - F_CRM_SYS_FROM); - return FALSE; - } + /* check the best case first */ + const char *sys_from = crm_element_value(client_msg, F_CRM_SYS_FROM); + char *uuid = NULL; + char *client_name = NULL; + char *major_version = NULL; + char *minor_version = NULL; + const char *filtered_from; + gpointer table_key = NULL; + gboolean auth_result = FALSE; + struct crm_subsystem_s *the_subsystem = NULL; + gboolean can_reply = FALSE; /* no-one has registered with this id */ + + xmlNode *xml = NULL; + const char *op = crm_element_value(client_msg, F_CRM_TASK); + + if (safe_str_neq(CRM_OP_HELLO, op)) { + + if(sys_from == NULL) { + crm_warn("Message [%s] was had no value for %s... discarding", + crm_element_value(client_msg, XML_ATTR_REFERENCE), + F_CRM_SYS_FROM); + return FALSE; + } - filtered_from = sys_from; + filtered_from = sys_from; - /* The CIB can have two names on the DC */ - if(strcasecmp(sys_from, CRM_SYSTEM_DCIB) == 0) - filtered_from = CRM_SYSTEM_CIB; + /* The CIB can have two names on the DC */ + if(strcasecmp(sys_from, CRM_SYSTEM_DCIB) == 0) + filtered_from = CRM_SYSTEM_CIB; - if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) { - can_reply = TRUE; /* reply can be routed */ - } + if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) { + can_reply = TRUE; /* reply can be routed */ + } - crm_debug_2("Message reply can%s be routed from %s.", - can_reply?"":" not", sys_from); + crm_debug_2("Message reply can%s be routed from %s.", + can_reply?"":" not", sys_from); - if(can_reply == FALSE) { - crm_warn("Message [%s] not authorized", - crm_element_value(client_msg, XML_ATTR_REFERENCE)); - } - - return can_reply; + if(can_reply == FALSE) { + crm_warn("Message [%s] not authorized", + crm_element_value(client_msg, XML_ATTR_REFERENCE)); } + + return can_reply; + } - crm_debug_3("received client join msg"); - crm_log_xml(LOG_MSG, "join", client_msg); - xml = get_message_xml(client_msg, F_CRM_DATA); - auth_result = process_hello_message( - xml, &uuid, &client_name, - &major_version, &minor_version); - - if (auth_result == TRUE) { - if(client_name == NULL || uuid == NULL) { - crm_err("Bad client details (client_name=%s, uuid=%s)", - crm_str(client_name), crm_str(uuid)); - auth_result = FALSE; - } + crm_debug_3("received client join msg"); + crm_log_xml(LOG_MSG, "join", client_msg); + xml = get_message_xml(client_msg, F_CRM_DATA); + auth_result = process_hello_message( + xml, &uuid, &client_name, + &major_version, &minor_version); + + if (auth_result == TRUE) { + if(client_name == NULL || uuid == NULL) { + crm_err("Bad client details (client_name=%s, uuid=%s)", + crm_str(client_name), crm_str(uuid)); + auth_result = FALSE; } + } - if (auth_result == TRUE) { - /* check version */ - int mav = atoi(major_version); - int miv = atoi(minor_version); - crm_debug_3("Checking client version number"); - if (mav < 0 || miv < 0) { - crm_err("Client version (%d:%d) is not acceptable", - mav, miv); - auth_result = FALSE; - } - crm_free(major_version); - crm_free(minor_version); + if (auth_result == TRUE) { + /* check version */ + int mav = atoi(major_version); + int miv = atoi(minor_version); + crm_debug_3("Checking client version number"); + if (mav < 0 || miv < 0) { + crm_err("Client version (%d:%d) is not acceptable", + mav, miv); + auth_result = FALSE; } + crm_free(major_version); + crm_free(minor_version); + } - if (safe_str_eq(CRM_SYSTEM_PENGINE, client_name)) { - the_subsystem = pe_subsystem; + if (safe_str_eq(CRM_SYSTEM_PENGINE, client_name)) { + the_subsystem = pe_subsystem; - } else if (safe_str_eq(CRM_SYSTEM_TENGINE, client_name)) { - the_subsystem = te_subsystem; - } + } else if (safe_str_eq(CRM_SYSTEM_TENGINE, client_name)) { + the_subsystem = te_subsystem; + } - /* TODO: Is this code required anymore?? */ - if (auth_result == TRUE && the_subsystem != NULL) { - /* if we already have one of those clients - * only applies to te, pe etc. not admin clients - */ - crm_err("Checking if %s is required/already connected", - client_name); + /* TODO: Is this code required anymore?? */ + if (auth_result == TRUE && the_subsystem != NULL) { + /* if we already have one of those clients + * only applies to te, pe etc. not admin clients + */ + crm_err("Checking if %s is required/already connected", + client_name); - table_key = (gpointer)crm_strdup(client_name); + table_key = (gpointer)crm_strdup(client_name); - if(is_set(fsa_input_register, the_subsystem->flag_connected)) { - auth_result = FALSE; - crm_free(table_key); - table_key = NULL; - crm_warn("Bit\t%.16llx set in %.16llx", - the_subsystem->flag_connected, - fsa_input_register); - crm_err("Client %s is already connected", - client_name); + if(is_set(fsa_input_register, the_subsystem->flag_connected)) { + auth_result = FALSE; + crm_free(table_key); + table_key = NULL; + crm_warn("Bit\t%.16llx set in %.16llx", + the_subsystem->flag_connected, + fsa_input_register); + crm_err("Client %s is already connected", + client_name); - } else if(FALSE == is_set(fsa_input_register, - the_subsystem->flag_required)) { - crm_warn("Bit\t%.16llx not set in %.16llx", - the_subsystem->flag_connected, - fsa_input_register); - crm_warn("Client %s joined but we dont need it", - client_name); - stop_subsystem(the_subsystem, TRUE); + } else if(FALSE == is_set(fsa_input_register, + the_subsystem->flag_required)) { + crm_warn("Bit\t%.16llx not set in %.16llx", + the_subsystem->flag_connected, + fsa_input_register); + crm_warn("Client %s joined but we dont need it", + client_name); + stop_subsystem(the_subsystem, TRUE); - } else { - the_subsystem->ipc = curr_client->client_channel; - set_bit_inplace(fsa_input_register, - the_subsystem->flag_connected); - } - } else { - table_key = (gpointer)generate_hash_key(client_name, uuid); + the_subsystem->ipc = curr_client->client_channel; + set_bit_inplace(fsa_input_register, + the_subsystem->flag_connected); } + + } else { + table_key = (gpointer)generate_hash_key(client_name, uuid); + } - if (auth_result == TRUE) { - crm_debug_2("Accepted client %s", crm_str(table_key)); + if (auth_result == TRUE) { + crm_debug_2("Accepted client %s", crm_str(table_key)); - curr_client->table_key = table_key; - curr_client->sub_sys = crm_strdup(client_name); - curr_client->uuid = crm_strdup(uuid); + curr_client->table_key = table_key; + curr_client->sub_sys = crm_strdup(client_name); + curr_client->uuid = crm_strdup(uuid); - g_hash_table_insert (ipc_clients, - table_key, curr_client->client_channel); + g_hash_table_insert (ipc_clients, + table_key, curr_client->client_channel); - send_hello_message(curr_client->client_channel, - "n/a", CRM_SYSTEM_CRMD, - "0", "1"); + send_hello_message(curr_client->client_channel, + "n/a", CRM_SYSTEM_CRMD, + "0", "1"); - crm_debug_3("Updated client list with %s", crm_str(table_key)); + crm_debug_3("Updated client list with %s", crm_str(table_key)); - crm_debug_3("Triggering FSA: %s", __FUNCTION__); - mainloop_set_trigger(fsa_source); - - if(the_subsystem != NULL) { - CRM_CHECK(the_subsystem->client == NULL, - process_client_disconnect(the_subsystem->client)); - the_subsystem->client = curr_client; - } + crm_debug_3("Triggering FSA: %s", __FUNCTION__); + mainloop_set_trigger(fsa_source); - } else { - crm_free(table_key); - crm_warn("Rejected client logon request"); - curr_client->client_channel->ch_status = IPC_DISC_PENDING; + if(the_subsystem != NULL) { + CRM_CHECK(the_subsystem->client == NULL, + process_client_disconnect(the_subsystem->client)); + the_subsystem->client = curr_client; } + + } else { + crm_free(table_key); + crm_warn("Rejected client logon request"); + curr_client->client_channel->ch_status = IPC_DISC_PENDING; + } - if(uuid != NULL) crm_free(uuid); - if(minor_version != NULL) crm_free(minor_version); - if(major_version != NULL) crm_free(major_version); - if(client_name != NULL) crm_free(client_name); + if(uuid != NULL) crm_free(uuid); + if(minor_version != NULL) crm_free(minor_version); + if(major_version != NULL) crm_free(major_version); + if(client_name != NULL) crm_free(client_name); - /* hello messages should never be processed further */ - return FALSE; + /* hello messages should never be processed further */ + return FALSE; } enum crmd_fsa_input handle_message(xmlNode *msg) { const char *type = NULL; CRM_CHECK(msg != NULL, return I_NULL); type = crm_element_value(msg, F_CRM_MSG_TYPE); if(crm_str_eq(type, XML_ATTR_REQUEST, TRUE)) { return handle_request(msg); } else if(crm_str_eq(type, XML_ATTR_RESPONSE, TRUE)) { handle_response(msg); return I_NULL; } crm_err("Unknown message type: %s", type); return I_NULL; } static enum crmd_fsa_input handle_failcount_op(xmlNode *stored_msg) { const char *rsc = NULL; xmlNode *xml_rsc = get_xpath_object("//"XML_CIB_TAG_RESOURCE, stored_msg, LOG_ERR); if(xml_rsc) { rsc = ID(xml_rsc); } if(rsc) { char *attr = NULL; crm_info("Removing failcount for %s", rsc); attr = crm_concat("fail-count", rsc, '-'); update_attrd(NULL, attr, NULL); crm_free(attr); attr = crm_concat("last-failure", rsc, '-'); update_attrd(NULL, attr, NULL); crm_free(attr); } else { crm_log_xml_warn(stored_msg, "invalid failcount op"); } return I_NULL; } enum crmd_fsa_input handle_request(xmlNode *stored_msg) { xmlNode *msg = NULL; const char *op = crm_element_value(stored_msg, F_CRM_TASK); /* Optimize this for the DC - it has the most to do */ if(op == NULL) { crm_log_xml(LOG_ERR, "Bad message", stored_msg); return I_NULL; } - /*========== DC-Only Actions ==========*/ + /*========== DC-Only Actions ==========*/ if(AM_I_DC) { if(strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) { return I_NODE_JOIN; } else if(strcmp(op, CRM_OP_JOIN_REQUEST) == 0) { return I_JOIN_REQUEST; } else if(strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) { return I_JOIN_RESULT; } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_info("Shutting ourselves down (DC)"); return I_STOP; } else if(dc_match) { crm_err("We didnt ask to be shut down, yet our" " TE is telling us too." " Better get out now!"); return I_TERMINATE; } else if(fsa_state != S_STOPPING) { crm_err("Another node is asking us to shutdown" " but we think we're ok."); return I_ELECTION; } } else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* a slave wants to shut down */ /* create cib fragment and add to message */ return handle_shutdown_request(stored_msg); } } - /*========== common actions ==========*/ + /*========== common actions ==========*/ if(strcmp(op, CRM_OP_NOVOTE) == 0) { ha_msg_input_t fsa_input; fsa_input.msg = stored_msg; register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input, A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__); } else if(strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) { return handle_failcount_op(stored_msg); } else if(strcmp(op, CRM_OP_VOTE) == 0) { /* count the vote and decide what to do after that */ ha_msg_input_t fsa_input; fsa_input.msg = stored_msg; register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input, A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__); /* Sometimes we _must_ go into S_ELECTION */ if(fsa_state == S_HALT) { crm_debug("Forcing an election from S_HALT"); return I_ELECTION; #if 0 } else if(AM_I_DC) { /* This is the old way of doing things but what is gained? */ return I_ELECTION; #endif } } else if(strcmp(op, CRM_OP_JOIN_OFFER) == 0) { crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID)); return I_JOIN_OFFER; } else if(strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) { crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID)); return I_JOIN_RESULT; } else if(strcmp(op, CRM_OP_LRM_DELETE) == 0 || strcmp(op, CRM_OP_LRM_FAIL) == 0 || strcmp(op, CRM_OP_LRM_REFRESH) == 0 || strcmp(op, CRM_OP_REPROBE) == 0) { crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD); return I_ROUTER; } else if(strcmp(op, CRM_OP_NOOP) == 0) { return I_NULL; } else if(strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) { crm_shutdown(SIGTERM); /*return I_SHUTDOWN; */ return I_NULL; /*========== (NOT_DC)-Only Actions ==========*/ } else if(AM_I_DC == FALSE && strcmp(op, CRM_OP_SHUTDOWN) == 0) { const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(dc_match || fsa_our_dc == NULL) { if(is_set(fsa_input_register, R_SHUTDOWN) == FALSE) { crm_err("We didn't ask to be shut down, yet our" " DC is telling us too."); set_bit_inplace(fsa_input_register, R_STAYDOWN); return I_STOP; } crm_info("Shutting down"); return I_STOP; } else { crm_warn("Discarding %s op from %s", op, host_from); } } else if(strcmp(op, CRM_OP_PING) == 0) { /* eventually do some stuff to figure out * if we /are/ ok */ const char *sys_to = crm_element_value(stored_msg, F_CRM_SYS_TO); xmlNode *ping = createPingAnswerFragment(sys_to, "ok"); crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state)); crm_info("Current ping state: %s", fsa_state2string(fsa_state)); msg = create_reply(stored_msg, ping); relay_message(msg, TRUE); free_xml(ping); free_xml(msg); /* probably better to do this via signals on the * local node */ } else if(strcmp(op, CRM_OP_DEBUG_UP) == 0) { alter_debug(DEBUG_INC); crm_info("Debug set to %d", get_crm_log_level()); } else if(strcmp(op, CRM_OP_DEBUG_DOWN) == 0) { alter_debug(DEBUG_DEC); crm_info("Debug set to %d", get_crm_log_level()); } else { crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC?"the DC":"non-DC node"); crm_log_xml(LOG_ERR, "Unexpected", stored_msg); } return I_NULL; } void handle_response(xmlNode *stored_msg) { const char *op = crm_element_value(stored_msg, F_CRM_TASK); if(op == NULL) { crm_log_xml(LOG_ERR, "Bad message", stored_msg); } else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) { /* Check if the PE answer been superceeded by a subsequent request? */ const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE); if(msg_ref == NULL) { crm_err("%s - Ignoring calculation with no reference", op); } else if(safe_str_eq(msg_ref, fsa_pe_ref)) { ha_msg_input_t fsa_input; fsa_input.msg = stored_msg; register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input); crm_debug_2("Completed: %s...", fsa_pe_ref); } else { crm_info("%s calculation %s is obsolete", op, msg_ref); } } else if(strcmp(op, CRM_OP_VOTE) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) { } else { const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); crm_err("Unexpected response (op=%s, src=%s) sent to the %s", op, host_from, AM_I_DC?"DC":"CRMd"); } } enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg) { - /* handle here to avoid potential version issues - * where the shutdown message/proceedure may have - * been changed in later versions. - * - * This way the DC is always in control of the shutdown - */ + /* handle here to avoid potential version issues + * where the shutdown message/proceedure may have + * been changed in later versions. + * + * This way the DC is always in control of the shutdown + */ - char *now_s = NULL; - time_t now = time(NULL); - xmlNode *node_state = NULL; - const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); - - if(host_from == NULL) { - /* we're shutting down and the DC */ - host_from = fsa_our_uname; - } + char *now_s = NULL; + time_t now = time(NULL); + xmlNode *node_state = NULL; + const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); + + if(host_from == NULL) { + /* we're shutting down and the DC */ + host_from = fsa_our_uname; + } - crm_info("Creating shutdown request for %s (state=%s)", - host_from, fsa_state2string(fsa_state)); + crm_info("Creating shutdown request for %s (state=%s)", + host_from, fsa_state2string(fsa_state)); - crm_log_xml(LOG_MSG, "message", stored_msg); + crm_log_xml(LOG_MSG, "message", stored_msg); - node_state = create_node_state( - host_from, NULL, NULL, NULL, NULL, - CRMD_STATE_INACTIVE, FALSE, __FUNCTION__); + node_state = create_node_state( + host_from, NULL, NULL, NULL, NULL, + CRMD_STATE_INACTIVE, FALSE, __FUNCTION__); - fsa_cib_anon_update(XML_CIB_TAG_STATUS, node_state, cib_quorum_override); - crm_log_xml_debug_2(node_state, "Shutdown update"); - free_xml(node_state); + fsa_cib_anon_update(XML_CIB_TAG_STATUS, node_state, cib_quorum_override); + crm_log_xml_debug_2(node_state, "Shutdown update"); + free_xml(node_state); - now_s = crm_itoa(now); - update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s); - crm_free(now_s); + now_s = crm_itoa(now); + update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s); + crm_free(now_s); - /* will be picked up by the TE as long as its running */ - return I_NULL; + /* will be picked up by the TE as long as its running */ + return I_NULL; } /* msg is deleted by the time this returns */ extern gboolean process_te_message(xmlNode *msg, xmlNode *xml_data); gboolean send_msg_via_ipc(xmlNode *msg, const char *sys) { - gboolean send_ok = TRUE; - IPC_Channel *client_channel; + gboolean send_ok = TRUE; + IPC_Channel *client_channel; - client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys); + client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys); - if(crm_element_value(msg, F_CRM_HOST_FROM) == NULL) { - crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname); - } + if(crm_element_value(msg, F_CRM_HOST_FROM) == NULL) { + crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname); + } - if (client_channel != NULL) { - crm_debug_3("Sending message via channel %s.", sys); - send_ok = send_ipc_message(client_channel, msg); + if (client_channel != NULL) { + crm_debug_3("Sending message via channel %s.", sys); + send_ok = send_ipc_message(client_channel, msg); - } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_TENGINE) == 0) { - xmlNode *data = get_message_xml(msg, F_CRM_DATA); - process_te_message(msg, data); + } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_TENGINE) == 0) { + xmlNode *data = get_message_xml(msg, F_CRM_DATA); + process_te_message(msg, data); - } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) { - fsa_data_t fsa_data; - ha_msg_input_t fsa_input; - - fsa_input.msg = msg; - fsa_input.xml = get_message_xml(msg, F_CRM_DATA); - - fsa_data.id = 0; - fsa_data.actions = 0; - fsa_data.data = &fsa_input; - fsa_data.fsa_input = I_MESSAGE; - fsa_data.fsa_cause = C_IPC_MESSAGE; - fsa_data.origin = __FUNCTION__; - fsa_data.data_type = fsa_dt_ha_msg; + } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) { + fsa_data_t fsa_data; + ha_msg_input_t fsa_input; + + fsa_input.msg = msg; + fsa_input.xml = get_message_xml(msg, F_CRM_DATA); + + fsa_data.id = 0; + fsa_data.actions = 0; + fsa_data.data = &fsa_input; + fsa_data.fsa_input = I_MESSAGE; + fsa_data.fsa_cause = C_IPC_MESSAGE; + fsa_data.origin = __FUNCTION__; + fsa_data.data_type = fsa_dt_ha_msg; #ifdef FSA_TRACE - crm_debug_2("Invoking action A_LRM_INVOKE (%.16llx)", A_LRM_INVOKE); + crm_debug_2("Invoking action A_LRM_INVOKE (%.16llx)", A_LRM_INVOKE); #endif - do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, &fsa_data); + do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, &fsa_data); - } else { - crm_err("Unknown Sub-system (%s)... discarding message.", - crm_str(sys)); - send_ok = FALSE; - } + } else { + crm_err("Unknown Sub-system (%s)... discarding message.", + crm_str(sys)); + send_ok = FALSE; + } - return send_ok; + return send_ok; } void msg_queue_helper(void) { #if SUPPORT_HEARTBEAT - IPC_Channel *ipc = NULL; - if(fsa_cluster_conn != NULL) { - ipc = fsa_cluster_conn->llc_ops->ipcchan( - fsa_cluster_conn); - } - if(ipc != NULL) { - ipc->ops->resume_io(ipc); - } + IPC_Channel *ipc = NULL; + if(fsa_cluster_conn != NULL) { + ipc = fsa_cluster_conn->llc_ops->ipcchan( + fsa_cluster_conn); + } + if(ipc != NULL) { + ipc->ops->resume_io(ipc); + } /* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */ #endif } gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data) { - crmd_client_t *ipc_client = value; - if(ipc_client->client_channel != NULL) { - ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel); - } - return FALSE; + crmd_client_t *ipc_client = value; + if(ipc_client->client_channel != NULL) { + ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel); + } + return FALSE; } diff --git a/crmd/te_events.c b/crmd/te_events.c index 2848fab583..6eab14104d 100644 --- a/crmd/te_events.c +++ b/crmd/te_events.c @@ -1,463 +1,486 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include char *failed_stop_offset = NULL; char *failed_start_offset = NULL; int match_graph_event(int action_id, xmlNode *event, const char *event_node, int op_status, int op_rc, int target_rc); gboolean fail_incompletable_actions(crm_graph_t *graph, const char *down_node) { - const char *target = NULL; - xmlNode *last_action = NULL; + const char *target = NULL; + xmlNode *last_action = NULL; - slist_iter( - synapse, synapse_t, graph->synapses, lpc, - if (synapse->confirmed) { - continue; - } + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; + + gIter = graph->synapses; + for(; gIter != NULL; gIter = gIter->next) { + synapse_t *synapse = (synapse_t*)gIter->data; + + if (synapse->confirmed) { + continue; + } - slist_iter( - action, crm_action_t, synapse->actions, lpc, - - if(action->type == action_type_pseudo || action->confirmed) { - continue; - } else if(action->type == action_type_crm) { - const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); - if(safe_str_eq(task, CRM_OP_FENCE)) { - continue; - } - } + gIter2 = synapse->actions; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + crm_action_t *action = (crm_action_t*)gIter2->data; + + if(action->type == action_type_pseudo || action->confirmed) { + continue; + } else if(action->type == action_type_crm) { + const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); + if(safe_str_eq(task, CRM_OP_FENCE)) { + continue; + } + } - target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); - if(safe_str_eq(target, down_node)) { - action->failed = TRUE; - last_action = action->xml; - update_graph(graph, action); - crm_notice("Action %d (%s) is scheduled for %s (offline)", - action->id, ID(action->xml), down_node); - } - ); - ); - - if(last_action != NULL) { - crm_warn("Node %s shutdown resulted in un-runnable actions", down_node); - abort_transition(INFINITY, tg_restart, "Node failure", last_action); - return TRUE; + target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); + if(safe_str_eq(target, down_node)) { + action->failed = TRUE; + last_action = action->xml; + update_graph(graph, action); + crm_notice("Action %d (%s) is scheduled for %s (offline)", + action->id, ID(action->xml), down_node); + } } + } + + if(last_action != NULL) { + crm_warn("Node %s shutdown resulted in un-runnable actions", down_node); + abort_transition(INFINITY, tg_restart, "Node failure", last_action); + return TRUE; + } - return FALSE; + return FALSE; } static gboolean update_failcount(xmlNode *event, const char *event_node, int rc, int target_rc, gboolean force) { - int interval = 0; - char *task = NULL; - char *rsc_id = NULL; - char *attr_name = NULL; - const char *id = ID(event); - const char *on_uname = get_uname(event_node); - const char *value = NULL; - - if(rc == 99) { - /* this is an internal code for "we're busy, try again" */ - return FALSE; - - } else if(rc == target_rc) { - return FALSE; - } + int interval = 0; + char *task = NULL; + char *rsc_id = NULL; + char *attr_name = NULL; + const char *id = ID(event); + const char *on_uname = get_uname(event_node); + const char *value = NULL; + + if(rc == 99) { + /* this is an internal code for "we're busy, try again" */ + return FALSE; - if(failed_stop_offset == NULL) { - failed_stop_offset = crm_strdup(INFINITY_S); - } + } else if(rc == target_rc) { + return FALSE; + } - if(failed_start_offset == NULL) { - failed_start_offset = crm_strdup(INFINITY_S); - } + if(failed_stop_offset == NULL) { + failed_stop_offset = crm_strdup(INFINITY_S); + } + + if(failed_start_offset == NULL) { + failed_start_offset = crm_strdup(INFINITY_S); + } - CRM_CHECK(on_uname != NULL, return TRUE); + CRM_CHECK(on_uname != NULL, return TRUE); - CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval), - crm_err("Couldn't parse: %s", ID(event)); - goto bail); - CRM_CHECK(task != NULL, goto bail); - CRM_CHECK(rsc_id != NULL, goto bail); + CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval), + crm_err("Couldn't parse: %s", ID(event)); + goto bail); + CRM_CHECK(task != NULL, goto bail); + CRM_CHECK(rsc_id != NULL, goto bail); - if(safe_str_eq(task, CRMD_ACTION_START)) { - interval = 1; - value = failed_start_offset; + if(safe_str_eq(task, CRMD_ACTION_START)) { + interval = 1; + value = failed_start_offset; - } else if(safe_str_eq(task, CRMD_ACTION_STOP)) { - interval = 1; - value = failed_stop_offset; - } + } else if(safe_str_eq(task, CRMD_ACTION_STOP)) { + interval = 1; + value = failed_stop_offset; + } - if(value == NULL || safe_str_neq(value, INFINITY_S)) { - value = XML_NVPAIR_ATTR_VALUE"++"; - } + if(value == NULL || safe_str_neq(value, INFINITY_S)) { + value = XML_NVPAIR_ATTR_VALUE"++"; + } - if(interval > 0 || force) { - char *now = crm_itoa(time(NULL)); + if(interval > 0 || force) { + char *now = crm_itoa(time(NULL)); - crm_warn("Updating failcount for %s on %s after failed %s:" - " rc=%d (update=%s, time=%s)", rsc_id, on_uname, task, rc, value, now); + crm_warn("Updating failcount for %s on %s after failed %s:" + " rc=%d (update=%s, time=%s)", rsc_id, on_uname, task, rc, value, now); - attr_name = crm_concat("fail-count", rsc_id, '-'); - update_attrd(on_uname, attr_name, value); - crm_free(attr_name); + attr_name = crm_concat("fail-count", rsc_id, '-'); + update_attrd(on_uname, attr_name, value); + crm_free(attr_name); - attr_name = crm_concat("last-failure", rsc_id, '-'); - update_attrd(on_uname, attr_name, now); - crm_free(attr_name); + attr_name = crm_concat("last-failure", rsc_id, '-'); + update_attrd(on_uname, attr_name, now); + crm_free(attr_name); - crm_free(now); - } + crm_free(now); + } bail: - crm_free(rsc_id); - crm_free(task); - return TRUE; + crm_free(rsc_id); + crm_free(task); + return TRUE; } static int status_from_rc(crm_action_t *action, int orig_status, int rc, int target_rc) { - int status = orig_status; - if(target_rc == rc) { - crm_debug_2("Target rc: == %d", rc); - if(status != LRM_OP_DONE) { - crm_debug_2("Re-mapping op status to" - " LRM_OP_DONE for rc=%d", rc); - status = LRM_OP_DONE; - } - - } else { - status = LRM_OP_ERROR; - } - - /* 99 is the code we use for direct nack's */ - if(rc != 99 && status != LRM_OP_DONE) { - const char *task, *uname; - task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); - uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - crm_warn("Action %d (%s) on %s failed (target: %d vs. rc: %d): %s", - action->id, task, uname, target_rc, rc, op_status2text(status)); + int status = orig_status; + if(target_rc == rc) { + crm_debug_2("Target rc: == %d", rc); + if(status != LRM_OP_DONE) { + crm_debug_2("Re-mapping op status to" + " LRM_OP_DONE for rc=%d", rc); + status = LRM_OP_DONE; } - return status; + } else { + status = LRM_OP_ERROR; + } + + /* 99 is the code we use for direct nack's */ + if(rc != 99 && status != LRM_OP_DONE) { + const char *task, *uname; + task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); + uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + crm_warn("Action %d (%s) on %s failed (target: %d vs. rc: %d): %s", + action->id, task, uname, target_rc, rc, op_status2text(status)); + } + + return status; } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int match_graph_event(int action_id, xmlNode *event, const char *event_node, int op_status, int op_rc, int target_rc) { - const char *target = NULL; - const char *allow_fail = NULL; - const char *this_event = NULL; - crm_action_t *action = NULL; - - action = get_action(action_id, FALSE); - if(action == NULL) { - return -1; - } + const char *target = NULL; + const char *allow_fail = NULL; + const char *this_event = NULL; + crm_action_t *action = NULL; + + action = get_action(action_id, FALSE); + if(action == NULL) { + return -1; + } - op_status = status_from_rc(action, op_status, op_rc, target_rc); - if(op_status != LRM_OP_DONE) { - update_failcount(event, event_node, op_rc, target_rc, FALSE); - } + op_status = status_from_rc(action, op_status, op_rc, target_rc); + if(op_status != LRM_OP_DONE) { + update_failcount(event, event_node, op_rc, target_rc, FALSE); + } - /* Process OP status */ - switch(op_status) { - case LRM_OP_PENDING: - crm_debug("Ignoring pending operation"); - return action->id; - break; - case LRM_OP_DONE: - break; - case LRM_OP_ERROR: - case LRM_OP_TIMEOUT: - case LRM_OP_NOTSUPPORTED: - action->failed = TRUE; - break; - case LRM_OP_CANCELLED: - /* do nothing?? */ - crm_err("Dont know what to do for cancelled ops yet"); - break; - default: - action->failed = TRUE; - crm_err("Unsupported action result: %d", op_status); - } - - /* stop this event's timer if it had one */ - stop_te_timer(action->timer); - action->confirmed = TRUE; + /* Process OP status */ + switch(op_status) { + case LRM_OP_PENDING: + crm_debug("Ignoring pending operation"); + return action->id; + break; + case LRM_OP_DONE: + break; + case LRM_OP_ERROR: + case LRM_OP_TIMEOUT: + case LRM_OP_NOTSUPPORTED: + action->failed = TRUE; + break; + case LRM_OP_CANCELLED: + /* do nothing?? */ + crm_err("Dont know what to do for cancelled ops yet"); + break; + default: + action->failed = TRUE; + crm_err("Unsupported action result: %d", op_status); + } + + /* stop this event's timer if it had one */ + stop_te_timer(action->timer); + action->confirmed = TRUE; - update_graph(transition_graph, action); - trigger_graph(); + update_graph(transition_graph, action); + trigger_graph(); - if(action->failed) { - allow_fail = crm_meta_value(action->params, XML_ATTR_TE_ALLOWFAIL); - if(crm_is_true(allow_fail)) { - action->failed = FALSE; - } + if(action->failed) { + allow_fail = crm_meta_value(action->params, XML_ATTR_TE_ALLOWFAIL); + if(crm_is_true(allow_fail)) { + action->failed = FALSE; } + } - if(action->failed) { - abort_transition(action->synapse->priority+1, - tg_restart, "Event failed", event); - } + if(action->failed) { + abort_transition(action->synapse->priority+1, + tg_restart, "Event failed", event); + } - this_event = ID(event); - target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - te_log_action(LOG_INFO, "Action %s (%d) confirmed on %s (rc=%d)", - crm_str(this_event), action->id, crm_str(target), - op_status); + this_event = ID(event); + target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + te_log_action(LOG_INFO, "Action %s (%d) confirmed on %s (rc=%d)", + crm_str(this_event), action->id, crm_str(target), + op_status); - return action->id; + return action->id; } crm_action_t * get_action(int id, gboolean confirmed) { - slist_iter( - synapse, synapse_t, transition_graph->synapses, lpc, - - slist_iter( - action, crm_action_t, synapse->actions, lpc2, - - if(action->id == id) { - if(confirmed) { - stop_te_timer(action->timer); - action->confirmed = TRUE; - } - return action; - } - ) - ); - return NULL; + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; + + gIter = transition_graph->synapses; + for(; gIter != NULL; gIter = gIter->next) { + synapse_t *synapse = (synapse_t*) gIter->data; + + gIter2 = synapse->actions; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + crm_action_t *action = (crm_action_t*)gIter2->data; + + if(action->id == id) { + if(confirmed) { + stop_te_timer(action->timer); + action->confirmed = TRUE; + } + return action; + } + } + } + + return NULL; } crm_action_t * get_cancel_action(const char *id, const char *node) { const char *task = NULL; const char *target = NULL; - slist_iter( - synapse, synapse_t, transition_graph->synapses, lpc, + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; + + gIter = transition_graph->synapses; + for(; gIter != NULL; gIter = gIter->next) { + synapse_t *synapse = (synapse_t*) gIter->data; - slist_iter( - action, crm_action_t, synapse->actions, lpc2, - + gIter2 = synapse->actions; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + crm_action_t *action = (crm_action_t*)gIter2->data; + task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); if(safe_str_neq(CRMD_ACTION_CANCEL, task)) { continue; } task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); if(safe_str_neq(task, id)) { continue; } target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); if(safe_str_neq(target, node)) { continue; } return action; - ); - ); - return NULL; + } + } + + return NULL; } crm_action_t * match_down_event(int id, const char *target, const char *filter) { - const char *this_action = NULL; - const char *this_node = NULL; - crm_action_t *match = NULL; + const char *this_action = NULL; + const char *this_node = NULL; + crm_action_t *match = NULL; - slist_iter( - synapse, synapse_t, transition_graph->synapses, lpc, - - /* lookup event */ - slist_iter( - action, crm_action_t, synapse->actions, lpc2, - - if(id > 0 && action->id == id) { - match = action; - break; - } + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; + gIter = transition_graph->synapses; + for(; gIter != NULL; gIter = gIter->next) { + synapse_t *synapse = (synapse_t*)gIter->data; + + /* lookup event */ + gIter2 = synapse->actions; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + crm_action_t *action = (crm_action_t*)gIter2->data; + + if(id > 0 && action->id == id) { + match = action; + break; + } - this_action = crm_element_value( - action->xml, XML_LRM_ATTR_TASK); + this_action = crm_element_value( + action->xml, XML_LRM_ATTR_TASK); - if(action->type != action_type_crm) { - continue; + if(action->type != action_type_crm) { + continue; - } else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){ - continue; + } else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){ + continue; - } else if(filter != NULL - && safe_str_neq(this_action, filter)) { - continue; - } + } else if(filter != NULL + && safe_str_neq(this_action, filter)) { + continue; + } - this_node = crm_element_value( - action->xml, XML_LRM_ATTR_TARGET_UUID); + this_node = crm_element_value( + action->xml, XML_LRM_ATTR_TARGET_UUID); - if(this_node == NULL) { - crm_log_xml_err(action->xml, "No node uuid"); - } + if(this_node == NULL) { + crm_log_xml_err(action->xml, "No node uuid"); + } - if(safe_str_neq(this_node, target)) { - crm_debug("Action %d : Node mismatch: %s", - action->id, this_node); - continue; - } - - match = action; - id = action->id; - break; - ); - if(match != NULL) { - /* stop this event's timer if it had one */ - break; - } - ); - + if(safe_str_neq(this_node, target)) { + crm_debug("Action %d : Node mismatch: %s", + action->id, this_node); + continue; + } + + match = action; + id = action->id; + break; + } + if(match != NULL) { - /* stop this event's timer if it had one */ - crm_debug("Match found for action %d: %s on %s", id, - crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), - target); + /* stop this event's timer if it had one */ + break; + } + } + + if(match != NULL) { + /* stop this event's timer if it had one */ + crm_debug("Match found for action %d: %s on %s", id, + crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), + target); - } else if(id > 0) { - crm_err("No match for action %d", id); + } else if(id > 0) { + crm_err("No match for action %d", id); - } else { - crm_warn("No match for shutdown action on %s", target); - } + } else { + crm_warn("No match for shutdown action on %s", target); + } - return match; + return match; } gboolean process_graph_event(xmlNode *event, const char *event_node) { - int rc = -1; - int status = -1; - - int action = -1; - int target_rc = -1; - int transition_num = -1; - char *update_te_uuid = NULL; - - gboolean stop_early = FALSE; - gboolean passed = FALSE; - const char *id = NULL; - const char *magic = NULL; + int rc = -1; + int status = -1; + + int action = -1; + int target_rc = -1; + int transition_num = -1; + char *update_te_uuid = NULL; + + gboolean stop_early = FALSE; + gboolean passed = FALSE; + const char *id = NULL; + const char *magic = NULL; - CRM_ASSERT(event != NULL); + CRM_ASSERT(event != NULL); - id = ID(event); - magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); + id = ID(event); + magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); - if(magic == NULL) { - /* non-change */ - return FALSE; - } + if(magic == NULL) { + /* non-change */ + return FALSE; + } - CRM_CHECK(decode_transition_magic( - magic, &update_te_uuid, &transition_num, &action, - &status, &rc, &target_rc), - crm_err("Invalid event %s detected", id); - abort_transition(INFINITY, tg_restart,"Bad event", event); - return FALSE; - ); - - if(status == LRM_OP_PENDING) { - goto bail; - } + CRM_CHECK(decode_transition_magic( + magic, &update_te_uuid, &transition_num, &action, + &status, &rc, &target_rc), + crm_err("Invalid event %s detected", id); + abort_transition(INFINITY, tg_restart,"Bad event", event); + return FALSE; + ); + + if(status == LRM_OP_PENDING) { + goto bail; + } - if(transition_num == -1) { - crm_err("Action %s (%s) initiated outside of a transition", - id, magic); - abort_transition(INFINITY, tg_restart,"Unexpected event",event); - - } else if(action < 0 || crm_str_eq(update_te_uuid, te_uuid, TRUE) == FALSE) { - crm_info("Action %s/%d (%s) initiated by a different transitioner", - id, action, magic); - abort_transition(INFINITY, tg_restart,"Foreign event", event); - stop_early = TRUE; /* This could be an lrm status refresh */ + if(transition_num == -1) { + crm_err("Action %s (%s) initiated outside of a transition", + id, magic); + abort_transition(INFINITY, tg_restart,"Unexpected event",event); + + } else if(action < 0 || crm_str_eq(update_te_uuid, te_uuid, TRUE) == FALSE) { + crm_info("Action %s/%d (%s) initiated by a different transitioner", + id, action, magic); + abort_transition(INFINITY, tg_restart,"Foreign event", event); + stop_early = TRUE; /* This could be an lrm status refresh */ - } else if(transition_graph->id != transition_num) { - crm_info("Detected action %s from a different transition:" - " %d vs. %d", id, transition_num, transition_graph->id); - abort_transition(INFINITY, tg_restart,"Old event", event); - stop_early = TRUE; /* This could be an lrm status refresh */ + } else if(transition_graph->id != transition_num) { + crm_info("Detected action %s from a different transition:" + " %d vs. %d", id, transition_num, transition_graph->id); + abort_transition(INFINITY, tg_restart,"Old event", event); + stop_early = TRUE; /* This could be an lrm status refresh */ - } else if(transition_graph->complete) { - crm_info("Action %s arrived after a completed transition", id); - abort_transition(INFINITY, tg_restart, "Inactive graph", event); - - } else if(match_graph_event( - action, event, event_node, status, rc, target_rc) < 0) { - crm_err("Unknown graph action %s", id); - abort_transition(INFINITY, tg_restart, "Unknown event", event); - - } else { - passed = TRUE; - crm_debug_2("Processed update to %s: %s", id, magic); - } - - if(passed == FALSE) { - if(update_failcount(event, event_node, rc, target_rc, transition_num == -1)) { - /* Turns out this wasn't an lrm status refresh update aferall */ - stop_early = FALSE; - } + } else if(transition_graph->complete) { + crm_info("Action %s arrived after a completed transition", id); + abort_transition(INFINITY, tg_restart, "Inactive graph", event); + + } else if(match_graph_event( + action, event, event_node, status, rc, target_rc) < 0) { + crm_err("Unknown graph action %s", id); + abort_transition(INFINITY, tg_restart, "Unknown event", event); + + } else { + passed = TRUE; + crm_debug_2("Processed update to %s: %s", id, magic); + } + + if(passed == FALSE) { + if(update_failcount(event, event_node, rc, target_rc, transition_num == -1)) { + /* Turns out this wasn't an lrm status refresh update aferall */ + stop_early = FALSE; } + } bail: - crm_free(update_te_uuid); - return stop_early; + crm_free(update_te_uuid); + return stop_early; } diff --git a/crmd/te_utils.c b/crmd/te_utils.c index 0bbec5afb3..b0421745a1 100644 --- a/crmd/te_utils.c +++ b/crmd/te_utils.c @@ -1,390 +1,393 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include GCHSource *stonith_src = NULL; crm_trigger_t *stonith_reconnect = NULL; static gboolean fail_incompletable_stonith(crm_graph_t *graph) { + GListPtr lpc = NULL; const char *task = NULL; xmlNode *last_action = NULL; if(graph == NULL) { return FALSE; } - slist_iter( - synapse, synapse_t, graph->synapses, lpc, + for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { + GListPtr lpc2 = NULL; + synapse_t *synapse = (synapse_t*)lpc->data; if (synapse->confirmed) { continue; } - slist_iter( - action, crm_action_t, synapse->actions, lpc, + for(lpc2 = synapse->actions; lpc2 != NULL; lpc2 = lpc2->next) { + crm_action_t *action = (crm_action_t*)lpc2->data; + if(action->type != action_type_crm || action->confirmed) { continue; } task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); if(task && safe_str_eq(task, CRM_OP_FENCE)) { action->failed = TRUE; last_action = action->xml; update_graph(graph, action); crm_notice("Failing action %d (%s): STONITHd terminated", action->id, ID(action->xml)); } - ); - ); - + } + } + if(last_action != NULL) { crm_warn("STONITHd failure resulted in un-runnable actions"); abort_transition(INFINITY, tg_restart, "Stonith failure", last_action); return TRUE; } return FALSE; } static void tengine_stonith_connection_destroy(stonith_t *st, const char *event, xmlNode *msg) { if(is_set(fsa_input_register, R_ST_REQUIRED)) { crm_crit("Fencing daemon connection failed"); mainloop_set_trigger(stonith_reconnect); } else { crm_info("Fencing daemon disconnected"); } /* cbchan will be garbage at this point, arrange for it to be reset */ stonith_api->state = stonith_disconnected; if(AM_I_DC) { fail_incompletable_stonith(transition_graph); trigger_graph(); } } /* */ #ifdef SUPPORT_CMAN # include # include "../lib/common/stack.h" #endif static void tengine_stonith_notify(stonith_t *st, const char *event, xmlNode *msg) { int rc = -99; const char *origin = NULL; const char *target = NULL; const char *executioner = NULL; xmlNode *action = get_xpath_object("//st-data", msg, LOG_ERR); if(action == NULL) { crm_log_xml(LOG_ERR, "Notify data not found", msg); return; } crm_log_xml(LOG_DEBUG, "stonith_notify", msg); crm_element_value_int(msg, F_STONITH_RC, &rc); origin = crm_element_value(action, F_STONITH_ORIGIN); target = crm_element_value(action, F_STONITH_TARGET); executioner = crm_element_value(action, F_STONITH_DELEGATE); if(rc == stonith_ok) { crm_info("Peer %s was terminated (%s) by %s for %s (ref=%s): %s", target, crm_element_value(action, F_STONITH_OPERATION), executioner, origin, crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc)); } else { crm_err("Peer %s could not be terminated (%s) by %s for %s (ref=%s): %s", target, crm_element_value(action, F_STONITH_OPERATION), executioner?executioner:"", origin, crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc)); } #ifdef SUPPORT_CMAN if(rc == stonith_ok && is_cman_cluster()) { int rc = 0; char *target_copy = crm_strdup(target); crm_info("Notifing CMAN that '%s' is now fenced", target); rc = fenced_join(); if(rc != 0) { crm_notice("Could not connect to fenced: rc=%d", rc); } else { rc = fenced_external(target_copy); if(rc != 0) { crm_err("Could not notify fenced: rc=%d", rc); } fenced_leave(); } crm_free(target_copy); } #endif if(rc == stonith_ok && safe_str_eq(target, origin)) { if(fsa_our_dc == NULL || safe_str_eq(fsa_our_dc, target)) { const char *uuid = get_uuid(target); crm_notice("Target was our leader %s/%s (recorded leader: %s)", target, uuid, fsa_our_dc?fsa_our_dc:""); /* There's no need for everyone to update the cib. * Have the node that performed the op do the update too. * In the unlikely event that both die, the DC would be * shot a second time which is not ideal but safe. */ if(safe_str_eq(executioner, fsa_our_uname)) { send_stonith_update(NULL, target, uuid); } } } } gboolean te_connect_stonith(gpointer user_data) { int lpc = 0; int rc = stonith_ok; if(stonith_api == NULL) { stonith_api = stonith_api_new(); } if(stonith_api->state != stonith_disconnected) { crm_debug_2("Still connected"); return TRUE; } for(lpc = 0; lpc < 30; lpc++) { crm_info("Attempting connection to fencing daemon..."); sleep(1); rc = stonith_api->cmds->connect(stonith_api, crm_system_name, NULL, NULL); if(rc == stonith_ok) { break; } if(user_data != NULL) { crm_err("Sign-in failed: triggered a retry"); mainloop_set_trigger(stonith_reconnect); return TRUE; } crm_err("Sign-in failed: pausing and trying again in 2s..."); sleep(1); } CRM_CHECK(rc == stonith_ok, return TRUE); /* If not, we failed 30 times... just get out */ stonith_api->cmds->register_notification( stonith_api, T_STONITH_NOTIFY_DISCONNECT, tengine_stonith_connection_destroy); stonith_api->cmds->register_notification( stonith_api, STONITH_OP_FENCE, tengine_stonith_notify); crm_info("Connected"); return TRUE; } gboolean stop_te_timer(crm_action_timer_t *timer) { const char *timer_desc = "action timer"; if(timer == NULL) { return FALSE; } if(timer->reason == timeout_abort) { timer_desc = "global timer"; crm_debug_2("Stopping %s", timer_desc); } if(timer->source_id != 0) { crm_debug_2("Stopping %s", timer_desc); g_source_remove(timer->source_id); timer->source_id = 0; } else { crm_debug_2("%s was already stopped", timer_desc); return FALSE; } return TRUE; } gboolean te_graph_trigger(gpointer user_data) { enum transition_status graph_rc = -1; if(transition_graph == NULL) { crm_debug("Nothing to do"); return TRUE; } crm_debug_2("Invoking graph %d in state %s", transition_graph->id, fsa_state2string(fsa_state)); switch(fsa_state) { case S_STARTING: case S_PENDING: case S_NOT_DC: case S_HALT: case S_ILLEGAL: case S_STOPPING: case S_TERMINATE: return TRUE; break; default: break; } if(transition_graph->complete == FALSE) { graph_rc = run_graph(transition_graph); print_graph(LOG_DEBUG_3, transition_graph); if(graph_rc == transition_active) { crm_debug_3("Transition not yet complete"); return TRUE; } else if(graph_rc == transition_pending) { crm_debug_3("Transition not yet complete - no actions fired"); return TRUE; } if(graph_rc != transition_complete) { crm_err("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_WARNING, transition_graph); } } crm_info("Transition %d is now complete", transition_graph->id); transition_graph->complete = TRUE; notify_crmd(transition_graph); return TRUE; } void trigger_graph_processing(const char *fn, int line) { mainloop_set_trigger(transition_trigger); crm_debug_2("%s:%d - Triggered graph processing", fn, line); } void abort_transition_graph( int abort_priority, enum transition_action abort_action, const char *abort_text, xmlNode *reason, const char *fn, int line) { int log_level = LOG_INFO; const char *magic = NULL; CRM_CHECK(transition_graph != NULL, return); if(reason) { int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; xmlNode *diff = get_xpath_object("//"F_CIB_UPDATE_RESULT"//diff", reason, LOG_DEBUG_2); magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC); if(diff) { cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s, cib=%d.%d.%d) : %s", fn, line, transition_graph->complete, TYPE(reason), ID(reason), magic?magic:"NA", diff_add_admin_epoch,diff_add_epoch,diff_add_updates, abort_text); } else { do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s) : %s", fn, line, transition_graph->complete, TYPE(reason), ID(reason), magic?magic:"NA", abort_text); } } else { do_crm_log(log_level, "%s:%d - Triggered transition abort (complete=%d) : %s", fn, line, transition_graph->complete, abort_text); } switch(fsa_state) { case S_STARTING: case S_PENDING: case S_NOT_DC: case S_HALT: case S_ILLEGAL: case S_STOPPING: case S_TERMINATE: do_crm_log(log_level, "Abort suppressed: state=%s (complete=%d)", fsa_state2string(fsa_state), transition_graph->complete); return; default: break; } if(magic == NULL && reason != NULL) { crm_log_xml(log_level+1, "Cause", reason); } /* Make sure any queued calculations are discarded ASAP */ crm_free(fsa_pe_ref); fsa_pe_ref = NULL; if(transition_graph->complete) { register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL); return; } update_abort_priority( transition_graph, abort_priority, abort_action, abort_text); mainloop_set_trigger(transition_trigger); } diff --git a/fencing/admin.c b/fencing/admin.c index 46ad4f84d0..9760ab621a 100644 --- a/fencing/admin.c +++ b/fencing/admin.c @@ -1,246 +1,248 @@ /* * Copyright (C) 2009 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct crm_option long_options[] = { {"help", 0, 0, '?', "\tThis text"}, {"version", 0, 0, '$', "\tVersion information" }, {"verbose", 0, 0, 'V', "\tIncrease debug output"}, {"list", 1, 0, 'l', "List devices that can terminate the specified host"}, {"list-all", 0, 0, 'L', "List all registered devices"}, {"metadata", 0, 0, 'M', "Check the device's metadata"}, {"query", 1, 0, 'Q', "Check the device's status"}, {"fence", 1, 0, 'F', "Fence the named host"}, {"unfence", 1, 0, 'U', "Unfence the named host"}, {"confirm", 1, 0, 'C', "Confirm the named host is now safely down"}, {"register", 1, 0, 'R', "Register a stonith device"}, {"deregister", 1, 0, 'D', "De-register a stonith device"}, {"env-option", 1, 0, 'e'}, {"option", 1, 0, 'o'}, {"agent", 1, 0, 'a'}, {0, 0, 0, 0} }; int st_opts = st_opt_sync_call; static void st_callback(stonith_t *st, const char *event, xmlNode *msg) { crm_log_xml_notice(msg, event); } int main(int argc, char ** argv) { int flag; int rc = 0; int argerr = 0; int option_index = 0; char name[512]; char value[512]; const char *agent = NULL; const char *device = NULL; const char *target = NULL; char action = 0; stonith_t *st = NULL; GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal); crm_log_init(NULL, LOG_INFO, TRUE, TRUE, argc, argv); crm_set_options("V?$LQ:R:D:o:a:l:e:F:U:M", "mode [options]", long_options, "Provides access to the stonith-ng API.\n"); while (1) { flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { case 'V': alter_debug(DEBUG_INC); cl_log_enable_stderr(1); break; case '$': case '?': crm_help(flag, LSB_EXIT_OK); break; case 'L': action = flag; break; case 'Q': case 'R': case 'D': action = flag; device = optarg; break; case 'a': agent = optarg; break; case 'l': target = optarg; action = 'L'; break; case 'M': action = flag; break; case 'F': case 'U': case 'C': target = optarg; action = flag; break; case 'o': crm_info("Scanning: -o %s", optarg); rc = sscanf(optarg, "%[^=]=%[^=]", name, value); if(rc != 2) { crm_err("Invalid option: -o %s", optarg); ++argerr; } else { crm_info("Got: '%s'='%s'", name, value); g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value)); } break; case 'e': { char *key = crm_concat("OCF_RESKEY", optarg, '_'); const char *env = getenv(key); if(env == NULL) { crm_err("Invalid option: -e %s", optarg); ++argerr; } else { crm_info("Got: '%s'='%s'", optarg, env); g_hash_table_insert(hash, crm_strdup(optarg), crm_strdup(env)); } } break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } #if 0 g_hash_table_insert(hash, crm_strdup("ipaddr"), crm_strdup("localhost")); g_hash_table_insert(hash, crm_strdup("pcmk-portmap"), crm_strdup("some-host=pcmk-1 pcmk-3=3,4")); g_hash_table_insert(hash, crm_strdup("login"), crm_strdup("root")); g_hash_table_insert(hash, crm_strdup("identity_file"), crm_strdup("/root/.ssh/id_dsa")); #endif crm_debug("Create"); st = stonith_api_new(); if(action != 'M') { rc = st->cmds->connect(st, crm_system_name, NULL, NULL); crm_debug("Connect: %d", rc); rc = st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback); } switch(action) { case 'L': { GListPtr devices = NULL; rc = st->cmds->query(st, st_opts, target, &devices, 10); if(rc == 0) { fprintf(stderr, "No devices found\n"); } else if(rc > 0) { + GListPtr lpc = NULL; fprintf(stderr, "%d devices found\n", rc); - slist_iter(device, char, devices, lpc, - fprintf(stdout, " %s\n", device); - ); + for(lpc = devices; lpc != NULL; lpc = lpc->next) { + char *device = (char*)lpc->data; + fprintf(stdout, " %s\n", device); + } rc = 0; } } break; case 'Q': rc = st->cmds->call(st, st_opts, device, "monitor", NULL, 10); if(rc < 0) { rc = st->cmds->call(st, st_opts, device, "list", NULL, 10); } break; case 'R': rc = st->cmds->register_device(st, st_opts, device, "stonith-ng", agent, hash); break; case 'D': rc = st->cmds->remove_device(st, st_opts, device); break; case 'M': { char *buffer = NULL; st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, 0); printf("%s\n", buffer); crm_free(buffer); } break; case 'C': rc = st->cmds->confirm(st, st_opts, target); break; case 'F': rc = st->cmds->fence(st, st_opts, target, hash, "off", 120); break; case 'U': rc = st->cmds->fence(st, st_opts, target, hash, "on", 120); break; } st->cmds->disconnect(st); crm_debug("Disconnect: %d", rc); crm_debug("Destroy"); stonith_api_delete(st); return rc; } diff --git a/fencing/commands.c b/fencing/commands.c index b262e5d464..25f770e07f 100644 --- a/fencing/commands.c +++ b/fencing/commands.c @@ -1,954 +1,956 @@ /* * Copyright (C) 2009 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GHashTable *device_list = NULL; static int active_children = 0; static void exec_child_done(ProcTrack* proc, int status, int signo, int rc, int waslogged); static void exec_child_new(ProcTrack* p) { active_children++; } static const char *exec_child_name(ProcTrack* p) { async_command_t *cmd = proctrack_data(p); return cmd->client?cmd->client:cmd->remote; } static ProcTrack_ops StonithdProcessTrackOps = { exec_child_done, exec_child_new, exec_child_name, }; static void free_async_command(async_command_t *cmd) { if(cmd->node_attrs) { g_hash_table_destroy(cmd->node_attrs); } crm_free(cmd->action); crm_free(cmd->victim); crm_free(cmd->remote); crm_free(cmd->client); crm_free(cmd->origin); crm_free(cmd->op); crm_free(cmd); } static async_command_t *create_async_command(xmlNode *msg, const char *action) { async_command_t *cmd = NULL; CRM_CHECK(action != NULL, crm_log_xml_warn(msg, "NoAction"); return NULL); crm_malloc0(cmd, sizeof(async_command_t)); crm_element_value_int(msg, F_STONITH_CALLID, &(cmd->id)); crm_element_value_int(msg, F_STONITH_CALLOPTS, &(cmd->options)); crm_element_value_int(msg, F_STONITH_TIMEOUT, &(cmd->timeout)); cmd->origin = crm_element_value_copy(msg, F_ORIG); cmd->remote = crm_element_value_copy(msg, F_STONITH_REMOTE); cmd->client = crm_element_value_copy(msg, F_STONITH_CLIENTID); cmd->op = crm_element_value_copy(msg, F_STONITH_OPERATION); cmd->action = crm_strdup(action); cmd->victim = crm_element_value_copy(msg, F_STONITH_TARGET); cmd->pt_ops = &StonithdProcessTrackOps; CRM_CHECK(cmd->op != NULL, crm_log_xml_warn(msg, "NoOp"); free_async_command(cmd); return NULL); CRM_CHECK(cmd->client != NULL || cmd->remote != NULL, crm_log_xml_warn(msg, "NoClient")); return cmd; } static void free_device(gpointer data) { stonith_device_t *device = data; g_hash_table_destroy(device->params); g_hash_table_destroy(device->aliases); slist_destroy(char, item, device->targets, crm_free(item)); crm_free(device->namespace); crm_free(device->agent); crm_free(device->id); crm_free(device); } static GHashTable *build_port_aliases(const char *hostmap, GListPtr *targets) { char *name = NULL; int last = 0, lpc = 0, max = 0; GHashTable *aliases = g_hash_table_new_full(g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(hostmap == NULL) { return aliases; } max = strlen(hostmap); for(; lpc < max; lpc++) { if(hostmap[lpc] == 0) { break; } else if(isalpha(hostmap[lpc])) { /* keep going */ } else if(hostmap[lpc] == '=') { crm_free(name); crm_malloc0(name, 1 + lpc - last); strncpy(name, hostmap + last, lpc - last); last = lpc + 1; } else if(name && isspace(hostmap[lpc])) { char *value = NULL; crm_malloc0(value, 1 + lpc - last); strncpy(value, hostmap + last, lpc - last); last = lpc + 1; crm_debug("Adding alias '%s'='%s'", name, value); g_hash_table_replace(aliases, name, value); if(targets) { *targets = g_list_append(*targets, crm_strdup(value)); } value=NULL; name=NULL; } else if(isspace(hostmap[lpc])) { last = lpc; } } crm_free(name); return aliases; } static void parse_host_line(const char *line, GListPtr *output) { int lpc = 0; int max = 0; int last = 0; if(line) { max = strlen(line); } else { return; } /* Check for any complaints about additional parameters that the device doesn't understand */ if(strstr(line, "invalid") || strstr(line, "variable")) { crm_debug("Skipping: %s", line); return; } crm_debug_2("Processing: %s", line); /* Skip initial whitespace */ for(lpc = 0; lpc <= max && isspace(line[lpc]); lpc++) { last = lpc+1; } /* Now the actual content */ for(lpc = 0; lpc <= max; lpc++) { gboolean a_space = isspace(line[lpc]); if(a_space && lpc < max && isspace(line[lpc+1])) { /* fast-forward to the end of the spaces */ } else if(a_space || line[lpc] == ',' || line[lpc] == 0) { int rc = 0; char *entry = NULL; crm_malloc0(entry, 1 + lpc - last); rc = sscanf(line+last, "%[a-zA-Z0-9_-.]", entry); if(rc != 1) { crm_warn("Could not parse (%d %d): %s", last, lpc, line+last); } else if(safe_str_neq(entry, "on") && safe_str_neq(entry, "off")) { crm_debug_2("Adding '%s'", entry); *output = g_list_append(*output, entry); entry = NULL; } crm_free(entry); last = lpc + 1; } } } static GListPtr parse_host_list(const char *hosts) { int lpc = 0; int max = 0; int last = 0; GListPtr output = NULL; if(hosts == NULL) { return output; } max = strlen(hosts); for(lpc = 0; lpc <= max; lpc++) { if(hosts[lpc] == '\n' || hosts[lpc] == 0) { char *line = NULL; crm_malloc0(line, 2 + lpc - last); snprintf(line, 1 + lpc - last, "%s", hosts+last); parse_host_line(line, &output); crm_free(line); last = lpc + 1; } } return output; } static stonith_device_t *build_device_from_xml(xmlNode *msg) { xmlNode *dev = get_xpath_object("//"F_STONITH_DEVICE, msg, LOG_ERR); stonith_device_t *device = NULL; crm_malloc0(device, sizeof(stonith_device_t)); device->id = crm_element_value_copy(dev, XML_ATTR_ID); device->agent = crm_element_value_copy(dev, "agent"); device->namespace = crm_element_value_copy(dev, "namespace"); device->params = xml2list(dev); /* TODO: Hook up priority */ return device; } static int stonith_device_register(xmlNode *msg) { const char *value = NULL; stonith_device_t *device = build_device_from_xml(msg); value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTLIST); if(value) { device->targets = parse_host_list(value); } value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTMAP); device->aliases = build_port_aliases(value, &(device->targets)); g_hash_table_replace(device_list, device->id, device); crm_info("Added '%s' to the device list (%d active devices)", device->id, g_hash_table_size(device_list)); return stonith_ok; } static int stonith_device_remove(xmlNode *msg) { xmlNode *dev = get_xpath_object("//"F_STONITH_DEVICE, msg, LOG_ERR); const char *id = crm_element_value(dev, XML_ATTR_ID); if(g_hash_table_remove(device_list, id)) { crm_info("Removed '%s' from the device list (%d active devices)", id, g_hash_table_size(device_list)); } else { crm_info("Device '%s' not found (%d active devices)", id, g_hash_table_size(device_list)); } return stonith_ok; } static gboolean string_in_list(GListPtr list, const char *item) { int lpc = 0; int max = g_list_length(list); for(lpc = 0; lpc < max; lpc ++) { const char *value = g_list_nth_data(list, lpc); if(safe_str_eq(item, value)) { return TRUE; } } return FALSE; } static const char *get_victim_name(stonith_device_t *dev, const char *host) { if(dev == NULL) { return NULL; } else if(host && dev->aliases) { char *alias = g_hash_table_lookup(dev->aliases, host); if(alias) { return alias; } } return host; } static int stonith_device_action(xmlNode *msg, char **output) { int rc = stonith_ok; xmlNode *dev = get_xpath_object("//"F_STONITH_DEVICE, msg, LOG_ERR); const char *id = crm_element_value(dev, F_STONITH_DEVICE); const char *action = crm_element_value(dev, F_STONITH_ACTION); async_command_t *cmd = NULL; stonith_device_t *device = NULL; if(id) { crm_debug_2("Looking for '%s'", id); device = g_hash_table_lookup(device_list, id); } else { CRM_CHECK(safe_str_eq(action, "metadata"), crm_log_xml_warn(msg, "StrangeOp")); device = build_device_from_xml(msg); if(device != NULL && device->id == NULL) { device->id = crm_strdup(device->agent); } } if(device) { int exec_rc = 0; const char *victim = NULL; GHashTable *node_attrs = xml2list(dev); cmd = create_async_command(msg, action); if(cmd == NULL) { free_device(device); return st_err_internal; } cmd->node_attrs = node_attrs; victim = get_victim_name(device, cmd->victim); if(cmd->victim && victim == NULL) { crm_err("Unknown or unhandled port '%s' for device '%s'", cmd->victim, device->id); free_async_command(cmd); return st_err_unknown_port; } cmd->device = crm_strdup(device->id); crm_debug("Calling '%s' with action '%s'%s%s", device->id, action, victim?" on port ":"", victim?victim:""); exec_rc = run_stonith_agent( device->agent, device->params, cmd->node_attrs, action, victim, &rc, output, cmd); if(exec_rc < 0 || rc != 0) { crm_warn("Operation %s on %s failed (%d/%d): %.100s", action, device->id, exec_rc, rc, *output); } else if(exec_rc > 0) { crm_debug("Operation %s on %s active with pid: %d", action, device->id, exec_rc); rc = exec_rc; } else { crm_info("Operation %s on %s passed: %.100s", action, device->id, *output); } } else { crm_notice("Device %s not found", id); rc = st_err_unknown_device; } if(id == NULL) { free_device(device); } return rc; } static gboolean can_fence_host_with_device(stonith_device_t *dev, const char *host) { gboolean can = FALSE; const char *victim = NULL; const char *check_type = NULL; if(dev == NULL) { return FALSE; } else if(host == NULL) { return TRUE; } victim = get_victim_name(dev, host); check_type = g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTCHECK); if(check_type == NULL) { if(g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTLIST)) { check_type = "static-list"; } else { check_type = "dynamic-list"; } } if(safe_str_eq(check_type, "none")) { can = TRUE; } else if(safe_str_eq(check_type, "static-list")) { /* Presence in the hostmap is sufficient * Only use if all hosts on which the device can be active can always fence all listed hosts */ if(string_in_list(dev->targets, victim)) { can = TRUE; } } else if(safe_str_eq(check_type, "dynamic-list")) { time_t now = time(NULL); /* Host/alias must be in the list output to be eligable to be fenced * * Will cause problems if down'd nodes aren't listed or (for virtual nodes) * if the guest is still listed despite being moved to another machine */ if(dev->targets == NULL || dev->targets_age + 60 < now) { char *output = NULL; int rc = stonith_ok; int exec_rc = stonith_ok; /* Some use hostlist instead of the "standard" list */ const char *list_cmd = g_hash_table_lookup(dev->params, STONITH_ATTR_LIST_OP); if(list_cmd == NULL) { list_cmd = "list"; } /* Check for the target's presence in the output of the 'list' command */ slist_destroy(char, item, dev->targets, crm_free(item)); dev->targets = NULL; exec_rc = run_stonith_agent(dev->agent, dev->params, NULL, list_cmd, NULL, &rc, &output, NULL); if(exec_rc < 0 || rc != 0) { crm_notice("Disabling port list queries for %s (%d/%d): %s", dev->id, exec_rc, rc, output); dev->targets_age = -1; } else { crm_info("Refreshing port list for %s", dev->id); dev->targets = parse_host_list(output); dev->targets_age = now; } crm_free(output); } if(string_in_list(dev->targets, victim)) { can = TRUE; } } else if(safe_str_eq(check_type, "status")) { int rc = 0; int exec_rc = 0; /* Some use stat instead of the "standard" status */ const char *status = g_hash_table_lookup(dev->params, STONITH_ATTR_STATUS_OP); if(status == NULL) { status = "status"; } /* Run the status operation for the device/target combination * Will cause problems if the device doesn't return 2 for down'd nodes or * (for virtual nodes) if the device doesn't return 1 for guests that * have been moved to another host */ /* TODO: Get node_attrs in here */ exec_rc = run_stonith_agent( dev->agent, dev->params, NULL, status, victim, &rc, NULL, NULL); if(exec_rc != 0) { crm_err("Could not invoke %s: rc=%d", dev->id, exec_rc); } else if(rc == 1 /* unkown */) { crm_debug_2("Host %s is not known by %s", victim, dev->id); } else if(rc == 0 /* active */ || rc == 2 /* inactive */) { can = TRUE; } else { crm_err("Unkown result calling %s for %s with %s: rc=%d", status, victim, dev->id, rc); } } else { crm_err("Unknown check type: %s", check_type); } crm_info("%s can%s fence %s: %s", dev->id, can?"":" not", victim, check_type); return can; } struct device_search_s { const char *host; GListPtr capable; }; static void search_devices( gpointer key, gpointer value, gpointer user_data) { stonith_device_t *dev = value; struct device_search_s *search = user_data; if(can_fence_host_with_device(dev, search->host)) { search->capable = g_list_append(search->capable, value); } } static int stonith_query(xmlNode *msg, xmlNode **list) { struct device_search_s search; int available_devices = 0; xmlNode *dev = get_xpath_object("//@"F_STONITH_TARGET, msg, LOG_DEBUG_3); search.host = NULL; search.capable = NULL; if(dev) { search.host = crm_element_value(dev, F_STONITH_TARGET); } crm_log_xml_info(msg, "Query"); g_hash_table_foreach(device_list, search_devices, &search); available_devices = g_list_length(search.capable); if(search.host) { crm_info("Found %d matching devices for '%s'", available_devices, search.host); } else { crm_info("%d devices installed", available_devices); } /* Pack the results into data */ if(list) { + GListPtr lpc = NULL; *list = create_xml_node(NULL, __FUNCTION__); crm_xml_add(*list, F_STONITH_TARGET, search.host); crm_xml_add_int(*list, "st-available-devices", available_devices); - slist_iter(device, stonith_device_t, search.capable, lpc, - dev = create_xml_node(*list, F_STONITH_DEVICE); - crm_xml_add(dev, XML_ATTR_ID, device->id); - crm_xml_add(dev, "namespace", device->namespace); - crm_xml_add(dev, "agent", device->agent); - if(search.host == NULL) { - xmlNode *attrs = create_xml_node(dev, XML_TAG_ATTRS); - g_hash_table_foreach(device->params, hash2field, attrs); - } - ); + for(lpc = search.capable; lpc != NULL; lpc = lpc->next) { + stonith_device_t *device = (stonith_device_t*)lpc->data; + dev = create_xml_node(*list, F_STONITH_DEVICE); + crm_xml_add(dev, XML_ATTR_ID, device->id); + crm_xml_add(dev, "namespace", device->namespace); + crm_xml_add(dev, "agent", device->agent); + if(search.host == NULL) { + xmlNode *attrs = create_xml_node(dev, XML_TAG_ATTRS); + g_hash_table_foreach(device->params, hash2field, attrs); + } + } } g_list_free(search.capable); return available_devices; } static void log_operation(async_command_t *cmd, int rc, int pid, const char *next, const char *output) { if(rc == 0) { next = NULL; } if(cmd->victim != NULL) { do_crm_log(rc==0?LOG_INFO:LOG_ERR, "Operation '%s' [%d] for host '%s' with device '%s' returned: %d%s%s (call %d from %s)", cmd->action, pid, cmd->victim, cmd->device, rc, next?". Trying: ":"", next?next:"", cmd->id, cmd->client); } else { do_crm_log(rc==0?LOG_DEBUG:LOG_NOTICE, "Operation '%s' [%d] for device '%s' returned: %d%s%s", cmd->action, pid, cmd->device, rc, next?". Trying: ":"", next?next:""); } if(output) { /* Logging the whole string confuses syslog when the string is xml */ char *local_copy = crm_strdup(output); int lpc = 0, last = 0, more = strlen(local_copy); for(lpc = 0; lpc < more; lpc++) { if(local_copy[lpc] == '\n' || local_copy[lpc] == 0) { local_copy[lpc] = 0; crm_debug("%s output: %s", cmd->device, local_copy+last); last = lpc+1; } } crm_debug("%s output: %s (total %d bytes)", cmd->device, local_copy+last, more); crm_free(local_copy); } } #define READ_MAX 500 static void exec_child_done(ProcTrack* proc, int status, int signum, int rc, int waslogged) { int len = 0; int more = 0; gboolean bcast = FALSE; char *output = NULL; xmlNode *data = NULL; xmlNode *reply = NULL; int pid = proctrack_pid(proc); async_command_t *cmd = proctrack_data(proc); CRM_CHECK(cmd != NULL, return); active_children--; if( signum ) { rc = st_err_signal; if( proctrack_timedout(proc) ) { crm_warn("Child '%d' performing action '%s' with '%s' timed out", pid, cmd->action, cmd->device); rc = st_err_timeout; } } do { char buffer[READ_MAX]; errno = 0; memset(&buffer, 0, READ_MAX); more = read(cmd->stdout, buffer, READ_MAX-1); do_crm_log(status!=0?LOG_DEBUG:LOG_DEBUG_2, "Got %d more bytes: %s", more, buffer); if(more > 0) { crm_realloc(output, len + more + 1); sprintf(output+len, "%s", buffer); len += more; } } while (more == (READ_MAX-1) || (more < 0 && errno == EINTR)); if(cmd->stdout) { close(cmd->stdout); cmd->stdout = 0; } while(rc != 0 && cmd->device_next) { int exec_rc = 0; stonith_device_t *dev = cmd->device_next->data; const char *victim = get_victim_name(dev, cmd->victim); log_operation(cmd, rc, pid, dev->id, output); cmd->device = dev->id; cmd->device_next = cmd->device_next->next; exec_rc = run_stonith_agent(dev->agent, dev->params, cmd->node_attrs, cmd->action, victim, &rc, NULL, cmd); if(exec_rc > 0) { goto done; } pid = exec_rc; } reply = stonith_construct_async_reply(cmd, output, data, rc); if(safe_str_eq(cmd->action, "metadata")) { /* Too verbose to log */ crm_free(output); output = NULL; } else if(crm_str_eq(cmd->action, "reboot", TRUE) || crm_str_eq(cmd->action, "poweroff", TRUE) || crm_str_eq(cmd->action, "poweron", TRUE) || crm_str_eq(cmd->action, "off", TRUE) || crm_str_eq(cmd->action, "on", TRUE)) { bcast = TRUE; } log_operation(cmd, rc, pid, NULL, output); crm_log_xml_debug_3(reply, "Reply"); if(bcast) { /* Send reply as T_STONITH_NOTIFY so everyone does notifications * Potentially limit to unsucessful operations to the originator? */ crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY); send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE); } else if(cmd->origin) { send_cluster_message(cmd->origin, crm_msg_stonith_ng, reply, FALSE); } else { do_local_reply(reply, cmd->client, cmd->options & st_opt_sync_call, FALSE); } free_async_command(cmd); done: reset_proctrack_data(proc); crm_free(output); free_xml(reply); free_xml(data); } static gint sort_device_priority(gconstpointer a, gconstpointer b) { const stonith_device_t *dev_a = a; const stonith_device_t *dev_b = a; if(dev_a->priority > dev_b->priority) { return -1; } else if(dev_a->priority < dev_b->priority) { return 1; } return 0; } static int stonith_fence(xmlNode *msg) { int rc = 0; struct device_search_s search; stonith_device_t *device = NULL; async_command_t *cmd = create_async_command(msg, crm_element_value(msg, F_STONITH_ACTION)); xmlNode *dev = get_xpath_object("//@"F_STONITH_TARGET, msg, LOG_ERR); GHashTable *node_attrs = xml2list(dev); if(cmd == NULL) { return st_err_internal; } search.capable = NULL; search.host = crm_element_value(dev, F_STONITH_TARGET); crm_log_xml_info(msg, "Exec"); g_hash_table_foreach(device_list, search_devices, &search); crm_info("Found %d matching devices for '%s'", g_list_length(search.capable), search.host); if(g_list_length(search.capable) == 0) { free_async_command(cmd); return st_err_none_available; } /* Order based on priority */ search.capable = g_list_sort(search.capable, sort_device_priority); device = search.capable->data; cmd->device = device->id; if(g_list_length(search.capable) > 1) { cmd->device_list = search.capable; cmd->node_attrs = node_attrs; } return run_stonith_agent(device->agent, device->params, node_attrs, cmd->action, cmd->victim, &rc, NULL, cmd); } xmlNode *stonith_construct_reply(xmlNode *request, char *output, xmlNode *data, int rc) { int lpc = 0; xmlNode *reply = NULL; const char *name = NULL; const char *value = NULL; const char *names[] = { F_STONITH_OPERATION, F_STONITH_CALLID, F_STONITH_CLIENTID, F_STONITH_REMOTE, F_STONITH_CALLOPTS }; crm_debug_4("Creating a basic reply"); reply = create_xml_node(NULL, T_STONITH_REPLY); crm_xml_add(reply, "st_origin", __FUNCTION__); crm_xml_add(reply, F_TYPE, T_STONITH_NG); crm_xml_add(reply, "st_output", output); crm_xml_add_int(reply, F_STONITH_RC, rc); CRM_CHECK(request != NULL, crm_warn("Can't create a sane reply"); return reply); for(lpc = 0; lpc < DIMOF(names); lpc++) { name = names[lpc]; value = crm_element_value(request, name); crm_xml_add(reply, name, value); } if(data != NULL) { crm_debug_4("Attaching reply output"); add_message_xml(reply, F_STONITH_CALLDATA, data); } return reply; } xmlNode *stonith_construct_async_reply(async_command_t *cmd, char *output, xmlNode *data, int rc) { xmlNode *reply = NULL; crm_debug_4("Creating a basic reply"); reply = create_xml_node(NULL, T_STONITH_REPLY); crm_xml_add(reply, "st_origin", __FUNCTION__); crm_xml_add(reply, F_TYPE, T_STONITH_NG); crm_xml_add(reply, F_STONITH_OPERATION, cmd->op); crm_xml_add(reply, F_STONITH_REMOTE, cmd->remote); crm_xml_add(reply, F_STONITH_CLIENTID, cmd->client); crm_xml_add_int(reply, F_STONITH_CALLID, cmd->id); crm_xml_add_int(reply, F_STONITH_CALLOPTS, cmd->options); crm_xml_add_int(reply, F_STONITH_RC, rc); crm_xml_add(reply, "st_output", output); if(data != NULL) { crm_info("Attaching reply output"); add_message_xml(reply, F_STONITH_CALLDATA, data); } return reply; } void stonith_command(stonith_client_t *client, xmlNode *request, const char *remote) { int call_options = 0; int rc = st_err_generic; gboolean is_reply = FALSE; xmlNode *reply = NULL; xmlNode *data = NULL; char *output = NULL; const char *op = crm_element_value(request, F_STONITH_OPERATION); const char *client_id = crm_element_value(request, F_STONITH_CLIENTID); crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options); if(get_xpath_object("//"T_STONITH_REPLY, request, LOG_DEBUG_3)) { is_reply = TRUE; } if(device_list == NULL) { device_list = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, free_device); } crm_debug("Processing %s%s from %s", op, is_reply?" reply":"", client?client->name:remote); if(crm_str_eq(op, CRM_OP_REGISTER, TRUE)) { return; } else if(crm_str_eq(op, STONITH_OP_DEVICE_ADD, TRUE)) { rc = stonith_device_register(request); do_stonith_notify(call_options, op, rc, request, NULL); } else if(crm_str_eq(op, STONITH_OP_DEVICE_DEL, TRUE)) { rc = stonith_device_remove(request); do_stonith_notify(call_options, op, rc, request, NULL); } else if(crm_str_eq(op, STONITH_OP_CONFIRM, TRUE)) { async_command_t *cmd = create_async_command(request, crm_element_value(request, F_STONITH_ACTION)); xmlNode *reply = stonith_construct_async_reply(cmd, NULL, NULL, 0); crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY); crm_notice("Broadcasting manual fencing confirmation for node %s", cmd->victim); send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE); free_async_command(cmd); free_xml(reply); } else if(crm_str_eq(op, STONITH_OP_EXEC, TRUE)) { rc = stonith_device_action(request, &output); } else if(is_reply && crm_str_eq(op, STONITH_OP_QUERY, TRUE)) { process_remote_stonith_query(request); return; } else if(crm_str_eq(op, STONITH_OP_QUERY, TRUE)) { create_remote_stonith_op(client_id, request, TRUE); /* Record it for the future notification */ rc = stonith_query(request, &data); } else if(is_reply && crm_str_eq(op, T_STONITH_NOTIFY, TRUE)) { process_remote_stonith_exec(request); return; } else if(crm_str_eq(op, T_STONITH_NOTIFY, TRUE)) { const char *flag_name = NULL; flag_name = crm_element_value(request, F_STONITH_NOTIFY_ACTIVATE); if(flag_name) { crm_debug("Setting %s callbacks for %s (%s): ON", flag_name, client->name, client->id); client->flags |= get_stonith_flag(flag_name); } flag_name = crm_element_value(request, F_STONITH_NOTIFY_DEACTIVATE); if(flag_name) { crm_debug("Setting %s callbacks for %s (%s): off", flag_name, client->name, client->id); client->flags |= get_stonith_flag(flag_name); } return; /* } else if(is_reply && crm_str_eq(op, STONITH_OP_FENCE, TRUE)) { */ /* process_remote_stonith_exec(request); */ /* return; */ } else if(is_reply == FALSE && crm_str_eq(op, STONITH_OP_FENCE, TRUE)) { if(remote) { rc = stonith_fence(request); } else if(call_options & st_opt_local_first) { rc = stonith_fence(request); if(rc < 0) { initiate_remote_stonith_op(client, request); } } else { initiate_remote_stonith_op(client, request); } return; } else { crm_err("Unknown %s%s from %s", op, is_reply?" reply":"", client?client->name:remote); crm_log_xml_warn(request, "UnknownOp"); } do_crm_log(rc>0?LOG_DEBUG:LOG_INFO,"Processed %s%s from %s: rc=%d", op, is_reply?" reply":"", client?client->name:remote, rc); if(is_reply) { /* Nothing */ } else if(remote) { reply = stonith_construct_reply(request, output, data, rc); send_cluster_message(remote, crm_msg_stonith_ng, reply, FALSE); free_xml(reply); } else if(rc <= 0 || crm_str_eq(op, STONITH_OP_QUERY, TRUE)) { reply = stonith_construct_reply(request, output, data, rc); do_local_reply(reply, client_id, call_options & st_opt_sync_call, remote!=NULL); free_xml(reply); } crm_free(output); free_xml(data); } diff --git a/lib/pengine/clone.c b/lib/pengine/clone.c index 319c384da5..663362c707 100644 --- a/lib/pengine/clone.c +++ b/lib/pengine/clone.c @@ -1,502 +1,504 @@ /* * 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 #define VARIANT_CLONE 1 #include "./variant.h" void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); void force_non_unique_clone(resource_t *rsc, const char *rid, pe_working_set_t *data_set); resource_t *create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set); static void mark_as_orphan(resource_t *rsc) { + GListPtr gIter = rsc->children; set_bit(rsc->flags, pe_rsc_orphan); - slist_iter( - child, resource_t, rsc->children, lpc, + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; mark_as_orphan(child); - ); + } } static void clear_bit_recursive(resource_t *rsc, unsigned long long flag) { + GListPtr gIter = rsc->children; clear_bit_inplace(rsc->flags, flag); - if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - clear_bit_recursive(child_rsc, flag); - ); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + clear_bit_recursive(child_rsc, flag); } } void force_non_unique_clone(resource_t *rsc, const char *rid, pe_working_set_t *data_set) { if(rsc->variant == pe_clone || rsc->variant == pe_master) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_config_warn("Clones %s contains non-OCF resource %s and so " "can only be used as an anonymous clone. " "Set the "XML_RSC_ATTR_UNIQUE" meta attribute to false", rsc->id, rid); clone_data->clone_node_max = 1; clone_data->clone_max = g_list_length(data_set->nodes); clear_bit_recursive(rsc, pe_rsc_unique); } } resource_t * find_clone_instance(resource_t *rsc, const char *sub_id, pe_working_set_t *data_set) { char *child_id = NULL; resource_t *child = NULL; const char *child_base = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); child_base = ID(clone_data->xml_obj_child); child_id = crm_concat(child_base, sub_id, ':'); child = pe_find_resource(rsc->children, child_id); crm_free(child_id); return child; } resource_t * create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set) { gboolean as_orphan = FALSE; char *inc_num = NULL; char *inc_max = NULL; resource_t *child_rsc = NULL; xmlNode * child_copy = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE); if(sub_id < 0) { as_orphan = TRUE; sub_id = clone_data->total_clones; } inc_num = crm_itoa(sub_id); inc_max = crm_itoa(clone_data->clone_max); child_copy = copy_xml(clone_data->xml_obj_child); crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num); if(common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); child_rsc = NULL; goto bail; } /* child_rsc->globally_unique = rsc->globally_unique; */ clone_data->total_clones += 1; crm_debug_2("Setting clone attributes for: %s", child_rsc->id); rsc->children = g_list_append(rsc->children, child_rsc); if(as_orphan) { mark_as_orphan(child_rsc); } add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max); print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE); bail: crm_free(inc_num); crm_free(inc_max); return child_rsc; } gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set) { const char *master_max = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_MAX); const char *master_node_max = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX); g_hash_table_replace(rsc->meta, crm_strdup("stateful"), crm_strdup(XML_BOOLEAN_TRUE)); if(clone_unpack(rsc, data_set)) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_data->master_max = crm_parse_int(master_max, "1"); clone_data->master_node_max = crm_parse_int(master_node_max, "1"); return TRUE; } return FALSE; } gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; const char *type = NULL; resource_t *self = NULL; int num_xml_children = 0; xmlNode *xml_tmp = NULL; xmlNode *xml_self = NULL; xmlNode *xml_obj = rsc->xml; clone_variant_data_t *clone_data = NULL; const char *ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *interleave = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INTERLEAVE); const char *max_clones = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_MAX); const char *max_clones_node = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(clone_data, sizeof(clone_variant_data_t)); rsc->variant_opaque = clone_data; clone_data->interleave = FALSE; clone_data->ordered = FALSE; clone_data->active_clones = 0; clone_data->xml_obj_child = NULL; clone_data->clone_node_max = crm_parse_int(max_clones_node, "1"); if(max_clones) { clone_data->clone_max = crm_parse_int(max_clones, "1"); } else if(g_list_length(data_set->nodes) > 0) { clone_data->clone_max = g_list_length(data_set->nodes); } else { clone_data->clone_max = 1; /* Handy during crm_verify */ } if(crm_is_true(interleave)) { clone_data->interleave = TRUE; } if(crm_is_true(ordered)) { clone_data->ordered = TRUE; } if((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) { crm_config_err("Anonymous clones (%s) may only support one copy" " per node", rsc->id); clone_data->clone_node_max = 1; } crm_debug_2("Options for %s", rsc->id); crm_debug_2("\tClone max: %d", clone_data->clone_max); crm_debug_2("\tClone node max: %d", clone_data->clone_node_max); crm_debug_2("\tClone is unique: %s", is_set(rsc->flags, pe_rsc_unique)?"true":"false"); clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_GROUP, FALSE); if(clone_data->xml_obj_child == NULL) { clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } else { xml_child_iter_filter(xml_obj, a_child, XML_CIB_TAG_RESOURCE, num_xml_children++); } if(clone_data->xml_obj_child == NULL) { crm_config_err("%s has nothing to clone", rsc->id); return FALSE; } type = crm_element_name(clone_data->xml_obj_child); xml_child_iter_filter(xml_obj, a_child, type, num_xml_children++); if(num_xml_children > 1) { crm_config_err("%s has too many children. Only the first (%s) will be cloned.", rsc->id, ID(clone_data->xml_obj_child)); } xml_self = copy_xml(rsc->xml); /* this is a bit of a hack - but simplifies everything else */ xmlNodeSetName(xml_self, ((const xmlChar*)XML_CIB_TAG_RESOURCE)); xml_tmp = find_xml_node(xml_obj, "operations", FALSE); if(xml_tmp != NULL) { add_node_copy(xml_self, xml_tmp); } /* Make clones ever so slightly sticky by default * This is the only way to ensure clone instances are not * shuffled around the cluster for no benefit */ add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1"); if(common_unpack(xml_self, &self, rsc, data_set)) { clone_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); clone_data->self = self; return FALSE; } crm_debug_2("\tClone is unique (fixed): %s", is_set(rsc->flags, pe_rsc_unique)?"true":"false"); clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify); add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE, is_set(rsc->flags, pe_rsc_unique)?XML_BOOLEAN_TRUE:XML_BOOLEAN_FALSE); for(lpc = 0; lpc < clone_data->clone_max; lpc++) { create_child_clone(rsc, lpc, data_set); } if(clone_data->clone_max == 0) { /* create one so that unpack_find_resource() will hook up * any orphans up to the parent correctly */ create_child_clone(rsc, -1, data_set); } crm_debug_3("Added %d children to resource %s...", clone_data->clone_max, rsc->id); return TRUE; } gboolean clone_active(resource_t *rsc, gboolean all) { - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - gboolean child_active = child_rsc->fns->active(child_rsc, all); - if(all == FALSE && child_active) { - return TRUE; - } else if(all && child_active == FALSE) { - return FALSE; - } - ); - if(all) { - return TRUE; - } else { - return FALSE; + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + gboolean child_active = child_rsc->fns->active(child_rsc, all); + + if(all == FALSE && child_active) { + return TRUE; + } else if(all && child_active == FALSE) { + return FALSE; } + } + + if(all) { + return TRUE; + } else { + return FALSE; + } } static char * add_list_element(char *list, const char *value) { int len = 0; int last = 0; if(value == NULL) { return list; } if(list) { last = strlen(list); } len = last + 2; /* +1 space, +1 EOS */ len += strlen(value); crm_realloc(list, len); sprintf(list + last, " %s", value); return list; } static void short_print(char *list, const char *prefix, const char *type, long options, void *print_data) { if(list) { if(options & pe_print_html) { status_print("
  • "); } status_print("%s%s: [%s ]", prefix, type, list); if(options & pe_print_html) { status_print("
  • \n"); } else if(options & pe_print_suppres_nl) { /* nothing */ } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\n"); } } } void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { char *child_text = NULL; char *master_list = NULL; char *started_list = NULL; char *stopped_list = NULL; const char *type = "Clone"; + GListPtr gIter = rsc->children; + clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text == NULL) { pre_text = " "; } child_text = crm_concat(pre_text, " ", ' '); if(rsc->variant == pe_master) { type = "Master/Slave"; } status_print("%s%s Set: %s [%s]%s%s", pre_text?pre_text:"", type, rsc->id, ID(clone_data->xml_obj_child), is_set(rsc->flags, pe_rsc_unique)?" (unique)":"", is_set(rsc->flags, pe_rsc_managed)?"":" (unmanaged)"); if(options & pe_print_html) { status_print("\n
      \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - + for(; gIter != NULL; gIter = gIter->next) { gboolean print_full = FALSE; + resource_t *child_rsc = (resource_t*)gIter->data; + if(child_rsc->fns->active(child_rsc, FALSE) == FALSE) { /* Inactive clone */ if(is_set(child_rsc->flags, pe_rsc_orphan)) { continue; } else if(is_set(rsc->flags, pe_rsc_unique)) { print_full = TRUE; } else { stopped_list = add_list_element(stopped_list, child_rsc->id); } } else if(is_set(child_rsc->flags, pe_rsc_unique) || is_set(child_rsc->flags, pe_rsc_orphan) || is_set(child_rsc->flags, pe_rsc_managed) == FALSE || is_set(child_rsc->flags, pe_rsc_failed)) { /* Unique, unmanaged or failed clone */ print_full = TRUE; } else if(child_rsc->fns->active(child_rsc, TRUE)) { /* Fully active anonymous clone */ node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE); if(location) { const char *host = location->details->uname; enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE); if(a_role > RSC_ROLE_SLAVE) { /* And active on a single node as master */ master_list = add_list_element(master_list, host); } else { /* And active on a single node as started/slave */ started_list = add_list_element(started_list, host); } } else { /* uncolocated group - bleh */ print_full = TRUE; } } else { /* Partially active anonymous clone */ print_full = TRUE; } if(print_full) { if(options & pe_print_html) { status_print("
    • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
    • \n"); } - } - - ); + } + } short_print(master_list, child_text, "Masters", options, print_data); short_print(started_list, child_text, rsc->variant==pe_master?"Slaves":"Started", options, print_data); short_print(stopped_list, child_text, "Stopped", options, print_data); crm_free(master_list); crm_free(started_list); crm_free(stopped_list); if(options & pe_print_html) { status_print("
    \n"); } crm_free(child_text); } void clone_free(resource_t *rsc) { - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + GListPtr gIter = rsc->children; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - crm_debug_3("Freeing %s", rsc->id); + crm_debug_3("Freeing %s", rsc->id); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - crm_debug_3("Freeing child %s", child_rsc->id); - free_xml(child_rsc->xml); - child_rsc->fns->free(child_rsc); - ); + crm_debug_3("Freeing child %s", child_rsc->id); + free_xml(child_rsc->xml); + child_rsc->fns->free(child_rsc); + } - crm_debug_3("Freeing child list"); - pe_free_shallow_adv(rsc->children, FALSE); + crm_debug_3("Freeing child list"); + pe_free_shallow_adv(rsc->children, FALSE); - if(clone_data->self) { - free_xml(clone_data->self->xml); - clone_data->self->fns->free(clone_data->self); - } + if(clone_data->self) { + free_xml(clone_data->self->xml); + clone_data->self->fns->free(clone_data->self); + } - CRM_ASSERT(clone_data->demote_notify == NULL); - CRM_ASSERT(clone_data->stop_notify == NULL); - CRM_ASSERT(clone_data->start_notify == NULL); - CRM_ASSERT(clone_data->promote_notify == NULL); + CRM_ASSERT(clone_data->demote_notify == NULL); + CRM_ASSERT(clone_data->stop_notify == NULL); + CRM_ASSERT(clone_data->start_notify == NULL); + CRM_ASSERT(clone_data->promote_notify == NULL); - common_free(rsc); + common_free(rsc); } enum rsc_role_e clone_resource_state(const resource_t *rsc, gboolean current) { - enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN; - - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current); - if(a_role > clone_role) { - clone_role = a_role; - } - ); + enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN; + GListPtr gIter = rsc->children; + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current); - crm_debug_3("%s role: %s", rsc->id, role2text(clone_role)); - return clone_role; + if(a_role > clone_role) { + clone_role = a_role; + } + } + + crm_debug_3("%s role: %s", rsc->id, role2text(clone_role)); + return clone_role; } diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c index e751b6c21e..bf74eb5a6a 100644 --- a/lib/pengine/complex.c +++ b/lib/pengine/complex.c @@ -1,471 +1,472 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include extern xmlNode *get_object_root(const char *object_type,xmlNode *the_root); void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_rsc, native_parameter, native_print, native_active, native_resource_state, native_location, native_free }, { group_unpack, native_find_rsc, native_parameter, group_print, group_active, group_resource_state, native_location, group_free }, { clone_unpack, native_find_rsc, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free }, { master_unpack, native_find_rsc, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free } }; enum pe_obj_types get_resource_type(const char *name) { if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { return pe_native; } else if(safe_str_eq(name, XML_CIB_TAG_GROUP)) { return pe_group; } else if(safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { return pe_clone; } else if(safe_str_eq(name, XML_CIB_TAG_MASTER)) { return pe_master; } return pe_unknown; } const char *get_resource_typename(enum pe_obj_types type) { switch(type) { case pe_native: return XML_CIB_TAG_RESOURCE; case pe_group: return XML_CIB_TAG_GROUP; case pe_clone: return XML_CIB_TAG_INCARNATION; case pe_master: return XML_CIB_TAG_MASTER; case pe_unknown: return "unknown"; } return ""; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { add_hash_param(user_data, key, value); } void get_meta_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set) { GHashTable *node_hash = NULL; if(node) { node_hash = node->details->attrs; } xml_prop_iter(rsc->xml, prop_name, prop_value, add_hash_param(meta_hash, prop_name, prop_value); ); unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_META_SETS, node_hash, meta_hash, NULL, FALSE, data_set->now); /* populate from the regular attributes until the GUI can create * meta attributes */ unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_ATTR_SETS, node_hash, meta_hash, NULL, FALSE, data_set->now); /* set anything else based on the parent */ if(rsc->parent != NULL) { g_hash_table_foreach(rsc->parent->meta, dup_attr, meta_hash); } /* and finally check the defaults */ unpack_instance_attributes(data_set->input, data_set->rsc_defaults, XML_TAG_META_SETS, node_hash, meta_hash, NULL, FALSE, data_set->now); } void get_rsc_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set) { GHashTable *node_hash = NULL; if(node) { node_hash = node->details->attrs; } unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_ATTR_SETS, node_hash, meta_hash, NULL, FALSE, data_set->now); /* set anything else based on the parent */ if(rsc->parent != NULL) { get_rsc_attributes(meta_hash, rsc->parent, node, data_set); } else { /* and finally check the defaults */ unpack_instance_attributes(data_set->input, data_set->rsc_defaults, XML_TAG_ATTR_SETS, node_hash, meta_hash, NULL, FALSE, data_set->now); } } gboolean common_unpack(xmlNode * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set) { xmlNode *ops = NULL; resource_t *top = NULL; const char *value = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *class = crm_element_value(xml_obj, XML_AGENT_ATTR_CLASS); crm_log_xml_debug_3(xml_obj, "Processing resource input..."); if(id == NULL) { pe_err("Must specify id tag in "); return FALSE; } else if(rsc == NULL) { pe_err("Nowhere to unpack resource into"); return FALSE; } crm_malloc0(*rsc, sizeof(resource_t)); ops = find_xml_node(xml_obj, "operations", FALSE); (*rsc)->xml = xml_obj; (*rsc)->parent = parent; (*rsc)->ops_xml = expand_idref(ops, data_set->input); (*rsc)->variant = get_resource_type(crm_element_name(xml_obj)); if((*rsc)->variant == pe_unknown) { pe_err("Unknown resource type: %s", crm_element_name(xml_obj)); crm_free(*rsc); return FALSE; } (*rsc)->parameters = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); (*rsc)->meta = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); (*rsc)->allowed_nodes = g_hash_table_new_full( g_str_hash,g_str_equal, NULL, g_hash_destroy_str); (*rsc)->known_on = g_hash_table_new_full( g_str_hash,g_str_equal, NULL, g_hash_destroy_str); value = crm_element_value(xml_obj, XML_RSC_ATTR_INCARNATION); if(value) { (*rsc)->id = crm_concat(id, value, ':'); add_hash_param((*rsc)->meta, XML_RSC_ATTR_INCARNATION, value); } else { (*rsc)->id = crm_strdup(id); } if(parent) { (*rsc)->long_name = crm_concat(parent->long_name, (*rsc)->id, ':'); } else { (*rsc)->long_name = crm_strdup((*rsc)->id); } (*rsc)->fns = &resource_class_functions[(*rsc)->variant]; crm_debug_3("Unpacking resource..."); get_meta_attributes((*rsc)->meta, *rsc, NULL, data_set); (*rsc)->flags = 0; set_bit((*rsc)->flags, pe_rsc_runnable); set_bit((*rsc)->flags, pe_rsc_provisional); if(is_set(data_set->flags, pe_flag_is_managed_default)) { set_bit((*rsc)->flags, pe_rsc_managed); } (*rsc)->rsc_cons = NULL; (*rsc)->actions = NULL; (*rsc)->role = RSC_ROLE_STOPPED; (*rsc)->next_role = RSC_ROLE_UNKNOWN; (*rsc)->recovery_type = recovery_stop_start; (*rsc)->stickiness = data_set->default_resource_stickiness; (*rsc)->migration_threshold= INFINITY; (*rsc)->failure_timeout = 0; value = g_hash_table_lookup((*rsc)->meta, XML_CIB_ATTR_PRIORITY); (*rsc)->priority = crm_parse_int(value, "0"); (*rsc)->effective_priority = (*rsc)->priority; value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_NOTIFY); if(crm_is_true(value)) { set_bit((*rsc)->flags, pe_rsc_notify); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_MANAGED); if(value != NULL && safe_str_neq("default", value)) { gboolean bool_value = TRUE; crm_str_to_boolean(value, &bool_value); if(bool_value == FALSE) { clear_bit((*rsc)->flags, pe_rsc_managed); } else { set_bit((*rsc)->flags, pe_rsc_managed); } } if(is_set(data_set->flags, pe_flag_maintenance_mode)) { clear_bit((*rsc)->flags, pe_rsc_managed); } crm_debug_2("Options for %s", (*rsc)->id); value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_UNIQUE); top = uber_parent(*rsc); if(crm_is_true(value) || top->variant < pe_clone) { set_bit((*rsc)->flags, pe_rsc_unique); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_RESTART); if(safe_str_eq(value, "restart")) { (*rsc)->restart_type = pe_restart_restart; crm_debug_2("\tDependency restart handling: restart"); } else { (*rsc)->restart_type = pe_restart_ignore; crm_debug_2("\tDependency restart handling: ignore"); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_MULTIPLE); if(safe_str_eq(value, "stop_only")) { (*rsc)->recovery_type = recovery_stop_only; crm_debug_2("\tMultiple running resource recovery: stop only"); } else if(safe_str_eq(value, "block")) { (*rsc)->recovery_type = recovery_block; crm_debug_2("\tMultiple running resource recovery: block"); } else { (*rsc)->recovery_type = recovery_stop_start; crm_debug_2("\tMultiple running resource recovery: stop/start"); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->stickiness = char2score(value); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->migration_threshold = char2score(value); } else if(value == NULL) { /* Make a best-effort guess at a migration threshold for people with 0.6 configs * try with underscores and hyphens, from both the resource and global defaults section */ value = g_hash_table_lookup((*rsc)->meta, "resource-failure-stickiness"); if(value == NULL) { value = g_hash_table_lookup((*rsc)->meta, "resource_failure_stickiness"); } if(value == NULL) { value = g_hash_table_lookup(data_set->config_hash, "default-resource-failure-stickiness"); } if(value == NULL) { value = g_hash_table_lookup(data_set->config_hash, "default_resource_failure_stickiness"); } if(value) { int fail_sticky = char2score(value); if(fail_sticky == -INFINITY) { (*rsc)->migration_threshold = 1; crm_info("Set a migration threshold of %d for %s based on a failure-stickiness of %s", (*rsc)->migration_threshold, (*rsc)->id, value); } else if((*rsc)->stickiness != 0 && fail_sticky != 0) { (*rsc)->migration_threshold = (*rsc)->stickiness / fail_sticky; if((*rsc)->migration_threshold < 0) { /* Make sure it's positive */ (*rsc)->migration_threshold = 0 - (*rsc)->migration_threshold; } (*rsc)->migration_threshold += 1; crm_info("Calculated a migration threshold for %s of %d based on a stickiness of %d/%s", (*rsc)->id, (*rsc)->migration_threshold, (*rsc)->stickiness, value); } } } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_FAIL_TIMEOUT); if(value != NULL) { /* call crm_get_msec() and convert back to seconds */ (*rsc)->failure_timeout = (crm_get_msec(value) / 1000); } get_target_role(*rsc, &((*rsc)->next_role)); crm_debug_2("\tDesired next state: %s", (*rsc)->next_role!=RSC_ROLE_UNKNOWN?role2text((*rsc)->next_role):"default"); if((*rsc)->fns->unpack(*rsc, data_set) == FALSE) { return FALSE; } if(is_set(data_set->flags, pe_flag_symmetric_cluster)) { resource_location(*rsc, NULL, 0, "symmetric_default", data_set); } crm_debug_2("\tAction notification: %s", is_set((*rsc)->flags, pe_rsc_notify)?"required":"not required"); if(safe_str_eq(class, "stonith")) { set_bit_inplace(data_set->flags, pe_flag_have_stonith_resource); } (*rsc)->utilization = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); unpack_instance_attributes(data_set->input, (*rsc)->xml, XML_TAG_UTILIZATION, NULL, (*rsc)->utilization, NULL, FALSE, data_set->now); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ return TRUE; } void common_update_score(resource_t *rsc, const char *id, int score) { node_t *node = NULL; node = pe_hash_table_lookup(rsc->allowed_nodes, id); if(node != NULL) { crm_debug_2("Updating score for %s on %s: %d + %d", rsc->id, id, node->weight, score); node->weight = merge_weights(node->weight, score); } if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; common_update_score(child_rsc, id, score); - ); + } } } resource_t *uber_parent(resource_t *rsc) { resource_t *parent = rsc; if(parent == NULL) { return NULL; } while(parent->parent != NULL) { parent = parent->parent; } return parent; } void common_free(resource_t *rsc) { if(rsc == NULL) { return; } crm_debug_5("Freeing %s %d", rsc->id, rsc->variant); g_list_free(rsc->rsc_cons); g_list_free(rsc->rsc_cons_lhs); g_list_free(rsc->dangling_migrations); if(rsc->parameters != NULL) { g_hash_table_destroy(rsc->parameters); } if(rsc->meta != NULL) { g_hash_table_destroy(rsc->meta); } if(rsc->utilization != NULL) { g_hash_table_destroy(rsc->utilization); } if(rsc->parent == NULL && is_set(rsc->flags, pe_rsc_orphan)) { free_xml(rsc->xml); } if(rsc->running_on) { g_list_free(rsc->running_on); rsc->running_on = NULL; } if(rsc->known_on) { g_hash_table_destroy(rsc->known_on); rsc->known_on = NULL; } if(rsc->actions) { g_list_free(rsc->actions); rsc->actions = NULL; } if(rsc->allowed_nodes) { g_hash_table_destroy(rsc->allowed_nodes); rsc->allowed_nodes = NULL; } pe_free_shallow_adv(rsc->rsc_location, FALSE); crm_free(rsc->id); crm_free(rsc->long_name); crm_free(rsc->clone_name); crm_free(rsc->allocated_to); crm_free(rsc->variant_opaque); crm_free(rsc); crm_debug_5("Resource freed"); } diff --git a/lib/pengine/group.c b/lib/pengine/group.c index 42245bc215..31363ec8dc 100644 --- a/lib/pengine/group.c +++ b/lib/pengine/group.c @@ -1,221 +1,223 @@ /* * 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 #define VARIANT_GROUP 1 #include "./variant.h" gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set) { resource_t *self = NULL; xmlNode *xml_obj = rsc->xml; xmlNode *xml_self = copy_xml(rsc->xml); group_variant_data_t *group_data = NULL; const char *group_ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *group_colocated = g_hash_table_lookup( rsc->meta, "collocated"); const char *clone_id = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(group_data, sizeof(group_variant_data_t)); group_data->num_children = 0; group_data->self = NULL; group_data->first_child = NULL; group_data->last_child = NULL; rsc->variant_opaque = group_data; group_data->ordered = TRUE; group_data->colocated = TRUE; if(group_ordered != NULL) { crm_str_to_boolean(group_ordered, &(group_data->ordered)); } if(group_colocated != NULL) { crm_str_to_boolean(group_colocated, &(group_data->colocated)); } /* this is a bit of a hack - but simplifies everything else */ xmlNodeSetName(xml_self, ((const xmlChar*)XML_CIB_TAG_RESOURCE)); if(common_unpack(xml_self, &self, NULL, data_set)) { group_data->self = self; self->restart_type = pe_restart_restart; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return FALSE; } clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION); xml_child_iter_filter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id); if(common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } group_data->num_children++; rsc->children = g_list_append(rsc->children, new_rsc); if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } group_data->last_child = new_rsc; print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); ); if(group_data->num_children == 0) { #if 0 /* Bug #1287 */ crm_config_err("Group %s did not have any children", rsc->id); return FALSE; #else crm_config_warn("Group %s did not have any children", rsc->id); return TRUE; #endif } crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id); return TRUE; } gboolean group_active(resource_t *rsc, gboolean all) { - gboolean c_all = TRUE; - gboolean c_any = FALSE; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - if(child_rsc->fns->active(child_rsc, all)) { - c_any = TRUE; - } else { - c_all = FALSE; - } - ); - - if(c_any == FALSE) { - return FALSE; - } else if(all && c_all == FALSE) { - return FALSE; + gboolean c_all = TRUE; + gboolean c_any = FALSE; + GListPtr gIter = rsc->children; + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + + if(child_rsc->fns->active(child_rsc, all)) { + c_any = TRUE; + } else { + c_all = FALSE; } - return TRUE; + } + + if(c_any == FALSE) { + return FALSE; + } else if(all && c_all == FALSE) { + return FALSE; + } + return TRUE; } void group_print( - resource_t *rsc, const char *pre_text, long options, void *print_data) + resource_t *rsc, const char *pre_text, long options, void *print_data) { - char *child_text = NULL; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); + char *child_text = NULL; + GListPtr gIter = rsc->children; - if(pre_text == NULL) { pre_text = " "; } - child_text = crm_concat(pre_text, " ", ' '); + if(pre_text == NULL) { pre_text = " "; } + child_text = crm_concat(pre_text, " ", ' '); - status_print("%sResource Group: %s", - pre_text?pre_text:"", rsc->id); + status_print("%sResource Group: %s", + pre_text?pre_text:"", rsc->id); - if(options & pe_print_html) { - status_print("\n
      \n"); + if(options & pe_print_html) { + status_print("\n
        \n"); - } else if((options & pe_print_log) == 0) { - status_print("\n"); - } + } else if((options & pe_print_log) == 0) { + status_print("\n"); + } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - if(options & pe_print_html) { - status_print("
      • \n"); - } - child_rsc->fns->print( - child_rsc, child_text, options, print_data); - if(options & pe_print_html) { - status_print("
      • \n"); - } - ); - if(options & pe_print_html) { - status_print("
      \n"); + status_print("
    • \n"); } - crm_free(child_text); + child_rsc->fns->print( + child_rsc, child_text, options, print_data); + if(options & pe_print_html) { + status_print("
    • \n"); + } + } + + if(options & pe_print_html) { + status_print("
    \n"); + } + crm_free(child_text); } void group_free(resource_t *rsc) { - group_variant_data_t *group_data = NULL; - CRM_CHECK(rsc != NULL, return); - get_group_variant_data(group_data, rsc); + GListPtr gIter = rsc->children; + group_variant_data_t *group_data = NULL; + CRM_CHECK(rsc != NULL, return); + get_group_variant_data(group_data, rsc); - crm_debug_3("Freeing %s", rsc->id); + crm_debug_3("Freeing %s", rsc->id); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - crm_debug_3("Freeing child %s", child_rsc->id); - child_rsc->fns->free(child_rsc); - ); + crm_debug_3("Freeing child %s", child_rsc->id); + child_rsc->fns->free(child_rsc); + } - crm_debug_3("Freeing child list"); - pe_free_shallow_adv(rsc->children, FALSE); + crm_debug_3("Freeing child list"); + pe_free_shallow_adv(rsc->children, FALSE); - if(group_data->self != NULL) { - free_xml(group_data->self->xml); - group_data->self->fns->free(group_data->self); - } + if(group_data->self != NULL) { + free_xml(group_data->self->xml); + group_data->self->fns->free(group_data->self); + } - common_free(rsc); + common_free(rsc); } enum rsc_role_e group_resource_state(const resource_t *rsc, gboolean current) { - enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; + enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; + GListPtr gIter = rsc->children; - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - enum rsc_role_e role = child_rsc->fns->state(child_rsc, current); - if(role > group_role) { - group_role = role; - } - ); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + enum rsc_role_e role = child_rsc->fns->state(child_rsc, current); + + if(role > group_role) { + group_role = role; + } + } - crm_debug_3("%s role: %s", rsc->id, role2text(group_role)); - return group_role; + crm_debug_3("%s role: %s", rsc->id, role2text(group_role)); + return group_role; } diff --git a/lib/pengine/native.c b/lib/pengine/native.c index 6993d3fe3c..ed66991d05 100644 --- a/lib/pengine/native.c +++ b/lib/pengine/native.c @@ -1,466 +1,486 @@ /* * 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 #define VARIANT_NATIVE 1 #include "./variant.h" void native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { - CRM_CHECK(node != NULL, return); + GListPtr gIter = rsc->running_on; + 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; - } - ); + for(; gIter != NULL; gIter = gIter->next) { + node_t *a_node = (node_t*)gIter->data; + + CRM_CHECK(a_node != NULL, return); + if(safe_str_eq(a_node->details->id, node->details->id)) { + return; + } + } - crm_debug_3("Adding %s to %s", rsc->id, node->details->uname); + crm_debug_3("Adding %s to %s", rsc->id, node->details->uname); - 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); - } + 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(is_not_set(rsc->flags, pe_rsc_managed)) { - crm_info("resource %s isnt managed", rsc->id); - resource_location(rsc, node, INFINITY, - "not_managed_default", data_set); - return; - } + if(is_not_set(rsc->flags, pe_rsc_managed)) { + crm_info("resource %s isnt managed", rsc->id); + resource_location(rsc, node, INFINITY, + "not_managed_default", data_set); + return; + } - 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); + 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 anyone gets it right - * at the moment and this way they might notice - */ - pe_proc_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_WARNING, "See %s for more information.", - "http://clusterlabs.org/wiki/FAQ#Resource_is_Too_Active"); + /* these are errors because hardly anyone gets it right + * at the moment and this way they might notice + */ + pe_proc_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_WARNING, "See %s for more information.", + "http://clusterlabs.org/wiki/FAQ#Resource_is_Too_Active"); - if(rsc->recovery_type == recovery_stop_only) { - GHashTableIter iter; - node_t *node = NULL; - crm_debug("Making sure %s doesn't come up again", rsc->id); - /* make sure it doesnt come up again */ - g_hash_table_destroy(rsc->allowed_nodes); /* TODO: Free contents */ - rsc->allowed_nodes = node_hash_from_list(data_set->nodes); - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - node->weight = -INFINITY; - } + if(rsc->recovery_type == recovery_stop_only) { + GHashTableIter iter; + node_t *node = NULL; + crm_debug("Making sure %s doesn't come up again", rsc->id); + /* make sure it doesnt come up again */ + g_hash_table_destroy(rsc->allowed_nodes); /* TODO: Free contents */ + rsc->allowed_nodes = node_hash_from_list(data_set->nodes); + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + node->weight = -INFINITY; + } - } else if(rsc->recovery_type == recovery_block) { - clear_bit(rsc->flags, pe_rsc_managed); - } - - } else { - crm_debug_3("Resource %s is active on: %s", - rsc->id, node->details->uname); + } else if(rsc->recovery_type == recovery_block) { + clear_bit(rsc->flags, pe_rsc_managed); } + + } else { + crm_debug_3("Resource %s is active on: %s", + rsc->id, node->details->uname); + } - if(rsc->parent != NULL) { - native_add_running(rsc->parent, node, data_set); - } + if(rsc->parent != NULL) { + native_add_running(rsc->parent, node, data_set); + } } extern void force_non_unique_clone(resource_t *rsc, const char *rid, pe_working_set_t *data_set); gboolean 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)); if(is_set(rsc->flags, pe_rsc_unique) && rsc->parent) { const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(safe_str_eq(class, "lsb")) { resource_t *top = uber_parent(rsc); force_non_unique_clone(top, rsc->id, data_set); } } rsc->variant_opaque = native_data; return TRUE; } resource_t * native_find_rsc( resource_t *rsc, const char *id, gboolean renamed_clones, gboolean partial, node_t *on_node, gboolean current) { gboolean match = FALSE; resource_t *result = NULL; + GListPtr gIter = rsc->children; if(id == NULL) { return NULL; } if(partial) { if(strstr(rsc->id, id) == rsc->id) { match = TRUE; } else if(rsc->long_name && strstr(rsc->long_name, id) == rsc->long_name) { match = TRUE; } else if(renamed_clones && rsc->clone_name && strstr(rsc->clone_name, id) == rsc->clone_name) { match = TRUE; } } else { if(strcmp(rsc->id, id) == 0){ match = TRUE; } else if(rsc->long_name && strcmp(rsc->long_name, id) == 0) { match = TRUE; } else if(renamed_clones && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) { match = TRUE; } } if(match && on_node) { if(current && rsc->running_on) { - slist_iter(loc, node_t, rsc->running_on, lpc, - if(loc->details == on_node->details) { - return rsc; - }); + + GListPtr gIter = rsc->running_on; + for(; gIter != NULL; gIter = gIter->next) { + node_t *loc = (node_t*)gIter->data; + + if(loc->details == on_node->details) { + return rsc; + } + } } else if(current == FALSE && rsc->allocated_to->details == on_node->details) { return rsc; } } else if(match) { - return rsc; + return rsc; } - if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - result = rsc->fns->find_rsc(child, id, renamed_clones, partial, on_node, current); - if(result) { - return result; - } - ); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + + result = rsc->fns->find_rsc(child, id, renamed_clones, partial, on_node, current); + if(result) { + return result; + } } return NULL; } 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; GHashTable *hash = rsc->parameters; GHashTable *local_hash = NULL; CRM_CHECK(rsc != NULL, return NULL); CRM_CHECK(name != NULL && strlen(name) != 0, return NULL); crm_debug_2("Looking up %s in %s", name, rsc->id); if(create || g_hash_table_size(rsc->parameters) == 0) { 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); get_rsc_attributes(local_hash, rsc, node, data_set); hash = local_hash; } value = g_hash_table_lookup(hash, name); if(value == NULL) { /* try meta attributes instead */ value = g_hash_table_lookup(rsc->meta, name); } if(value != NULL) { value_copy = crm_strdup(value); } if(local_hash != NULL) { g_hash_table_destroy(local_hash); } return value_copy; } 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; - } - ); + GListPtr gIter = rsc->running_on; + for(; gIter != NULL; gIter = gIter->next) { + node_t *a_node = (node_t*)gIter->data; + + + 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; + 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 = NULL; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(pre_text == NULL && (options & pe_print_printf)) { pre_text = " "; } if(safe_str_eq(class, "ocf")) { 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(is_not_set(rsc->flags, pe_rsc_managed)) { status_print(""); } else if(is_set(rsc->flags, pe_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\t(%s%s%s:%s%s) %s %s%s%s%s", pre_text?pre_text:"", rsc->id, class, prov?"::":"", prov?prov:"", crm_element_value(rsc->xml, XML_ATTR_TYPE), is_set(rsc->flags, pe_rsc_orphan)?" ORPHANED":"", (rsc->variant!=pe_native)?"":role2text(rsc->role), is_set(rsc->flags, pe_rsc_managed)?"":" (unmanaged)", is_set(rsc->flags, pe_rsc_failed)?" FAILED":"", desc?": ":"", desc?desc:""); } else { status_print("%s%s\t(%s%s%s:%s):\t%s%s %s%s%s", pre_text?pre_text:"", rsc->id, class, prov?"::":"", prov?prov:"", crm_element_value(rsc->xml, XML_ATTR_TYPE), is_set(rsc->flags, pe_rsc_orphan)?" ORPHANED ":"", (rsc->variant!=pe_native)?"":role2text(rsc->role), (rsc->variant!=pe_native)?"":node!=NULL?node->details->uname:"", is_set(rsc->flags, pe_rsc_managed)?"":" (unmanaged)", is_set(rsc->flags, pe_rsc_failed)?" FAILED":""); #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) { + GListPtr gIter = rsc->running_on; + int counter = 0; + 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"); - - } - ); + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + counter++; + + 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", counter, 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_suppres_nl) { /* nothing */ } 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) { GHashTableIter iter; node_t *node = NULL; status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text, is_set(rsc->flags, pe_rsc_provisional)?"provisional, ":"", is_set(rsc->flags, pe_rsc_runnable)?"":"non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); status_print("%s\tAllowed Nodes", pre_text); g_hash_table_iter_init (&iter, rsc->allowed_nodes); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { status_print("%s\t * %s %d", pre_text, node->details->uname, node->weight); } } if(options & pe_print_max_details) { GHashTableIter iter; node_t *node = NULL; status_print("%s\t=== Allowed Nodes\n", pre_text); g_hash_table_iter_init (&iter, rsc->allowed_nodes); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { print_node("\t", node, FALSE); } } } void native_free(resource_t *rsc) { crm_debug_4("Freeing resource action list (not the data)"); common_free(rsc); } enum rsc_role_e native_resource_state(const resource_t *rsc, gboolean current) { enum rsc_role_e role = rsc->next_role; if(current) { role = rsc->role; } crm_debug_4("%s state: %s", rsc->id, role2text(role)); return role; } node_t *native_location(resource_t *rsc, GListPtr *list, gboolean current) { node_t *one = NULL; GListPtr result = NULL; if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - child->fns->location(child, &result, current); - ); + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + child->fns->location(child, &result, current); + } + } else if(current && rsc->running_on) { result = g_list_copy(rsc->running_on); } else if(current == FALSE && rsc->allocated_to) { result = g_list_append(NULL, rsc->allocated_to); } if(result && g_list_length(result) == 1) { one = g_list_nth_data(result, 0); } if(list) { - slist_iter(node, node_t, result, lpc, - if(*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) { - *list = g_list_append(*list, node); - } - ); + GListPtr gIter = result; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + if(*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) { + *list = g_list_append(*list, node); + } + } } g_list_free(result); return one; } diff --git a/lib/pengine/status.c b/lib/pengine/status.c index ae68d5577b..1f1c2e3253 100644 --- a/lib/pengine/status.c +++ b/lib/pengine/status.c @@ -1,282 +1,286 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include extern xmlNode*get_object_root( const char *object_type, xmlNode *the_root); #define MEMCHECK_STAGE_0 0 #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependencies on other resources) * - A list of constraints between resources and nodes * - A list of constraints between start/stop actions * - A list of nodes that need to be stonith'd * - A list of nodes that need to be shutdown * - A list of the possible stop/start actions (without dependencies) */ gboolean cluster_status(pe_working_set_t *data_set) { xmlNode * config = get_object_root( XML_CIB_TAG_CRMCONFIG, data_set->input); xmlNode * cib_nodes = get_object_root( XML_CIB_TAG_NODES, data_set->input); xmlNode * cib_resources = get_object_root( XML_CIB_TAG_RESOURCES, data_set->input); xmlNode * cib_status = get_object_root( XML_CIB_TAG_STATUS, data_set->input); xmlNode * cib_domains = get_object_root( XML_CIB_TAG_DOMAINS, data_set->input); const char *value = crm_element_value( data_set->input, XML_ATTR_HAVE_QUORUM); crm_debug_3("Beginning unpack"); pe_dataset = data_set; /* reset remaining global variables */ data_set->failed = create_xml_node(NULL, "failed-ops"); if(data_set->input == NULL) { return FALSE; } if(data_set->now == NULL) { data_set->now = new_ha_date(TRUE); } if(data_set->input != NULL && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) { /* this should always be present */ data_set->dc_uuid = crm_element_value_copy( data_set->input, XML_ATTR_DC_UUID); } clear_bit_inplace(data_set->flags, pe_flag_have_quorum); if(crm_is_true(value)) { set_bit_inplace(data_set->flags, pe_flag_have_quorum); } data_set->op_defaults = get_object_root(XML_CIB_TAG_OPCONFIG, data_set->input); data_set->rsc_defaults = get_object_root(XML_CIB_TAG_RSCCONFIG, data_set->input); unpack_config(config, data_set); if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE && data_set->no_quorum_policy != no_quorum_ignore) { crm_warn("We do not have quorum" " - fencing and resource management disabled"); } unpack_nodes(cib_nodes, data_set); unpack_domains(cib_domains, data_set); unpack_resources(cib_resources, data_set); unpack_status(cib_status, data_set); set_bit_inplace(data_set->flags, pe_flag_have_status); return TRUE; } static void pe_free_resources(GListPtr resources) { resource_t *rsc = NULL; GListPtr iterator = resources; while(iterator != NULL) { iterator = iterator; rsc = (resource_t *)iterator->data; iterator = iterator->next; rsc->fns->free(rsc); } if(resources != NULL) { g_list_free(resources); } } static void pe_free_actions(GListPtr actions) { GListPtr iterator = actions; while(iterator != NULL) { pe_free_action(iterator->data); iterator = iterator->next; } if(actions != NULL) { g_list_free(actions); } } static void pe_free_nodes(GListPtr nodes) { GListPtr iterator = nodes; while(iterator != NULL) { node_t *node = (node_t*)iterator->data; struct node_shared_s *details = node->details; iterator = iterator->next; crm_debug_5("deleting node"); crm_debug_5("%s is being deleted", details->uname); print_node("delete", node, FALSE); if(details != NULL) { if(details->attrs != NULL) { g_hash_table_destroy(details->attrs); } if(details->utilization != NULL) { g_hash_table_destroy(details->utilization); } pe_free_shallow_adv(details->running_rsc, FALSE); pe_free_shallow_adv(details->allocated_rsc, FALSE); crm_free(details); } crm_free(node); } if(nodes != NULL) { g_list_free(nodes); } } void cleanup_calculations(pe_working_set_t *data_set) { pe_dataset = NULL; if(data_set == NULL) { return; } clear_bit_inplace(data_set->flags, pe_flag_have_status); if(data_set->config_hash != NULL) { g_hash_table_destroy(data_set->config_hash); } crm_free(data_set->dc_uuid); crm_debug_3("deleting resources"); pe_free_resources(data_set->resources); crm_debug_3("deleting actions"); pe_free_actions(data_set->actions); if(data_set->domains) { g_hash_table_destroy(data_set->domains); } crm_debug_3("deleting nodes"); pe_free_nodes(data_set->nodes); free_xml(data_set->graph); free_ha_date(data_set->now); free_xml(data_set->input); free_xml(data_set->failed); set_working_set_defaults(data_set); CRM_CHECK(data_set->ordering_constraints == NULL, ;); CRM_CHECK(data_set->placement_constraints == NULL, ;); xmlCleanupParser(); } void set_working_set_defaults(pe_working_set_t *data_set) { pe_dataset = data_set; memset(data_set, 0, sizeof(pe_working_set_t)); data_set->order_id = 1; data_set->action_id = 1; data_set->no_quorum_policy = no_quorum_freeze; data_set->flags = 0x0ULL; set_bit_inplace(data_set->flags, pe_flag_stop_rsc_orphans); set_bit_inplace(data_set->flags, pe_flag_symmetric_cluster); set_bit_inplace(data_set->flags, pe_flag_is_managed_default); set_bit_inplace(data_set->flags, pe_flag_stop_action_orphans); } resource_t * pe_find_resource(GListPtr rsc_list, const char *id) { unsigned lpc = 0; resource_t *rsc = NULL; resource_t *match = NULL; if(id == NULL) { return NULL; } for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); match = rsc->fns->find_rsc(rsc, id, TRUE, FALSE, NULL, TRUE); if(match != NULL) { return match; } } crm_debug_2("No match for %s", id); return NULL; } node_t * pe_find_node_id(GListPtr nodes, const char *id) { - slist_iter(node, node_t, nodes, lpc, - if(node && safe_str_eq(node->details->id, id)) { - return node; - } - ); + GListPtr gIter = nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + if(node && safe_str_eq(node->details->id, id)) { + return node; + } + } /* error */ return NULL; } node_t * pe_find_node(GListPtr nodes, const char *uname) { - slist_iter(node, node_t, nodes, lpc, - if(node && safe_str_eq(node->details->uname, uname)) { - return node; - } - ); + GListPtr gIter = nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + if(node && safe_str_eq(node->details->uname, uname)) { + return node; + } + } /* error */ return NULL; } diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index 0b2a395571..2e26d3a9a2 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -1,1998 +1,2025 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include CRM_TRACE_INIT_DATA(pe_status); #define set_config_flag(data_set, option, flag) do { \ const char *tmp = pe_pref(data_set->config_hash, option); \ if(tmp) { \ if(crm_is_true(tmp)) { \ set_bit_inplace(data_set->flags, flag); \ } else { \ clear_bit_inplace(data_set->flags, flag); \ } \ } \ } while(0) gboolean unpack_rsc_op( resource_t *rsc, node_t *node, xmlNode *xml_op, GListPtr next, enum action_fail_response *failed, pe_working_set_t *data_set); static void pe_fence_node(pe_working_set_t *data_set, node_t *node, const char *reason) { CRM_CHECK(node, return); if(node->details->unclean == FALSE) { if(is_set(data_set->flags, pe_flag_stonith_enabled)) { crm_warn("Node %s will be fenced %s", node->details->uname, reason); } else { crm_warn("Node %s is unclean %s", node->details->uname, reason); } } node->details->unclean = TRUE; } gboolean unpack_config(xmlNode *config, pe_working_set_t *data_set) { const char *value = NULL; GHashTable *config_hash = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); data_set->config_hash = config_hash; unpack_instance_attributes( data_set->input, config, XML_CIB_TAG_PROPSET, NULL, config_hash, CIB_OPTIONS_FIRST, FALSE, data_set->now); verify_pe_options(data_set->config_hash); set_config_flag(data_set, "enable-startup-probes", pe_flag_startup_probes); crm_info("Startup probes: %s", is_set(data_set->flags, pe_flag_startup_probes)?"enabled":"disabled (dangerous)"); value = pe_pref(data_set->config_hash, "stonith-timeout"); data_set->stonith_timeout = crm_get_msec(value); crm_debug("STONITH timeout: %d", data_set->stonith_timeout); set_config_flag(data_set, "stonith-enabled", pe_flag_stonith_enabled); crm_debug("STONITH of failed nodes is %s", is_set(data_set->flags, pe_flag_stonith_enabled)?"enabled":"disabled"); data_set->stonith_action = pe_pref(data_set->config_hash, "stonith-action"); crm_debug_2("STONITH will %s nodes", data_set->stonith_action); set_config_flag(data_set, "stop-all-resources", pe_flag_stop_everything); crm_debug("Stop all active resources: %s", is_set(data_set->flags, pe_flag_stop_everything)?"true":"false"); set_config_flag(data_set, "symmetric-cluster", pe_flag_symmetric_cluster); if(is_set(data_set->flags, pe_flag_symmetric_cluster)) { crm_debug("Cluster is symmetric" " - resources can run anywhere by default"); } value = pe_pref(data_set->config_hash, "default-resource-stickiness"); data_set->default_resource_stickiness = char2score(value); crm_debug("Default stickiness: %d", data_set->default_resource_stickiness); value = pe_pref(data_set->config_hash, "no-quorum-policy"); if(safe_str_eq(value, "ignore")) { data_set->no_quorum_policy = no_quorum_ignore; } else if(safe_str_eq(value, "freeze")) { data_set->no_quorum_policy = no_quorum_freeze; } else if(safe_str_eq(value, "suicide")) { gboolean do_panic = FALSE; crm_element_value_int(data_set->input, XML_ATTR_QUORUM_PANIC, &do_panic); if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE){ crm_config_err("Setting no-quorum-policy=suicide makes no sense if stonith-enabled=false"); } if(do_panic && is_set(data_set->flags, pe_flag_stonith_enabled)) { data_set->no_quorum_policy = no_quorum_suicide; } else if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE && do_panic == FALSE) { crm_notice("Resetting no-quorum-policy to 'stop': The cluster has never had quorum"); data_set->no_quorum_policy = no_quorum_stop; } } else { data_set->no_quorum_policy = no_quorum_stop; } switch (data_set->no_quorum_policy) { case no_quorum_freeze: crm_debug("On loss of CCM Quorum: Freeze resources"); break; case no_quorum_stop: crm_debug("On loss of CCM Quorum: Stop ALL resources"); break; case no_quorum_suicide: crm_notice("On loss of CCM Quorum: Fence all remaining nodes"); break; case no_quorum_ignore: crm_notice("On loss of CCM Quorum: Ignore"); break; } set_config_flag(data_set, "stop-orphan-resources", pe_flag_stop_rsc_orphans); crm_debug_2("Orphan resources are %s", is_set(data_set->flags, pe_flag_stop_rsc_orphans)?"stopped":"ignored"); set_config_flag(data_set, "stop-orphan-actions", pe_flag_stop_action_orphans); crm_debug_2("Orphan resource actions are %s", is_set(data_set->flags, pe_flag_stop_action_orphans)?"stopped":"ignored"); set_config_flag(data_set, "remove-after-stop", pe_flag_remove_after_stop); crm_debug_2("Stopped resources are removed from the status section: %s", is_set(data_set->flags, pe_flag_remove_after_stop)?"true":"false"); set_config_flag(data_set, "maintenance-mode", pe_flag_maintenance_mode); crm_debug_2("Maintenance mode: %s", is_set(data_set->flags, pe_flag_maintenance_mode)?"true":"false"); if(is_set(data_set->flags, pe_flag_maintenance_mode)) { clear_bit(data_set->flags, pe_flag_is_managed_default); } else { set_config_flag(data_set, "is-managed-default", pe_flag_is_managed_default); } crm_debug_2("By default resources are %smanaged", is_set(data_set->flags, pe_flag_is_managed_default)?"":"not "); set_config_flag(data_set, "start-failure-is-fatal", pe_flag_start_failure_fatal); crm_debug_2("Start failures are %s", is_set(data_set->flags, pe_flag_start_failure_fatal)?"always fatal":"handled by failcount"); node_score_red = char2score(pe_pref(data_set->config_hash, "node-health-red")); node_score_green = char2score(pe_pref(data_set->config_hash, "node-health-green")); node_score_yellow = char2score(pe_pref(data_set->config_hash, "node-health-yellow")); crm_info("Node scores: 'red' = %s, 'yellow' = %s, 'green' = %s", pe_pref(data_set->config_hash, "node-health-red"), pe_pref(data_set->config_hash, "node-health-yellow"), pe_pref(data_set->config_hash, "node-health-green")); data_set->placement_strategy = pe_pref(data_set->config_hash, "placement-strategy"); crm_debug_2("Placement strategy: %s", data_set->placement_strategy); return TRUE; } gboolean unpack_nodes(xmlNode * xml_nodes, pe_working_set_t *data_set) { node_t *new_node = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; const char *score = NULL; gboolean unseen_are_unclean = TRUE; const char *blind_faith = pe_pref( data_set->config_hash, "startup-fencing"); if(crm_is_true(blind_faith) == FALSE) { unseen_are_unclean = FALSE; crm_warn("Blind faith: not fencing unseen nodes"); } xml_child_iter_filter( xml_nodes, xml_obj, XML_CIB_TAG_NODE, new_node = NULL; id = crm_element_value(xml_obj, XML_ATTR_ID); uname = crm_element_value(xml_obj, XML_ATTR_UNAME); type = crm_element_value(xml_obj, XML_ATTR_TYPE); score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); crm_debug_3("Processing node %s/%s", uname, id); if(id == NULL) { crm_config_err("Must specify id tag in "); continue; } if(type == NULL) { crm_config_err("Must specify type tag in "); continue; } if(pe_find_node(data_set->nodes, uname) != NULL) { crm_config_warn("Detected multiple node entries with uname=%s" " - this is rarely intended", uname); } crm_malloc0(new_node, sizeof(node_t)); if(new_node == NULL) { return FALSE; } new_node->weight = char2score(score); new_node->fixed = FALSE; crm_malloc0(new_node->details, sizeof(struct node_shared_s)); if(new_node->details == NULL) { crm_free(new_node); return FALSE; } crm_debug_3("Creaing node for entry %s/%s", uname, id); new_node->details->id = id; new_node->details->uname = uname; new_node->details->type = node_ping; new_node->details->online = FALSE; new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->attrs = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); new_node->details->utilization = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); /* if(data_set->have_quorum == FALSE */ /* && data_set->no_quorum_policy == no_quorum_stop) { */ /* /\* start shutting resources down *\/ */ /* new_node->weight = -INFINITY; */ /* } */ if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE || unseen_are_unclean == FALSE) { /* blind faith... */ new_node->details->unclean = FALSE; } else { /* all nodes are unclean until we've seen their * status entry */ new_node->details->unclean = TRUE; } if(type == NULL || safe_str_eq(type, "member") || safe_str_eq(type, NORMALNODE)) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node, FALSE, data_set); unpack_instance_attributes( data_set->input, xml_obj, XML_TAG_UTILIZATION, NULL, new_node->details->utilization, NULL, FALSE, data_set->now); data_set->nodes = g_list_append(data_set->nodes, new_node); crm_debug_3("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); ); return TRUE; } static void g_hash_destroy_node_list(gpointer data) { GListPtr domain = data; slist_destroy(node_t, node, domain, crm_free(node)); } gboolean unpack_domains(xmlNode *xml_domains, pe_working_set_t *data_set) { GListPtr domain = NULL; const char *id = NULL; crm_info("Unpacking domains"); data_set->domains = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_node_list); xml_child_iter_filter( xml_domains, xml_domain, XML_CIB_TAG_DOMAIN, domain = NULL; id = crm_element_value(xml_domain, XML_ATTR_ID); xml_child_iter_filter( xml_domain, xml_node, XML_CIB_TAG_NODE, node_t *copy = NULL; node_t *node = NULL; const char *uname = crm_element_value(xml_node, "name"); const char *score = crm_element_value(xml_node, XML_RULE_ATTR_SCORE); if(uname == NULL) { crm_config_err("Invalid domain %s: Must specify id tag in ", id); continue; } node = pe_find_node(data_set->nodes, uname); if(node == NULL) { node = pe_find_node_id(data_set->nodes, uname); } if(node == NULL) { crm_config_warn("Invalid domain %s: Node %s does not exist", id, uname); continue; } copy = node_copy(node); copy->weight = char2score(score); crm_debug("Adding %s to domain %s with score %s", node->details->uname, id, score); domain = g_list_prepend(domain, copy); ); if(domain) { crm_debug("Created domain %s with %d members", id, g_list_length(domain)); g_hash_table_replace(data_set->domains, crm_strdup(id), domain); } ); return TRUE; } gboolean unpack_resources(xmlNode * xml_resources, pe_working_set_t *data_set) { xml_child_iter( xml_resources, xml_obj, resource_t *new_rsc = NULL; crm_debug_3("Beginning unpack... <%s id=%s... >", crm_element_name(xml_obj), ID(xml_obj)); if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) { data_set->resources = g_list_append( data_set->resources, new_rsc); print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); } else { crm_config_err("Failed unpacking %s %s", crm_element_name(xml_obj), crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } ); data_set->resources = g_list_sort( data_set->resources, sort_rsc_priority); if(is_set(data_set->flags, pe_flag_stonith_enabled) && is_set(data_set->flags, pe_flag_have_stonith_resource) == FALSE) { crm_config_err("Resource start-up disabled since no STONITH resources have been defined"); crm_config_err("Either configure some or disable STONITH with the stonith-enabled option"); crm_config_err("NOTE: Clusters with shared data need STONITH to ensure data integrity"); } return TRUE; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean unpack_status(xmlNode * status, pe_working_set_t *data_set) { const char *id = NULL; const char *uname = NULL; xmlNode * lrm_rsc = NULL; xmlNode * attrs = NULL; node_t *this_node = NULL; crm_debug_3("Beginning unpack"); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); uname = crm_element_value(node_state, XML_ATTR_UNAME); attrs = find_xml_node(node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); crm_debug_3("Processing node id=%s, uname=%s", id, uname); this_node = pe_find_node_id(data_set->nodes, id); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { crm_config_warn("Node %s in status section no longer exists", uname); continue; } /* Mark the node as provisionally clean * - at least we have seen it in the current cluster's lifetime */ this_node->details->unclean = FALSE; add_node_attrs(attrs, this_node, TRUE, data_set); if(crm_is_true(g_hash_table_lookup(this_node->details->attrs, "standby"))) { crm_info("Node %s is in standby-mode", this_node->details->uname); this_node->details->standby = TRUE; } crm_debug_3("determining node state"); determine_online_status(node_state, this_node, data_set); if(this_node->details->online && data_set->no_quorum_policy == no_quorum_suicide) { /* Everything else should flow from this automatically * At least until the PE becomes able to migrate off healthy resources */ pe_fence_node(data_set, this_node, "because the cluster does not have quorum"); } ); /* Split into two phases so that we know all node states before we hit migration ops */ xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_debug_3("Processing lrm operations on node %s", id); this_node = pe_find_node_id(data_set->nodes, id); if(this_node->details->online || is_set(data_set->flags, pe_flag_stonith_enabled)) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ crm_debug_3("Processing lrm resource entries"); unpack_lrm_resources(this_node, lrm_rsc, data_set); } ); return TRUE; } static gboolean determine_online_status_no_fencing(pe_working_set_t *data_set, xmlNode * node_state, node_t *this_node) { gboolean online = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(ha_state == NULL) { ha_state = DEADSTATUS; } if(!crm_is_true(ccm_state) || safe_str_eq(ha_state, DEADSTATUS)){ crm_debug_2("Node is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); } else if(safe_str_eq(crm_state, ONLINESTATUS)) { if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { online = TRUE; } else { crm_debug("Node is not ready to run resources: %s", join_state); } } else if(this_node->details->expected_up == FALSE) { crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ pe_fence_node(data_set, this_node, "because it is partially and/or un-expectedly down"); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } static gboolean determine_online_status_fencing(pe_working_set_t *data_set, xmlNode * node_state, node_t *this_node) { gboolean online = FALSE; gboolean do_terminate = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); const char *terminate = g_hash_table_lookup(this_node->details->attrs, "terminate"); if(ha_state == NULL) { ha_state = DEADSTATUS; } if(crm_is_true(terminate)) { do_terminate = TRUE; } else if(terminate != NULL && strlen(terminate) > 0) { /* could be a time() value */ char t = terminate[0]; if(t != '0' && isdigit(t)) { do_terminate = TRUE; } } if(crm_is_true(ccm_state) && safe_str_eq(ha_state, ACTIVESTATUS) && safe_str_eq(crm_state, ONLINESTATUS)) { if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { online = TRUE; if(do_terminate) { pe_fence_node(data_set, this_node, "because termination was requested"); } } else if(join_state == exp_state /* == NULL */) { crm_info("Node %s is coming up", this_node->details->uname); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else if(safe_str_eq(join_state, CRMD_JOINSTATE_PENDING)) { crm_info("Node %s is not ready to run resources", this_node->details->uname); this_node->details->standby = TRUE; this_node->details->pending = TRUE; online = TRUE; } else if(safe_str_eq(join_state, CRMD_JOINSTATE_NACK)) { crm_warn("Node %s is not part of the cluster", this_node->details->uname); this_node->details->standby = TRUE; this_node->details->pending = TRUE; online = TRUE; } else if(safe_str_eq(join_state, exp_state)) { crm_info("Node %s is still coming up: %s", this_node->details->uname, join_state); crm_info("\tha_state=%s, ccm_state=%s, crm_state=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state)); this_node->details->standby = TRUE; this_node->details->pending = TRUE; online = TRUE; } else { crm_warn("Node %s (%s) is un-expectedly down", this_node->details->uname, this_node->details->id); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); pe_fence_node(data_set, this_node, "because it is un-expectedly down"); } } else if(crm_is_true(ccm_state) == FALSE && safe_str_eq(ha_state, DEADSTATUS) && safe_str_eq(crm_state, OFFLINESTATUS) && this_node->details->expected_up == FALSE) { crm_debug("Node %s is down: join_state=%s, expected=%s", this_node->details->uname, crm_str(join_state), crm_str(exp_state)); #if 0 /* While a nice optimization, it causes the cluster to block until the node * comes back online. Which is a serious problem if the cluster software * is not configured to start at boot or stonith is configured to merely * stop the node instead of restart it. * Easily triggered by setting terminate=true for the DC */ } else if(do_terminate) { crm_info("Node %s is %s after forced termination", this_node->details->uname, crm_is_true(ccm_state)?"coming up":"going down"); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); if(crm_is_true(ccm_state) == FALSE) { this_node->details->standby = TRUE; this_node->details->pending = TRUE; online = TRUE; } #endif } else if(this_node->details->expected_up) { /* mark it unclean */ pe_fence_node(data_set, this_node, "because it is un-expectedly down"); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { crm_info("Node %s is down", this_node->details->uname); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } gboolean determine_online_status( xmlNode * node_state, node_t *this_node, pe_working_set_t *data_set) { gboolean online = FALSE; const char *shutdown = NULL; const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(this_node == NULL) { crm_config_err("No node to check"); return online; } this_node->details->shutdown = FALSE; this_node->details->expected_up = FALSE; shutdown = g_hash_table_lookup(this_node->details->attrs, XML_CIB_ATTR_SHUTDOWN); if(shutdown != NULL && safe_str_neq("0", shutdown)) { this_node->details->shutdown = TRUE; } else if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) { this_node->details->expected_up = TRUE; } if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) { online = determine_online_status_no_fencing( data_set, node_state, this_node); } else { online = determine_online_status_fencing( data_set, node_state, this_node); } if(online) { this_node->details->online = TRUE; } else { /* remove node from contention */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(online && this_node->details->shutdown) { /* dont run resources here */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(this_node->details->unclean) { pe_proc_warn("Node %s is unclean", this_node->details->uname); } else if(this_node->details->online) { crm_info("Node %s is %s", this_node->details->uname, this_node->details->shutdown?"shutting down": this_node->details->pending?"pending": this_node->details->standby?"standby":"online"); } else { crm_debug_2("Node %s is offline", this_node->details->uname); } return online; } #define set_char(x) last_rsc_id[lpc] = x; complete = TRUE; char * clone_zero(const char *last_rsc_id) { int lpc = 0; char *zero = NULL; CRM_CHECK(last_rsc_id != NULL, return NULL); if(last_rsc_id != NULL) { lpc = strlen(last_rsc_id); } while(--lpc > 0) { switch(last_rsc_id[lpc]) { case 0: return NULL; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case ':': crm_malloc0(zero, lpc + 3); memcpy(zero, last_rsc_id, lpc); zero[lpc] = ':'; zero[lpc+1] = '0'; zero[lpc+2] = 0; return zero; } } return NULL; } char * increment_clone(char *last_rsc_id) { int lpc = 0; int len = 0; char *tmp = NULL; gboolean complete = FALSE; CRM_CHECK(last_rsc_id != NULL, return NULL); if(last_rsc_id != NULL) { len = strlen(last_rsc_id); } lpc = len-1; while(complete == FALSE && lpc > 0) { switch (last_rsc_id[lpc]) { case 0: lpc--; break; case '0': set_char('1'); break; case '1': set_char('2'); break; case '2': set_char('3'); break; case '3': set_char('4'); break; case '4': set_char('5'); break; case '5': set_char('6'); break; case '6': set_char('7'); break; case '7': set_char('8'); break; case '8': set_char('9'); break; case '9': last_rsc_id[lpc] = '0'; lpc--; break; case ':': tmp = last_rsc_id; crm_malloc0(last_rsc_id, len + 2); memcpy(last_rsc_id, tmp, len); last_rsc_id[++lpc] = '1'; last_rsc_id[len] = '0'; last_rsc_id[len+1] = 0; complete = TRUE; crm_free(tmp); break; default: crm_err("Unexpected char: %c (%d)", last_rsc_id[lpc], lpc); break; } } return last_rsc_id; } static resource_t * create_fake_resource(const char *rsc_id, xmlNode *rsc_entry, pe_working_set_t *data_set) { resource_t *rsc = NULL; xmlNode *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); copy_in_properties(xml_rsc, rsc_entry); crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id); crm_log_xml_debug(xml_rsc, "Orphan resource"); if(!common_unpack(xml_rsc, &rsc, NULL, data_set)) { return NULL; } set_bit(rsc->flags, pe_rsc_orphan); data_set->resources = g_list_append(data_set->resources, rsc); return rsc; } extern resource_t *create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set); static resource_t *find_clone(pe_working_set_t *data_set, node_t *node, resource_t *parent, const char *rsc_id) { int len = 0; resource_t *rsc = NULL; char *base = clone_zero(rsc_id); char *alt_rsc_id = crm_strdup(rsc_id); CRM_ASSERT(parent != NULL); CRM_ASSERT(parent->variant == pe_clone || parent->variant == pe_master); if(base) { len = strlen(base); } if(len > 0) { base[len-1] = 0; } crm_debug_3("Looking for %s on %s in %s %d", rsc_id, node->details->uname, parent->id, is_set(parent->flags, pe_rsc_unique)); if(is_set(parent->flags, pe_rsc_unique)) { crm_debug_3("Looking for %s", rsc_id); rsc = parent->fns->find_rsc(parent, rsc_id, FALSE, FALSE, NULL, TRUE); } else { rsc = parent->fns->find_rsc(parent, base, FALSE, TRUE, node, TRUE); if(rsc != NULL && rsc->running_on) { + GListPtr gIter = parent->children; rsc = NULL; crm_debug_3("Looking for an existing orphan for %s: %s on %s", parent->id, rsc_id, node->details->uname); /* There is already an instance of this _anonymous_ clone active on "node". * * If there is a partially active orphan (only applies to clone groups) on * the same node, use that. * Otherwise create a new (orphaned) instance at "orphan_check:". */ - slist_iter(child, resource_t, parent->children, lpc, - node_t *loc = child->fns->location(child, NULL, TRUE); - if(loc && loc->details == node->details) { - resource_t *tmp = child->fns->find_rsc(child, base, FALSE, TRUE, NULL, TRUE); - if(tmp && tmp->running_on == NULL) { - rsc = tmp; - break; - } - } - ); + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + node_t *loc = child->fns->location(child, NULL, TRUE); + + if(loc && loc->details == node->details) { + resource_t *tmp = child->fns->find_rsc(child, base, FALSE, TRUE, NULL, TRUE); + if(tmp && tmp->running_on == NULL) { + rsc = tmp; + break; + } + } + } goto orphan_check; } while(rsc == NULL) { crm_debug_3("Trying %s", alt_rsc_id); rsc = parent->fns->find_rsc(parent, alt_rsc_id, FALSE, FALSE, NULL, TRUE); if(rsc == NULL) { break; } else if(rsc->running_on == NULL) { break; } alt_rsc_id = increment_clone(alt_rsc_id); rsc = NULL; } } orphan_check: if(rsc == NULL) { /* Create an extra orphan */ resource_t *top = create_child_clone(parent, -1, data_set); crm_debug("Created orphan for %s: %s on %s", parent->id, rsc_id, node->details->uname); rsc = top->fns->find_rsc(top, base, FALSE, TRUE, NULL, TRUE); CRM_ASSERT(rsc != NULL); } crm_free(rsc->clone_name); rsc->clone_name = NULL; if(safe_str_neq(rsc_id, rsc->id)) { crm_info("Internally renamed %s on %s to %s%s", rsc_id, node->details->uname, rsc->id, is_set(rsc->flags, pe_rsc_orphan)?" (ORPHAN)":""); rsc->clone_name = crm_strdup(rsc_id); } crm_free(alt_rsc_id); crm_free(base); return rsc; } static resource_t * unpack_find_resource( pe_working_set_t *data_set, node_t *node, const char *rsc_id, xmlNode *rsc_entry) { resource_t *rsc = NULL; resource_t *clone_parent = NULL; char *alt_rsc_id = crm_strdup(rsc_id); crm_debug_2("looking for %s", rsc_id); rsc = pe_find_resource(data_set->resources, alt_rsc_id); /* no match */ if(rsc == NULL) { /* Even when clone-max=0, we still create a single :0 orphan to match against */ char *tmp = clone_zero(alt_rsc_id); resource_t *clone0 = pe_find_resource(data_set->resources, tmp); clone_parent = uber_parent(clone0); crm_free(tmp); crm_debug_2("%s not found: %s", alt_rsc_id, clone_parent?clone_parent->id:"orphan"); } else { clone_parent = uber_parent(rsc); } if(clone_parent && clone_parent->variant > pe_group) { rsc = find_clone(data_set, node, clone_parent, rsc_id); CRM_ASSERT(rsc != NULL); } crm_free(alt_rsc_id); return rsc; } static resource_t * process_orphan_resource(xmlNode *rsc_entry, node_t *node, pe_working_set_t *data_set) { resource_t *rsc = NULL; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); crm_debug("Detected orphan resource %s on %s", rsc_id, node->details->uname); rsc = create_fake_resource(rsc_id, rsc_entry, data_set); if(is_set(data_set->flags, pe_flag_stop_rsc_orphans) == FALSE) { clear_bit(rsc->flags, pe_rsc_managed); } else { print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE); CRM_CHECK(rsc != NULL, return NULL); resource_location(rsc, NULL, -INFINITY, "__orphan_dont_run__", data_set); } return rsc; } static void process_rsc_state(resource_t *rsc, node_t *node, enum action_fail_response on_fail, xmlNode *migrate_op, pe_working_set_t *data_set) { crm_debug_2("Resource %s is %s on %s: on_fail=%s", rsc->id, role2text(rsc->role), node->details->uname, fail2text(on_fail)); /* process current state */ if(rsc->role != RSC_ROLE_UNKNOWN) { resource_t *iter = rsc; while(iter) { if(g_hash_table_lookup(iter->known_on, node->details->id) == NULL) { node_t *n = node_copy(node); g_hash_table_insert(iter->known_on, (gpointer)n->details->id, n); } if(is_set(iter->flags, pe_rsc_unique)) { break; } iter = iter->parent; } } if(node->details->unclean) { /* No extra processing needed * Also allows resources to be started again after a node is shot */ on_fail = action_fail_ignore; } switch(on_fail) { case action_fail_ignore: /* nothing to do */ break; case action_fail_fence: /* treat it as if it is still running * but also mark the node as unclean */ pe_fence_node(data_set, node, "to recover from resource failure(s)"); break; case action_fail_standby: node->details->standby = TRUE; node->details->standby_onfail = TRUE; break; case action_fail_block: /* is_managed == FALSE will prevent any * actions being sent for the resource */ clear_bit(rsc->flags, pe_rsc_managed); break; case action_fail_migrate: /* make sure it comes up somewhere else * or not at all */ resource_location(rsc, node, -INFINITY, "__action_migration_auto__",data_set); break; case action_fail_stop: rsc->next_role = RSC_ROLE_STOPPED; break; case action_fail_recover: if(rsc->role != RSC_ROLE_STOPPED && rsc->role != RSC_ROLE_UNKNOWN) { set_bit(rsc->flags, pe_rsc_failed); stop_action(rsc, node, FALSE); } break; } if(rsc->role != RSC_ROLE_STOPPED && rsc->role != RSC_ROLE_UNKNOWN) { if(is_set(rsc->flags, pe_rsc_orphan)) { if(is_set(rsc->flags, pe_rsc_managed)) { crm_config_warn("Detected active orphan %s running on %s", rsc->id, node->details->uname); } else { crm_config_warn("Cluster configured not to stop active orphans." " %s must be stopped manually on %s", rsc->id, node->details->uname); } } native_add_running(rsc, node, data_set); if(on_fail != action_fail_ignore) { set_bit(rsc->flags, pe_rsc_failed); } } else if(rsc->clone_name) { crm_debug_2("Resetting clone_name %s for %s (stopped)", rsc->clone_name, rsc->id); crm_free(rsc->clone_name); rsc->clone_name = NULL; } else { char *key = stop_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, node); - slist_iter(stop, action_t, possible_matches, lpc, - stop->flags |= pe_action_optional; - ); + GListPtr gIter = possible_matches; + for(; gIter != NULL; gIter = gIter->next) { + action_t *stop = (action_t*)gIter->data; + stop->flags |= pe_action_optional; + } + crm_free(key); } } /* create active recurring operations as optional */ static void process_recurring(node_t *node, resource_t *rsc, int start_index, int stop_index, GListPtr sorted_op_list, pe_working_set_t *data_set) { - const char *task = NULL; - const char *status = NULL; + int counter = -1; + const char *task = NULL; + const char *status = NULL; + GListPtr gIter = sorted_op_list; - crm_debug_3("%s: Start index %d, stop index = %d", - rsc->id, start_index, stop_index); - slist_iter(rsc_op, xmlNode, sorted_op_list, lpc, - int interval = 0; - char *key = NULL; - const char *id = ID(rsc_op); - const char *interval_s = NULL; - if(node->details->online == FALSE) { - crm_debug_4("Skipping %s/%s: node is offline", - rsc->id, node->details->uname); - break; + crm_debug_3("%s: Start index %d, stop index = %d", + rsc->id, start_index, stop_index); + + for(; gIter != NULL; gIter = gIter->next) { + xmlNode *rsc_op = (xmlNode*)gIter->data; + + int interval = 0; + char *key = NULL; + const char *id = ID(rsc_op); + const char *interval_s = NULL; + counter++; + + if(node->details->online == FALSE) { + crm_debug_4("Skipping %s/%s: node is offline", + rsc->id, node->details->uname); + break; - } else if(start_index < stop_index) { - crm_debug_4("Skipping %s/%s: not active", - rsc->id, node->details->uname); - break; + } else if(start_index < stop_index) { + crm_debug_4("Skipping %s/%s: not active", + rsc->id, node->details->uname); + break; - } else if(lpc <= start_index) { - crm_debug_4("Skipping %s/%s: old", - id, node->details->uname); - continue; - } + } else if(counter <= start_index) { + crm_debug_4("Skipping %s/%s: old", + id, node->details->uname); + continue; + } - interval_s = crm_element_value(rsc_op,XML_LRM_ATTR_INTERVAL); - interval = crm_parse_int(interval_s, "0"); - if(interval == 0) { - crm_debug_4("Skipping %s/%s: non-recurring", - id, node->details->uname); - continue; - } + interval_s = crm_element_value(rsc_op,XML_LRM_ATTR_INTERVAL); + interval = crm_parse_int(interval_s, "0"); + if(interval == 0) { + crm_debug_4("Skipping %s/%s: non-recurring", + id, node->details->uname); + continue; + } - status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); - if(safe_str_eq(status, "-1")) { - crm_debug_4("Skipping %s/%s: status", - id, node->details->uname); - continue; - } - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - /* create the action */ - key = generate_op_key(rsc->id, task, interval); - crm_debug_3("Creating %s/%s", key, node->details->uname); - custom_action(rsc, key, task, node, TRUE, TRUE, data_set); - ); + status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); + if(safe_str_eq(status, "-1")) { + crm_debug_4("Skipping %s/%s: status", + id, node->details->uname); + continue; + } + task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); + /* create the action */ + key = generate_op_key(rsc->id, task, interval); + crm_debug_3("Creating %s/%s", key, node->details->uname); + custom_action(rsc, key, task, node, TRUE, TRUE, data_set); + } } void calculate_active_ops(GListPtr sorted_op_list, int *start_index, int *stop_index) { - const char *task = NULL; - const char *status = NULL; + int counter = -1; + const char *task = NULL; + const char *status = NULL; + GListPtr gIter = sorted_op_list; - *stop_index = -1; - *start_index = -1; - - slist_iter( - rsc_op, xmlNode, sorted_op_list, lpc, + *stop_index = -1; + *start_index = -1; - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); + for(; gIter != NULL; gIter = gIter->next) { + xmlNode *rsc_op = (xmlNode*)gIter->data; + counter++; + + task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); + status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); - if(safe_str_eq(task, CRMD_ACTION_STOP) - && safe_str_eq(status, "0")) { - *stop_index = lpc; + if(safe_str_eq(task, CRMD_ACTION_STOP) + && safe_str_eq(status, "0")) { + *stop_index = counter; - } else if(safe_str_eq(task, CRMD_ACTION_START)) { - *start_index = lpc; + } else if(safe_str_eq(task, CRMD_ACTION_START)) { + *start_index = counter; - } else if(*start_index <= *stop_index - && safe_str_eq(task, CRMD_ACTION_STATUS)) { - const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC); - if(safe_str_eq(rc, "0") || safe_str_eq(rc, "8")) { - *start_index = lpc; - } - } - ); + } else if(*start_index <= *stop_index + && safe_str_eq(task, CRMD_ACTION_STATUS)) { + const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC); + if(safe_str_eq(rc, "0") || safe_str_eq(rc, "8")) { + *start_index = counter; + } + } + } } static void unpack_lrm_rsc_state( node_t *node, xmlNode * rsc_entry, pe_working_set_t *data_set) { + GListPtr gIter = NULL; int stop_index = -1; int start_index = -1; enum rsc_role_e req_role = RSC_ROLE_UNKNOWN; const char *task = NULL; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); resource_t *rsc = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; xmlNode *migrate_op = NULL; enum action_fail_response on_fail = FALSE; enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN; crm_debug_3("[%s] Processing %s on %s", crm_element_name(rsc_entry), rsc_id, node->details->uname); /* extract operations */ op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_prepend(op_list, rsc_op); ); if(op_list == NULL) { /* if there are no operations, there is nothing to do */ return; } /* find the resource */ rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry); if(rsc == NULL) { rsc = process_orphan_resource(rsc_entry, node, data_set); } CRM_ASSERT(rsc != NULL); /* process operations */ saved_role = rsc->role; on_fail = action_fail_ignore; rsc->role = RSC_ROLE_UNKNOWN; sorted_op_list = g_list_sort(op_list, sort_op_by_callid); - - slist_iter( - rsc_op, xmlNode, sorted_op_list, lpc, - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) { - migrate_op = rsc_op; - } - - unpack_rsc_op(rsc, node, rsc_op, __crm_iter_head, &on_fail, data_set); - ); + + gIter = sorted_op_list; + for(; gIter != NULL; gIter = gIter->next) { + xmlNode *rsc_op = (xmlNode*)gIter->data; + + task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); + if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) { + migrate_op = rsc_op; + } + + unpack_rsc_op(rsc, node, rsc_op, gIter->next, &on_fail, data_set); + } /* create active recurring operations as optional */ calculate_active_ops(sorted_op_list, &start_index, &stop_index); process_recurring(node, rsc, start_index, stop_index, sorted_op_list, data_set); /* no need to free the contents */ g_list_free(sorted_op_list); process_rsc_state(rsc, node, on_fail, migrate_op, data_set); if(get_target_role(rsc, &req_role)) { if(rsc->next_role == RSC_ROLE_UNKNOWN || req_role < rsc->next_role) { crm_debug("%s: Overwriting calculated next role %s" " with requested next role %s", rsc->id, role2text(rsc->next_role), role2text(req_role)); rsc->next_role = req_role; } else if(req_role > rsc->next_role) { crm_info("%s: Not overwriting calculated next role %s" " with requested next role %s", rsc->id, role2text(rsc->next_role), role2text(req_role)); } } if(saved_role > rsc->role) { rsc->role = saved_role; } } gboolean unpack_lrm_resources(node_t *node, xmlNode * lrm_rsc_list, pe_working_set_t *data_set) { CRM_CHECK(node != NULL, return FALSE); crm_debug_3("Unpacking resources on %s", node->details->uname); xml_child_iter_filter( lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, unpack_lrm_rsc_state(node, rsc_entry, data_set); ); return TRUE; } static void set_active(resource_t *rsc) { resource_t *top = uber_parent(rsc); if(top && top->variant == pe_master) { rsc->role = RSC_ROLE_SLAVE; } else { rsc->role = RSC_ROLE_STARTED; } } static void set_node_score(gpointer key, gpointer value, gpointer user_data) { node_t *node = value; int *score = user_data; node->weight = *score; } #define STATUS_PATH_MAX 1024 static xmlNode *find_lrm_op(const char *resource, const char *op, const char *node, const char *source, pe_working_set_t *data_set) { int offset = 0; char xpath[STATUS_PATH_MAX]; offset += snprintf(xpath+offset, STATUS_PATH_MAX-offset, "//node_state[@id='%s']", node); offset += snprintf(xpath+offset, STATUS_PATH_MAX-offset, "//"XML_LRM_TAG_RESOURCE"[@id='%s']", resource); /* Need to check against transition_magic too? */ if(source && safe_str_eq(op, CRMD_ACTION_MIGRATE)) { offset += snprintf(xpath+offset, STATUS_PATH_MAX-offset, "/"XML_LRM_TAG_RSC_OP"[@operation='%s' and @migrate_target='%s']", op, source); } else if(source && safe_str_eq(op, CRMD_ACTION_MIGRATED)) { offset += snprintf(xpath+offset, STATUS_PATH_MAX-offset, "/"XML_LRM_TAG_RSC_OP"[@operation='%s' and @migrate_source='%s']", op, source); } else { offset += snprintf(xpath+offset, STATUS_PATH_MAX-offset, "/"XML_LRM_TAG_RSC_OP"[@operation='%s']", op); } return get_xpath_object(xpath, data_set->input, LOG_DEBUG); } gboolean unpack_rsc_op(resource_t *rsc, node_t *node, xmlNode *xml_op, GListPtr next, enum action_fail_response *on_fail, pe_working_set_t *data_set) { int task_id = 0; const char *id = NULL; const char *key = NULL; const char *task = NULL; const char *magic = NULL; const char *actual_rc = NULL; /* const char *target_rc = NULL; */ const char *task_status = NULL; const char *interval_s = NULL; const char *op_version = NULL; int interval = 0; int task_status_i = -2; int actual_rc_i = 0; int target_rc = -1; int last_failure = 0; action_t *action = NULL; node_t *effective_node = NULL; resource_t *failed = NULL; gboolean expired = FALSE; gboolean is_probe = FALSE; CRM_CHECK(rsc != NULL, return FALSE); CRM_CHECK(node != NULL, return FALSE); CRM_CHECK(xml_op != NULL, return FALSE); id = ID(xml_op); task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); magic = crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC); key = crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY); crm_element_value_int(xml_op, XML_LRM_ATTR_CALLID, &task_id); CRM_CHECK(id != NULL, return FALSE); CRM_CHECK(task != NULL, return FALSE); CRM_CHECK(task_status != NULL, return FALSE); task_status_i = crm_parse_int(task_status, NULL); CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE); CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE); if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { /* safe to ignore these */ return TRUE; } if(rsc->failure_timeout > 0) { int last_run = 0; if(crm_element_value_int(xml_op, "last-run", &last_run) == 0) { /* int last_change = crm_element_value_int(xml_op, "last_rc_change"); */ time_t now = get_timet_now(data_set); if(now > (last_run + rsc->failure_timeout)) { expired = TRUE; } } } crm_debug_2("Unpacking task %s/%s (call_id=%d, status=%s) on %s (role=%s)", id, task, task_id, task_status, node->details->uname, role2text(rsc->role)); interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { is_probe = TRUE; } if(node->details->unclean) { crm_debug_2("Node %s (where %s is running) is unclean." " Further action depends on the value of the stop's on-fail attribue", node->details->uname, rsc->id); } actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); CRM_CHECK(actual_rc != NULL, return FALSE); actual_rc_i = crm_parse_int(actual_rc, NULL); if(key) { int dummy = 0; char *dummy_string = NULL; decode_transition_key(key, &dummy_string, &dummy, &dummy, &target_rc); crm_free(dummy_string); } if(task_status_i == LRM_OP_DONE && target_rc >= 0) { if(target_rc == actual_rc_i) { task_status_i = LRM_OP_DONE; } else { task_status_i = LRM_OP_ERROR; crm_debug("%s on %s returned %d (%s) instead of the expected value: %d (%s)", id, node->details->uname, actual_rc_i, execra_code2string(actual_rc_i), target_rc, execra_code2string(target_rc)); } } else if(task_status_i == LRM_OP_ERROR) { /* let us decide that */ task_status_i = LRM_OP_DONE; } if(task_status_i == LRM_OP_NOTSUPPORTED) { actual_rc_i = EXECRA_UNIMPLEMENT_FEATURE; } if(task_status_i != actual_rc_i && rsc->failure_timeout > 0 && get_failcount(node, rsc, &last_failure, data_set) == 0) { if(last_failure > 0) { action_t *clear_op = NULL; clear_op = custom_action( rsc, crm_concat(rsc->id, CRM_OP_CLEAR_FAILCOUNT, '_'), CRM_OP_CLEAR_FAILCOUNT, node, FALSE, TRUE, data_set); add_hash_param(clear_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); crm_notice("Clearing expired failcount for %s on %s", rsc->id, node->details->uname); } } if(expired && actual_rc_i != EXECRA_NOT_RUNNING && actual_rc_i != EXECRA_RUNNING_MASTER && actual_rc_i != EXECRA_OK) { crm_notice("Ignoring expired failure %s (rc=%d, magic=%s) on %s", id, actual_rc_i, magic, node->details->uname); goto done; } /* we could clean this up significantly except for old LRMs and CRMs that * didnt include target_rc and liked to remap status */ switch(actual_rc_i) { case EXECRA_NOT_RUNNING: if(is_probe || target_rc == actual_rc_i) { task_status_i = LRM_OP_DONE; rsc->role = RSC_ROLE_STOPPED; /* clear any previous failure actions */ *on_fail = action_fail_ignore; rsc->next_role = RSC_ROLE_UNKNOWN; } else if(safe_str_neq(task, CRMD_ACTION_STOP)) { task_status_i = LRM_OP_ERROR; } break; case EXECRA_RUNNING_MASTER: if(is_probe) { task_status_i = LRM_OP_DONE; crm_notice("Operation %s found resource %s active in master mode on %s", id, rsc->id, node->details->uname); } else if(target_rc == actual_rc_i) { /* nothing to do */ } else if(target_rc >= 0) { task_status_i = LRM_OP_ERROR; /* legacy code for pre-0.6.5 operations */ } else if(safe_str_neq(task, CRMD_ACTION_STATUS) || rsc->role != RSC_ROLE_MASTER) { task_status_i = LRM_OP_ERROR; if(rsc->role != RSC_ROLE_MASTER) { crm_err("%s reported %s in master mode on %s", id, rsc->id, node->details->uname); } } rsc->role = RSC_ROLE_MASTER; break; case EXECRA_FAILED_MASTER: rsc->role = RSC_ROLE_MASTER; task_status_i = LRM_OP_ERROR; break; case EXECRA_UNIMPLEMENT_FEATURE: if(interval > 0) { task_status_i = LRM_OP_NOTSUPPORTED; break; } /* else: fall through */ case EXECRA_INSUFFICIENT_PRIV: case EXECRA_NOT_INSTALLED: case EXECRA_INVALID_PARAM: effective_node = node; /* fall through */ case EXECRA_NOT_CONFIGURED: failed = rsc; if(is_not_set(rsc->flags, pe_rsc_unique)) { failed = uber_parent(failed); } do_crm_log(actual_rc_i==EXECRA_NOT_INSTALLED?LOG_NOTICE:LOG_ERR, "Hard error - %s failed with rc=%d: Preventing %s from re-starting %s %s", id, actual_rc_i, failed->id, effective_node?"on":"anywhere", effective_node?effective_node->details->uname:"in the cluster"); resource_location(failed, effective_node, -INFINITY, "hard-error", data_set); if(is_probe) { /* treat these like stops */ task = CRMD_ACTION_STOP; task_status_i = LRM_OP_DONE; crm_xml_add(xml_op, XML_ATTR_UNAME, node->details->uname); if(actual_rc_i != EXECRA_NOT_INSTALLED || is_set(data_set->flags, pe_flag_symmetric_cluster)) { if ((node->details->shutdown == FALSE) || (node->details->online == TRUE)) { add_node_copy(data_set->failed, xml_op); } } } break; case EXECRA_OK: if(is_probe && target_rc == 7) { task_status_i = LRM_OP_DONE; crm_notice("Operation %s found resource %s active on %s", id, rsc->id, node->details->uname); /* legacy code for pre-0.6.5 operations */ } else if(target_rc < 0 && interval > 0 && rsc->role == RSC_ROLE_MASTER) { /* catch status ops that return 0 instead of 8 while they * are supposed to be in master mode */ task_status_i = LRM_OP_ERROR; } break; default: if(task_status_i == LRM_OP_DONE) { crm_info("Remapping %s (rc=%d) on %s to an ERROR", id, actual_rc_i, node->details->uname); task_status_i = LRM_OP_ERROR; } } if(task_status_i == LRM_OP_ERROR || task_status_i == LRM_OP_TIMEOUT || task_status_i == LRM_OP_NOTSUPPORTED) { action = custom_action(rsc, crm_strdup(id), task, NULL, TRUE, FALSE, data_set); if(expired) { crm_notice("Ignoring expired failure (calculated) %s (rc=%d, magic=%s) on %s", id, actual_rc_i, magic, node->details->uname); goto done; } else if(action->on_fail == action_fail_ignore) { crm_warn("Remapping %s (rc=%d) on %s to DONE: ignore", id, actual_rc_i, node->details->uname); task_status_i = LRM_OP_DONE; } } switch(task_status_i) { case LRM_OP_PENDING: if(safe_str_eq(task, CRMD_ACTION_START)) { set_bit(rsc->flags, pe_rsc_start_pending); set_active(rsc); } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } /* * Intentionally ignoring pending migrate ops here; * haven't decided if we need to do anything special * with them yet... */ break; case LRM_OP_DONE: crm_debug_3("%s/%s completed on %s", rsc->id, task, node->details->uname); if(actual_rc_i == EXECRA_NOT_RUNNING) { /* nothing to do */ } else if(safe_str_eq(task, CRMD_ACTION_STOP)) { rsc->role = RSC_ROLE_STOPPED; /* clear any previous failure actions */ switch(*on_fail) { case action_fail_block: case action_fail_stop: case action_fail_fence: case action_fail_migrate: case action_fail_standby: crm_debug_2("%s.%s is not cleared by a completed stop", rsc->id, fail2text(*on_fail)); break; case action_fail_ignore: case action_fail_recover: *on_fail = action_fail_ignore; rsc->next_role = RSC_ROLE_UNKNOWN; } } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_SLAVE; } else if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) { rsc->role = RSC_ROLE_STARTED; } else if(safe_str_eq(task, CRMD_ACTION_MIGRATE)) { /* * The normal sequence is (now): migrate_to(Src) -> migrate_from(Tgt) -> stop(Src) * * So if a migrate_to is followed by a stop, then we dont need to care what * happended on the target node * * Without the stop, we need to look for a successful migrate_from. * This would also imply we're no longer running on the source * * Without the stop, and without a migrate_from op we make sure the resource * gets stopped on both source and target (assuming the target is up) * */ int stop_id = 0; xmlNode *stop_op = find_lrm_op(rsc->id, CRMD_ACTION_STOP, node->details->id, NULL, data_set); if(stop_op) { crm_element_value_int(stop_op, XML_LRM_ATTR_CALLID, &stop_id); } if(stop_op == NULL || stop_id < task_id) { int from_rc = 0, from_status = 0; const char *migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE); const char *migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET); node_t *target = pe_find_node_id(data_set->nodes, migrate_target); xmlNode *migrate_from = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, migrate_target, migrate_source, data_set); rsc->role = RSC_ROLE_STARTED; /* can be master? */ if(migrate_from) { crm_element_value_int(migrate_from, XML_LRM_ATTR_RC, &from_rc); crm_element_value_int(migrate_from, XML_LRM_ATTR_OPSTATUS, &from_status); crm_trace("%s op on %s exited with status=%d, rc=%d", ID(migrate_from), migrate_target, from_status, from_rc); } if(migrate_from && from_rc == EXECRA_OK && from_status == LRM_OP_DONE) { crm_trace("Detected dangling migration op: %s on %s", ID(xml_op), migrate_source); /* all good * just need to arrange for the stop action to get sent * but _without_ affecting the target somehow */ rsc->role = RSC_ROLE_STOPPED; rsc->dangling_migrations = g_list_prepend(rsc->dangling_migrations, node); } else if(migrate_from) { /* Failed */ crm_trace("Marking active on %s %p %d", migrate_target, target, target->details->online); if(target && target->details->online) { native_add_running(rsc, target, data_set); } } else { /* Pending or complete but erased */ node_t *target = pe_find_node_id(data_set->nodes, migrate_target); crm_trace("Marking active on %s %p %d", migrate_target, target, target->details->online); if(target && target->details->online) { /* TODO: One day, figure out how to complete the migration * For now, consider it active in both locations so it gets stopped everywhere */ native_add_running(rsc, target, data_set); } else { /* Consider it failed here - forces a restart, prevents migration */ set_bit_inplace(rsc->flags, pe_rsc_failed); } } } } else if(rsc->role < RSC_ROLE_STARTED) { /* start, migrate_to and migrate_from will land here */ crm_debug_3("%s active on %s", rsc->id, node->details->uname); set_active(rsc); } break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Processing failed op %s on %s: %s (%d)", id, node->details->uname, execra_code2string(actual_rc_i), actual_rc_i); crm_xml_add(xml_op, XML_ATTR_UNAME, node->details->uname); if ((node->details->shutdown == FALSE) || (node->details->online == TRUE)) { add_node_copy(data_set->failed, xml_op); } if(*on_fail < action->on_fail) { *on_fail = action->on_fail; } if(safe_str_eq(task, CRMD_ACTION_STOP)) { resource_location( rsc, node, -INFINITY, "__stop_fail__", data_set); } else if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) { int stop_id = 0; int migrate_id = 0; const char *migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE); const char *migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET); xmlNode *stop_op = find_lrm_op(rsc->id, CRMD_ACTION_STOP, migrate_source, NULL, data_set); xmlNode *migrate_op = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATE, migrate_source, migrate_target, data_set); if(stop_op) { crm_element_value_int(stop_op, XML_LRM_ATTR_CALLID, &stop_id); } if(migrate_op) { crm_element_value_int(migrate_op, XML_LRM_ATTR_CALLID, &migrate_id); } /* Get our state right */ rsc->role = RSC_ROLE_STARTED; /* can be master? */ if(stop_op == NULL || stop_id < migrate_id) { node_t *source = pe_find_node_id(data_set->nodes, migrate_source); if(source && source->details->online) { native_add_running(rsc, source, data_set); } } } else if(safe_str_eq(task, CRMD_ACTION_MIGRATE)) { int stop_id = 0; int migrate_id = 0; const char *migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE); const char *migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET); xmlNode *stop_op = find_lrm_op(rsc->id, CRMD_ACTION_STOP, migrate_target, NULL, data_set); xmlNode *migrate_op = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, migrate_target, migrate_source, data_set); if(stop_op) { crm_element_value_int(stop_op, XML_LRM_ATTR_CALLID, &stop_id); } if(migrate_op) { crm_element_value_int(migrate_op, XML_LRM_ATTR_CALLID, &migrate_id); } /* Get our state right */ rsc->role = RSC_ROLE_STARTED; /* can be master? */ if(stop_op == NULL || stop_id < migrate_id) { node_t *target = pe_find_node_id(data_set->nodes, migrate_target); crm_trace("Stop: %p %d, Migrated: %p %d", stop_op, stop_id, migrate_op, migrate_id); if(target && target->details->online) { native_add_running(rsc, target, data_set); } } else if(migrate_op == NULL) { /* Make sure it gets cleaned up, the stop may pre-date the migrate_from */ rsc->dangling_migrations = g_list_prepend(rsc->dangling_migrations, node); } } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { /* * staying in role=master ends up putting the PE/TE into a loop * setting role=slave is not dangerous because no master will be * promoted until the failed resource has been fully stopped */ crm_warn("Forcing %s to stop after a failed demote action", rsc->id); rsc->next_role = RSC_ROLE_STOPPED; rsc->role = RSC_ROLE_SLAVE; } else if(compare_version("2.0", op_version) > 0 && safe_str_eq(task, CRMD_ACTION_START)) { crm_warn("Compatibility handling for failed op %s on %s", id, node->details->uname); resource_location( rsc, node, -INFINITY, "__legacy_start__", data_set); } if(rsc->role < RSC_ROLE_STARTED) { set_active(rsc); } crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s", rsc->id, role2text(rsc->role), node->details->unclean?"true":"false", fail2text(action->on_fail), role2text(action->fail_role)); if(action->fail_role != RSC_ROLE_STARTED && rsc->next_role < action->fail_role) { rsc->next_role = action->fail_role; } if(action->fail_role == RSC_ROLE_STOPPED) { int score = -INFINITY; crm_err("Making sure %s doesn't come up again", rsc->id); /* make sure it doesnt come up again */ g_hash_table_destroy(rsc->allowed_nodes); rsc->allowed_nodes = node_hash_from_list(data_set->nodes); g_hash_table_foreach(rsc->allowed_nodes, set_node_score, &score); } pe_free_action(action); action = NULL; break; case LRM_OP_CANCELLED: /* do nothing?? */ pe_err("Dont know what to do for cancelled ops yet"); break; } done: crm_debug_3("Resource %s after %s: role=%s", rsc->id, task, role2text(rsc->role)); pe_free_action(action); return TRUE; } gboolean add_node_attrs(xmlNode *xml_obj, node_t *node, gboolean overwrite, pe_working_set_t *data_set) { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_UNAME), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_ID), crm_strdup(node->details->id)); if(safe_str_eq(node->details->id, data_set->dc_uuid)) { data_set->dc_node = node; node->details->is_dc = TRUE; g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_TRUE)); } else { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_FALSE)); } unpack_instance_attributes( data_set->input, xml_obj, XML_TAG_ATTR_SETS, NULL, node->details->attrs, NULL, overwrite, data_set->now); return TRUE; } static GListPtr extract_operations(const char *node, const char *rsc, xmlNode *rsc_entry, gboolean active_filter) { + int counter = -1; int stop_index = -1; int start_index = -1; + GListPtr gIter = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; /* extract operations */ op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, crm_xml_add(rsc_op, "resource", rsc); crm_xml_add(rsc_op, XML_ATTR_UNAME, node); op_list = g_list_prepend(op_list, rsc_op); ); if(op_list == NULL) { /* if there are no operations, there is nothing to do */ return NULL; } sorted_op_list = g_list_sort(op_list, sort_op_by_callid); /* create active recurring operations as optional */ if(active_filter == FALSE) { return sorted_op_list; } op_list = NULL; - calculate_active_ops(sorted_op_list, &start_index, &stop_index); - slist_iter(rsc_op, xmlNode, sorted_op_list, lpc, - if(start_index < stop_index) { - crm_debug_4("Skipping %s: not active", ID(rsc_entry)); - break; - - } else if(lpc < start_index) { - crm_debug_4("Skipping %s: old", ID(rsc_op)); - continue; - } - op_list = g_list_append(op_list, rsc_op); - ); + calculate_active_ops(sorted_op_list, &start_index, &stop_index); + + gIter = sorted_op_list; + for(; gIter != NULL; gIter = gIter->next) { + xmlNode *rsc_op = (xmlNode*)gIter->data; + counter++; + + if(start_index < stop_index) { + crm_debug_4("Skipping %s: not active", ID(rsc_entry)); + break; + + } else if(counter < start_index) { + crm_debug_4("Skipping %s: old", ID(rsc_op)); + continue; + } + op_list = g_list_append(op_list, rsc_op); + } g_list_free(sorted_op_list); return op_list; } GListPtr find_operations( const char *rsc, const char *node, gboolean active_filter, pe_working_set_t *data_set) { GListPtr output = NULL; GListPtr intermediate = NULL; xmlNode *tmp = NULL; xmlNode *status = find_xml_node(data_set->input, XML_CIB_TAG_STATUS, TRUE); const char *uname = NULL; node_t *this_node = NULL; xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, uname = crm_element_value(node_state, XML_ATTR_UNAME); if(node != NULL && safe_str_neq(uname, node)) { continue; } this_node = pe_find_node(data_set->nodes, uname); CRM_CHECK(this_node != NULL, continue); determine_online_status(node_state, this_node, data_set); if(this_node->details->online || is_set(data_set->flags, pe_flag_stonith_enabled)) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ tmp = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); tmp = find_xml_node(tmp, XML_LRM_TAG_RESOURCES, FALSE); xml_child_iter_filter( tmp, lrm_rsc, XML_LRM_TAG_RESOURCE, const char *rsc_id = crm_element_value(lrm_rsc, XML_ATTR_ID); if(rsc != NULL && safe_str_neq(rsc_id, rsc)) { continue; } intermediate = extract_operations(uname, rsc_id, lrm_rsc, active_filter); output = g_list_concat(output, intermediate); ); } ); return output; } diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index f08b9b5fdc..c962b1ba0e 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -1,1346 +1,1373 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include pe_working_set_t *pe_dataset = NULL; extern xmlNode *get_object_root(const char *object_type,xmlNode *the_root); void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); void unpack_operation( action_t *action, xmlNode *xml_obj, pe_working_set_t* data_set); void pe_free_shallow(GListPtr alist) { pe_free_shallow_adv(alist, TRUE); } void pe_free_shallow_adv(GListPtr alist, gboolean with_data) { GListPtr item; GListPtr item_next = alist; if(with_data == FALSE && alist != NULL) { g_list_free(alist); return; } while(item_next != NULL) { item = item_next; item_next = item_next->next; if(with_data) { /* crm_debug_5("freeing %p", item->data); */ crm_free(item->data); } item->data = NULL; item->next = NULL; g_list_free_1(item); } } node_t * node_copy(node_t *this_node) { node_t *new_node = NULL; CRM_CHECK(this_node != NULL, return NULL); crm_malloc0(new_node, sizeof(node_t)); CRM_ASSERT(new_node != NULL); crm_debug_5("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; return new_node; } /* any node in list1 or list2 and not in the other gets a score of -INFINITY */ void node_list_exclude(GHashTable *hash, GListPtr list, gboolean merge_scores) { GHashTable *result = hash; node_t *other_node = NULL; + GListPtr gIter = list; GHashTableIter iter; node_t *node = NULL; g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { other_node = pe_find_node_id(list, node->details->id); if(other_node == NULL) { node->weight = -INFINITY; } else if(merge_scores) { node->weight = merge_weights(node->weight, other_node->weight); } } - slist_iter( - node, node_t, list, lpc, + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; other_node = pe_hash_table_lookup(result, node->details->id); if(other_node == NULL) { node_t *new_node = node_copy(node); new_node->weight = -INFINITY; g_hash_table_insert(result, (gpointer)new_node->details->id, new_node); } - ); + } } GHashTable * node_hash_from_list(GListPtr list) { + GListPtr gIter = list; GHashTable *result = g_hash_table_new_full( g_str_hash,g_str_equal, NULL, g_hash_destroy_str); - slist_iter( - node, node_t, list, lpc, + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; node_t *n = node_copy(node); + g_hash_table_insert(result, (gpointer)n->details->id, n); - ); + } return result; } GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter) { - GListPtr result = NULL; + GListPtr result = NULL; + GListPtr gIter = list1; - slist_iter( - this_node, node_t, list1, lpc, - node_t *new_node = NULL; - if(filter && this_node->weight < 0) { - continue; - } + for(; gIter != NULL; gIter = gIter->next) { + node_t *new_node = NULL; + node_t *this_node = (node_t*)gIter->data; + + + if(filter && this_node->weight < 0) { + continue; + } - new_node = node_copy(this_node); - if(reset) { - new_node->weight = 0; - } - if(new_node != NULL) { - result = g_list_prepend(result, new_node); - } - ); + new_node = node_copy(this_node); + if(reset) { + new_node->weight = 0; + } + if(new_node != NULL) { + result = g_list_prepend(result, new_node); + } + } - return result; + return result; } static gint sort_node_uname(gconstpointer a, gconstpointer b) { const node_t *node_a = a; const node_t *node_b = b; return strcmp(node_a->details->uname, node_b->details->uname); } void dump_node_scores_worker(int level, const char *file, const char *function, int line, resource_t *rsc, const char *comment, GHashTable *nodes) { GHashTable *hash = nodes; GHashTableIter iter; node_t *node = NULL; if(rsc) { hash = rsc->allowed_nodes; } if(rsc && is_set(rsc->flags, pe_rsc_orphan)) { /* Don't show the allocation scores for orphans */ return; } if(level == 0) { /* For now we want this in sorted order to keep the regression tests happy */ + GListPtr gIter = NULL; GListPtr list = g_hash_table_get_values(hash); list = g_list_sort(list, sort_node_uname); - slist_iter( - node, node_t, list, lpc, + gIter = list; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; char *score = score2char(node->weight); + if(rsc) { printf("%s: %s allocation score on %s: %s\n", comment, rsc->id, node->details->uname, score); } else { printf("%s: %s = %s\n", comment, node->details->uname, score); } crm_free(score); - ); + } + g_list_free(list); } else { g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { char *score = score2char(node->weight); if(rsc) { do_crm_log_alias(level, file, function, line, "%s: %s allocation score on %s: %s", comment, rsc->id, node->details->uname, score); } else { do_crm_log_alias(level, file, function, line, "%s: %s = %s", comment, node->details->uname, score); } crm_free(score); } } if(rsc && rsc->children) { - slist_iter( - child, resource_t, rsc->children, lpc, + GListPtr gIter = NULL; + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; dump_node_scores_worker(level, file, function, line, child, comment, nodes); - ); + } } } static void append_dump_text(gpointer key, gpointer value, gpointer user_data) { char **dump_text = user_data; int len = 0; char *new_text = NULL; len = strlen(*dump_text) + strlen(" ") + strlen(key) + strlen("=") + strlen(value) + 1; crm_malloc0(new_text, len); sprintf(new_text, "%s %s=%s", *dump_text, (char *)key, (char *)value); crm_free(*dump_text); *dump_text = new_text; } void dump_node_capacity(int level, const char *comment, node_t *node) { int len = 0; char *dump_text = NULL; len = strlen(comment) + strlen(": ") + strlen(node->details->uname) + strlen(" capacity:") + 1; crm_malloc0(dump_text, len); sprintf(dump_text, "%s: %s capacity:", comment, node->details->uname); g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text); if(level == 0) { fprintf(stdout, "%s\n", dump_text); } else { do_crm_log_unlikely(level, "%s", dump_text); } crm_free(dump_text); } void dump_rsc_utilization(int level, const char *comment, resource_t *rsc, node_t *node) { int len = 0; char *dump_text = NULL; len = strlen(comment) + strlen(": ") + strlen(rsc->id) + strlen(" utilization on ") + strlen(node->details->uname) + strlen(":") + 1; crm_malloc0(dump_text, len); sprintf(dump_text, "%s: %s utilization on %s:", comment, rsc->id, node->details->uname); g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text); if(level == 0) { fprintf(stdout, "%s\n", dump_text); } else { do_crm_log_unlikely(level, "%s", dump_text); } crm_free(dump_text); } gint sort_rsc_index(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL && b == NULL) { return 0; } if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(resource1->sort_index > resource2->sort_index) { return -1; } if(resource1->sort_index < resource2->sort_index) { return 1; } return 0; } gint sort_rsc_priority(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL && b == NULL) { return 0; } if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(resource1->priority > resource2->priority) { return -1; } if(resource1->priority < resource2->priority) { return 1; } return 0; } action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set) { action_t *action = NULL; GListPtr possible_matches = NULL; CRM_CHECK(key != NULL, return NULL); CRM_CHECK(task != NULL, return NULL); if(save_action && rsc != NULL) { possible_matches = find_actions(rsc->actions, key, on_node); } if(possible_matches != NULL) { crm_free(key); if(g_list_length(possible_matches) > 1) { pe_warn("Action %s for %s on %s exists %d times", task, rsc?rsc->id:"", on_node?on_node->details->uname:"", g_list_length(possible_matches)); } action = g_list_nth_data(possible_matches, 0); crm_debug_4("Found existing action (%d) %s for %s on %s", action->id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); g_list_free(possible_matches); } if(action == NULL) { if(save_action) { crm_debug_4("Creating%s action %d: %s for %s on %s", optional?"":" manditory", data_set->action_id, key, rsc?rsc->id:"", on_node?on_node->details->uname:""); } crm_malloc0(action, sizeof(action_t)); if(save_action) { action->id = data_set->action_id++; } else { action->id = 0; } action->rsc = rsc; CRM_ASSERT(task != NULL); action->task = crm_strdup(task); if(on_node) { action->node = node_copy(on_node); } action->uuid = key; set_bit_inplace(action->flags, pe_action_failure_is_fatal); set_bit_inplace(action->flags, pe_action_runnable); if(optional) { set_bit_inplace(action->flags, pe_action_optional); } else { clear_bit_inplace(action->flags, pe_action_optional); } /* Implied by crm_malloc0()... action->actions_before = NULL; action->actions_after = NULL; action->pseudo = FALSE; action->dumped = FALSE; action->processed = FALSE; action->seen_count = 0; */ action->extra = g_hash_table_new_full( g_str_hash, g_str_equal, free, free); action->meta = g_hash_table_new_full( g_str_hash, g_str_equal, free, free); if(save_action) { data_set->actions = g_list_prepend( data_set->actions, action); } if(rsc != NULL) { action->op_entry = find_rsc_op_entry(rsc, key); unpack_operation( action, action->op_entry, data_set); if(save_action) { rsc->actions = g_list_prepend( rsc->actions, action); } } if(save_action) { crm_debug_4("Action %d created", action->id); } } if(optional == FALSE && (action->flags & pe_action_optional)) { crm_debug_2("Action %d (%s) marked manditory", action->id, action->uuid); clear_bit_inplace(action->flags, pe_action_optional); } if(rsc != NULL) { enum action_tasks a_task = text2task(action->task); int warn_level = LOG_DEBUG_3; if(save_action) { warn_level = LOG_WARNING; } if(is_set(action->flags, pe_action_have_node_attrs) == FALSE && action->node != NULL && action->op_entry != NULL) { set_bit_inplace(action->flags, pe_action_have_node_attrs); unpack_instance_attributes( data_set->input, action->op_entry, XML_TAG_ATTR_SETS, action->node->details->attrs, action->extra, NULL, FALSE, data_set->now); } if(is_set(action->flags, pe_action_pseudo)) { /* leave untouched */ } else if(action->node == NULL) { clear_bit_inplace(action->flags, pe_action_runnable); } else if(is_not_set(rsc->flags, pe_rsc_managed) && g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL) == NULL) { do_crm_log_unlikely(LOG_DEBUG, "Action %s (unmanaged)", action->uuid); set_bit_inplace(action->flags, pe_action_optional); /* action->runnable = FALSE; */ } else if(action->node->details->online == FALSE) { clear_bit_inplace(action->flags, pe_action_runnable); do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)", action->uuid, action->node->details->uname); if(is_set(action->rsc->flags, pe_rsc_managed) && save_action && a_task == stop_rsc) { do_crm_log(warn_level, "Marking node %s unclean", action->node->details->uname); action->node->details->unclean = TRUE; } } else if(action->node->details->pending) { clear_bit_inplace(action->flags, pe_action_runnable); do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)", action->uuid, action->node->details->uname); } else if(action->needs == rsc_req_nothing) { crm_debug_3("Action %s doesnt require anything", action->uuid); set_bit_inplace(action->flags, pe_action_runnable); #if 0 /* * No point checking this * - if we dont have quorum we cant stonith anyway */ } else if(action->needs == rsc_req_stonith) { crm_debug_3("Action %s requires only stonith", action->uuid); action->runnable = TRUE; #endif } else if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE && data_set->no_quorum_policy == no_quorum_stop) { clear_bit_inplace(action->flags, pe_action_runnable); crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid); } else if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE && data_set->no_quorum_policy == no_quorum_freeze) { crm_debug_3("Check resource is already active"); if(rsc->fns->active(rsc, TRUE) == FALSE) { clear_bit_inplace(action->flags, pe_action_runnable); crm_debug("%s\t%s (cancelled : quorum freeze)", action->node->details->uname, action->uuid); } } else { crm_debug_3("Action %s is runnable", action->uuid); set_bit_inplace(action->flags, pe_action_runnable); } if(save_action) { switch(a_task) { case stop_rsc: set_bit(rsc->flags, pe_rsc_stopping); break; case start_rsc: clear_bit(rsc->flags, pe_rsc_starting); if(is_set(action->flags, pe_action_runnable)) { set_bit(rsc->flags, pe_rsc_starting); } break; default: break; } } } return action; } void unpack_operation( action_t *action, xmlNode *xml_obj, pe_working_set_t* data_set) { int value_i = 0; unsigned long long interval = 0; unsigned long long start_delay = 0; char *value_ms = NULL; const char *class = NULL; const char *value = NULL; const char *field = NULL; CRM_CHECK(action->rsc != NULL, return); unpack_instance_attributes(data_set->input, data_set->op_defaults, XML_TAG_META_SETS, NULL, action->meta, NULL, FALSE, data_set->now); xml_prop_iter(xml_obj, name, value, if (value != NULL) { g_hash_table_replace(action->meta, crm_strdup(name), crm_strdup(value)); } ); unpack_instance_attributes(data_set->input, xml_obj, XML_TAG_META_SETS, NULL, action->meta, NULL, FALSE, data_set->now); unpack_instance_attributes(data_set->input, xml_obj, XML_TAG_ATTR_SETS, NULL, action->meta, NULL, FALSE, data_set->now); g_hash_table_remove(action->meta, "id"); class = g_hash_table_lookup(action->rsc->meta, "class"); value = g_hash_table_lookup(action->meta, "requires"); if(safe_str_eq(class, "stonith")) { action->needs = rsc_req_nothing; value = "nothing (fencing op)"; } else if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) { action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(safe_str_eq(value, "nothing")) { action->needs = rsc_req_nothing; } else if(safe_str_eq(value, "quorum")) { action->needs = rsc_req_quorum; } else if(safe_str_eq(value, "fencing")) { action->needs = rsc_req_stonith; } else if(data_set->no_quorum_policy == no_quorum_ignore) { action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(data_set->no_quorum_policy == no_quorum_freeze && is_set(data_set->flags, pe_flag_stonith_enabled)) { action->needs = rsc_req_stonith; value = "fencing (default)"; } else { action->needs = rsc_req_quorum; value = "quorum (default)"; } crm_debug_3("\tAction %s requires: %s", action->task, value); value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL); if(safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) { crm_config_err("on-fail=standby is not allowed for stop actions: %s", action->rsc->id); value = NULL; } if(value == NULL) { } else if(safe_str_eq(value, "block")) { action->on_fail = action_fail_block; } else if(safe_str_eq(value, "fence")) { action->on_fail = action_fail_fence; value = "node fencing"; if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) { crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense"); action->on_fail = action_fail_stop; action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } } else if(safe_str_eq(value, "standby")) { action->on_fail = action_fail_standby; value = "node standby"; } else if(safe_str_eq(value, "ignore") || safe_str_eq(value, "nothing")) { action->on_fail = action_fail_ignore; value = "ignore"; } else if(safe_str_eq(value, "migrate")) { action->on_fail = action_fail_migrate; value = "force migration"; } else if(safe_str_eq(value, "stop")) { action->on_fail = action_fail_stop; action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } else if(safe_str_eq(value, "restart")) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate)"; } else { pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value); value = NULL; } /* defaults */ if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { if(is_set(data_set->flags, pe_flag_stonith_enabled)) { action->on_fail = action_fail_fence; value = "resource fence (default)"; } else { action->on_fail = action_fail_block; value = "resource block (default)"; } } else if(value == NULL) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate) (default)"; } crm_debug_3("\t%s failure handling: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = g_hash_table_lookup(action->meta, "role_after_failure"); } if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) { action->fail_role = text2role(value); } /* defaults */ if(action->fail_role == RSC_ROLE_UNKNOWN) { if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) { action->fail_role = RSC_ROLE_SLAVE; } else { action->fail_role = RSC_ROLE_STARTED; } } crm_debug_3("\t%s failure results in: %s", action->task, role2text(action->fail_role)); field = XML_LRM_ATTR_INTERVAL; value = g_hash_table_lookup(action->meta, field); if(value != NULL) { interval = crm_get_interval(value); if(interval > 0) { value_ms = crm_itoa(interval); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } else { g_hash_table_remove(action->meta, field); } } field = XML_OP_ATTR_START_DELAY; value = g_hash_table_lookup(action->meta, field); if(value != NULL) { value_i = crm_get_msec(value); if(value_i < 0) { value_i = 0; } start_delay = value_i; value_ms = crm_itoa(value_i); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } else if(interval > 0 && g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN)) { char *date_str = NULL; char *date_str_mutable = NULL; ha_time_t *origin = NULL; value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN); date_str = crm_strdup(value); date_str_mutable = date_str; origin = parse_date(&date_str_mutable); crm_free(date_str); if(origin == NULL) { crm_config_err("Operation %s contained an invalid "XML_OP_ATTR_ORIGIN": %s", ID(xml_obj), value); } else { ha_time_t *delay = NULL; int rc = compare_date(origin, data_set->now); unsigned long long delay_s = 0; while(rc < 0) { add_seconds(origin, interval/1000); rc = compare_date(origin, data_set->now); } delay = subtract_time(origin, data_set->now); delay_s = date_in_seconds(delay); /* log_date(LOG_DEBUG_5, "delay", delay, ha_log_date|ha_log_time|ha_log_local); */ crm_info("Calculated a start delay of %llus for %s", delay_s, ID(xml_obj)); g_hash_table_replace(action->meta, crm_strdup(XML_OP_ATTR_START_DELAY), crm_itoa(delay_s * 1000)); start_delay = delay_s * 1000; free_ha_date(origin); free_ha_date(delay); } } field = XML_ATTR_TIMEOUT; value = g_hash_table_lookup(action->meta, field); if(value == NULL) { value = pe_pref( data_set->config_hash, "default-action-timeout"); } value_i = crm_get_msec(value); if(value_i < 0) { value_i = 0; } value_i += start_delay; value_ms = crm_itoa(value_i); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } xmlNode * find_rsc_op_entry(resource_t *rsc, const char *key) { int number = 0; gboolean do_retry = TRUE; char *local_key = NULL; const char *name = NULL; const char *value = NULL; const char *interval = NULL; char *match_key = NULL; xmlNode *op = NULL; retry: xml_child_iter_filter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); value = crm_element_value(operation, "enabled"); if(value && crm_is_true(value) == FALSE) { continue; } number = crm_get_interval(interval); if(number < 0) { continue; } match_key = generate_op_key(rsc->id, name, number); if(safe_str_eq(key, match_key)) { op = operation; } crm_free(match_key); if(op != NULL) { crm_free(local_key); return op; } ); crm_free(local_key); if(do_retry == FALSE) { return NULL; } do_retry = FALSE; if(strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) { local_key = generate_op_key(rsc->id, "migrate", 0); key = local_key; goto retry; } else if(strstr(key, "_notify_")) { local_key = generate_op_key(rsc->id, "notify", 0); key = local_key; goto retry; } return NULL; } void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%sNode %s: (weight=%d, fixed=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", node->details->uname, node->weight, node->fixed?"True":"False"); if(details && node != NULL && node->details != NULL) { char *pe_mutable = crm_strdup("\t\t"); + GListPtr gIter = node->details->running_rsc; crm_debug_4("\t\t===Node Attributes"); g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable); crm_free(pe_mutable); crm_debug_4("\t\t=== Resources"); - slist_iter( - rsc, resource_t, node->details->running_rsc, lpc, - print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE); - ); + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE); + } } } /* * Used by the HashTable for-loop */ void print_str_str(gpointer key, gpointer value, gpointer user_data) { crm_debug_4("%s%s %s ==> %s", user_data==NULL?"":(char*)user_data, user_data==NULL?"":": ", (char*)key, (char*)value); } void print_resource( int log_level, const char *pre_text, resource_t *rsc, gboolean details) { long options = pe_print_log; if(rsc == NULL) { do_crm_log(log_level-1, "%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(details) { options |= pe_print_details; } rsc->fns->print(rsc, pre_text, options, &log_level); } void pe_free_action(action_t *action) { if(action == NULL) { return; } pe_free_shallow(action->actions_before);/* action_warpper_t* */ pe_free_shallow(action->actions_after); /* action_warpper_t* */ if(action->extra) { g_hash_table_destroy(action->extra); } if(action->meta) { g_hash_table_destroy(action->meta); } crm_free(action->task); crm_free(action->uuid); crm_free(action->node); crm_free(action); } GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node) { - const char *value = NULL; - GListPtr result = NULL; - CRM_CHECK(input != NULL, return NULL); + const char *value = NULL; + GListPtr result = NULL; + GListPtr gIter = input; + CRM_CHECK(input != NULL, return NULL); - slist_iter( - action, action_t, input, lpc, - value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); - if(value == NULL) { - /* skip */ - } else if(safe_str_eq(value, "0")) { - /* skip */ - } else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) { - /* skip */ - } else if(not_on_node == NULL) { - crm_debug_5("(null) Found: %s", action->uuid); - result = g_list_prepend(result, action); - - } else if(action->node == NULL) { - /* skip */ - } else if(action->node->details != not_on_node->details) { - crm_debug_5("Found: %s", action->uuid); - result = g_list_prepend(result, action); - } - ); + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); + if(value == NULL) { + /* skip */ + } else if(safe_str_eq(value, "0")) { + /* skip */ + } else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) { + /* skip */ + } else if(not_on_node == NULL) { + crm_debug_5("(null) Found: %s", action->uuid); + result = g_list_prepend(result, action); + + } else if(action->node == NULL) { + /* skip */ + } else if(action->node->details != not_on_node->details) { + crm_debug_5("Found: %s", action->uuid); + result = g_list_prepend(result, action); + } + } - return result; + return result; } action_t * find_first_action(GListPtr input, const char *uuid, const char *task, node_t *on_node) { - CRM_CHECK(uuid || task, return NULL); + GListPtr gIter = input; + CRM_CHECK(uuid || task, return NULL); - slist_iter( - action, action_t, input, lpc, - if(uuid != NULL && safe_str_neq(uuid, action->uuid)) { - continue; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + if(uuid != NULL && safe_str_neq(uuid, action->uuid)) { + continue; - } else if(task != NULL && safe_str_neq(task, action->task)) { - continue; + } else if(task != NULL && safe_str_neq(task, action->task)) { + continue; - } else if(on_node == NULL) { - return action; + } else if(on_node == NULL) { + return action; - } else if(action->node == NULL) { - continue; + } else if(action->node == NULL) { + continue; - } else if(on_node->details == action->node->details) { - return action; - } - ); + } else if(on_node->details == action->node->details) { + return action; + } + } - return NULL; + return NULL; } GListPtr find_actions(GListPtr input, const char *key, node_t *on_node) { - GListPtr result = NULL; - CRM_CHECK(key != NULL, return NULL); + GListPtr gIter = input; + GListPtr result = NULL; + CRM_CHECK(key != NULL, return NULL); - slist_iter( - action, action_t, input, lpc, - crm_debug_5("Matching %s against %s", key, action->uuid); - if(safe_str_neq(key, action->uuid)) { - continue; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + crm_debug_5("Matching %s against %s", key, action->uuid); + if(safe_str_neq(key, action->uuid)) { + continue; - } else if(on_node == NULL) { - result = g_list_prepend(result, action); + } else if(on_node == NULL) { + result = g_list_prepend(result, action); - } else if(action->node == NULL) { - /* skip */ - crm_debug_2("While looking for %s action on %s, " - "found an unallocated one. Assigning" - " it to the requested node...", - key, on_node->details->uname); - - action->node = node_copy(on_node); - result = g_list_prepend(result, action); + } else if(action->node == NULL) { + /* skip */ + crm_debug_2("While looking for %s action on %s, " + "found an unallocated one. Assigning" + " it to the requested node...", + key, on_node->details->uname); + + action->node = node_copy(on_node); + result = g_list_prepend(result, action); - } else if(on_node->details == action->node->details) { - result = g_list_prepend(result, action); - } - ); + } else if(on_node->details == action->node->details) { + result = g_list_prepend(result, action); + } + } - return result; + return result; } GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node) { - GListPtr result = NULL; - CRM_CHECK(key != NULL, return NULL); + GListPtr gIter = input; + GListPtr result = NULL; + CRM_CHECK(key != NULL, return NULL); - slist_iter( - action, action_t, input, lpc, - crm_debug_5("Matching %s against %s", key, action->uuid); - if(safe_str_neq(key, action->uuid)) { - crm_debug_3("Key mismatch: %s vs. %s", - key, action->uuid); - continue; - - } else if(on_node == NULL || action->node == NULL) { - crm_debug_3("on_node=%p, action->node=%p", - on_node, action->node); - continue; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + - } else if(safe_str_eq(on_node->details->id, - action->node->details->id)) { - result = g_list_prepend(result, action); - } - crm_debug_2("Node mismatch: %s vs. %s", - on_node->details->id, action->node->details->id); - ); + crm_debug_5("Matching %s against %s", key, action->uuid); + if(safe_str_neq(key, action->uuid)) { + crm_debug_3("Key mismatch: %s vs. %s", + key, action->uuid); + continue; + + } else if(on_node == NULL || action->node == NULL) { + crm_debug_3("on_node=%p, action->node=%p", + on_node, action->node); + continue; + + } else if(safe_str_eq(on_node->details->id, + action->node->details->id)) { + result = g_list_prepend(result, action); + } + crm_debug_2("Node mismatch: %s vs. %s", + on_node->details->id, action->node->details->id); + } - return result; + return result; } static void resource_node_score(resource_t *rsc, node_t *node, int score, const char *tag) { node_t *match = NULL; if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + resource_node_score(child_rsc, node, score, tag); - ); + } } crm_debug_2("Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score); match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id); if(match == NULL) { match = node_copy(node); match->weight = merge_weights(score, node->weight); g_hash_table_insert(rsc->allowed_nodes, (gpointer)match->details->id, match); } match->weight = merge_weights(match->weight, score); } void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set) { if(node != NULL) { resource_node_score(rsc, node, score, tag); } else if(data_set != NULL) { - slist_iter( - node, node_t, data_set->nodes, lpc, - resource_node_score(rsc, node, score, tag); - ); + GListPtr gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + resource_node_score(rsc, node, score, tag); + } + } else { GHashTableIter iter; node_t *node = NULL; g_hash_table_iter_init (&iter, rsc->allowed_nodes); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { resource_node_score(rsc, node, score, tag); } } if(node == NULL && score == -INFINITY) { if(rsc->allocated_to) { crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname); crm_free(rsc->allocated_to); rsc->allocated_to = NULL; } } } #define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int gint sort_op_by_callid(gconstpointer a, gconstpointer b) { char *a_uuid = NULL; char *b_uuid = NULL; const xmlNode *xml_a = a; const xmlNode *xml_b = b; const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID); const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID); const char *a_task_id = crm_element_value_const(xml_a, XML_LRM_ATTR_CALLID); const char *b_task_id = crm_element_value_const(xml_b, XML_LRM_ATTR_CALLID); const char *a_key = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC); const char *b_key = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC); int dummy = -1; int a_id = -1; int b_id = -1; int a_rc = -1; int b_rc = -1; int a_status = -1; int b_status = -1; int a_call_id = -1; int b_call_id = -1; if(safe_str_eq(a_xml_id, b_xml_id)) { /* We have duplicate lrm_rsc_op entries in the status * section which is unliklely to be a good thing * - we can handle it easily enough, but we need to get * to the bottom of why its happening. */ pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id); sort_return(0); } CRM_CHECK(a_task_id != NULL && b_task_id != NULL, crm_err("a: %s, b: %s", crm_str(a_xml_id), crm_str(b_xml_id)); sort_return(0)); a_call_id = crm_parse_int(a_task_id, NULL); b_call_id = crm_parse_int(b_task_id, NULL); if(a_call_id == -1 && b_call_id == -1) { /* both are pending ops so it doesnt matter since * stops are never pending */ sort_return(0); } else if(a_call_id >= 0 && a_call_id < b_call_id) { crm_debug_4("%s (%d) < %s (%d) : call id", a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(-1); } else if(b_call_id >= 0 && a_call_id > b_call_id) { crm_debug_4("%s (%d) > %s (%d) : call id", a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(1); } crm_debug_5("%s (%d) == %s (%d) : continuing", a_xml_id, a_call_id, b_xml_id, b_call_id); /* now process pending ops */ CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0)); CRM_CHECK(decode_transition_magic( a_key, &a_uuid, &a_id, &dummy, &a_status, &a_rc, &dummy), sort_return(0)); CRM_CHECK(decode_transition_magic( b_key, &b_uuid, &b_id, &dummy, &b_status, &b_rc, &dummy), sort_return(0)); /* try and determin the relative age of the operation... * some pending operations (ie. a start) may have been supuerceeded * by a subsequent stop * * [a|b]_id == -1 means its a shutdown operation and _always_ comes last */ if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) { /* * some of the logic in here may be redundant... * * if the UUID from the TE doesnt match then one better * be a pending operation. * pending operations dont survive between elections and joins * because we query the LRM directly */ CRM_CHECK(a_call_id == -1 || b_call_id == -1, crm_err("a: %s=%d, b: %s=%d", crm_str(a_xml_id), a_call_id, crm_str(b_xml_id), b_call_id); sort_return(0)); CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0)); if(b_call_id == -1) { crm_debug_2("%s (%d) < %s (%d) : transition + call id", a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(-1); } if(a_call_id == -1) { crm_debug_2("%s (%d) > %s (%d) : transition + call id", a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(1); } } else if((a_id >= 0 && a_id < b_id) || b_id == -1) { crm_debug_3("%s (%d) < %s (%d) : transition", a_xml_id, a_id, b_xml_id, b_id); sort_return(-1); } else if((b_id >= 0 && a_id > b_id) || a_id == -1) { crm_debug_3("%s (%d) > %s (%d) : transition", a_xml_id, a_id, b_xml_id, b_id); sort_return(1); } /* we should never end up here */ crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default", a_xml_id, a_call_id, a_id, a_uuid, b_xml_id, b_call_id, b_id, b_uuid); CRM_CHECK(FALSE, sort_return(0)); } time_t get_timet_now(pe_working_set_t *data_set) { time_t now = 0; if(data_set && data_set->now) { now = data_set->now->tm_now; } if(now == 0) { /* eventually we should convert data_set->now into time_tm * for now, its only triggered by PE regression tests */ now = time(NULL); crm_crit("Defaulting to 'now'"); if(data_set && data_set->now) { data_set->now->tm_now = now; } } return now; } struct fail_search { resource_t *rsc; int count; long long last; char *key; }; static void get_failcount_by_prefix(gpointer key_p, gpointer value, gpointer user_data) { struct fail_search *search = user_data; const char *key = key_p; const char *match = strstr(key, search->key); if(match) { if(strstr(key, "last-failure-") == key && (key+13) == match) { search->last = crm_int_helper(value, NULL); } else if(strstr(key, "fail-count-") == key && (key+11) == match) { search->count += char2score(value); } } } int get_failcount(node_t *node, resource_t *rsc, int *last_failure, pe_working_set_t *data_set) { struct fail_search search = {rsc, 0, 0, NULL}; search.key = crm_strdup(rsc->id); if(is_not_set(rsc->flags, pe_rsc_unique)) { int lpc = 0; search.rsc = uber_parent(rsc); /* Strip the clone incarnation */ for(lpc = strlen(search.key); lpc > 0; lpc--) { if(search.key[lpc] == ':') { search.key[lpc+1] = 0; break; } } g_hash_table_foreach(node->details->attrs, get_failcount_by_prefix, &search); } else { /* Optimize the "normal" case */ char *key = NULL; const char *value = NULL; key = crm_concat("fail-count", rsc->id, '-'); value = g_hash_table_lookup(node->details->attrs, key); search.count = char2score(value); crm_free(key); key = crm_concat("last-failure", rsc->id, '-'); value = g_hash_table_lookup(node->details->attrs, key); search.last = crm_int_helper(value, NULL); crm_free(key); } if(search.count != 0 && search.last != 0 && rsc->failure_timeout) { if(last_failure) { *last_failure = search.last; } if(search.last > 0) { time_t now = get_timet_now(data_set); if(now > (search.last + rsc->failure_timeout)) { crm_notice("Failcount for %s on %s has expired (limit was %ds)", search.rsc->id, node->details->uname, rsc->failure_timeout); search.count = 0; } } } if(search.count != 0) { crm_info("%s has failed %s times on %s", search.rsc->id, score2char(search.count), node->details->uname); } crm_free(search.key); return search.count; } gboolean get_target_role(resource_t *rsc, enum rsc_role_e *role) { const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE); CRM_CHECK(role != NULL, return FALSE); if(value == NULL || safe_str_eq("started", value) || safe_str_eq("default", value)) { return FALSE; } *role = text2role(value); if(*role == RSC_ROLE_UNKNOWN) { crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value); return FALSE; } else if(*role > RSC_ROLE_STARTED) { const char *stateful = g_hash_table_lookup(rsc->meta, "stateful"); if(rsc->variant == pe_master) { /* Next check isn't true during common_unpack() for the master */ } else if(crm_is_true(stateful) == FALSE) { pe_warn("%s is not part of a master/slave resource, a %s of '%s' makes no sense: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value, stateful); *role = RSC_ROLE_STARTED; return FALSE; } } return TRUE; } diff --git a/lib/transition/graph.c b/lib/transition/graph.c index 25db4a1492..dc2fafd57c 100644 --- a/lib/transition/graph.c +++ b/lib/transition/graph.c @@ -1,327 +1,334 @@ /* * 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 */ /* */ crm_graph_functions_t *graph_fns = NULL; static gboolean update_synapse_ready(synapse_t *synapse, int action_id) { - gboolean updates = FALSE; - CRM_CHECK(synapse->executed == FALSE, return FALSE); - CRM_CHECK(synapse->confirmed == FALSE, return FALSE); - - synapse->ready = TRUE; - slist_iter( - prereq, crm_action_t, synapse->inputs, lpc, + GListPtr lpc = NULL; + gboolean updates = FALSE; + CRM_CHECK(synapse->executed == FALSE, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return FALSE); + + synapse->ready = TRUE; + for(lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { + crm_action_t *prereq = (crm_action_t*)lpc->data; + - crm_debug_3("Processing input %d", prereq->id); + crm_debug_3("Processing input %d", prereq->id); - if(prereq->id == action_id) { - crm_debug_2("Marking input %d of synapse %d confirmed", - action_id, synapse->id); - prereq->confirmed = TRUE; - updates = TRUE; - - } else if(prereq->confirmed == FALSE) { - synapse->ready = FALSE; - } + if(prereq->id == action_id) { + crm_debug_2("Marking input %d of synapse %d confirmed", + action_id, synapse->id); + prereq->confirmed = TRUE; + updates = TRUE; + + } else if(prereq->confirmed == FALSE) { + synapse->ready = FALSE; + } - ); + } - if(updates) { - crm_debug_2("Updated synapse %d", synapse->id); - } - return updates; + if(updates) { + crm_debug_2("Updated synapse %d", synapse->id); + } + return updates; } static gboolean update_synapse_confirmed(synapse_t *synapse, int action_id) { - gboolean updates = FALSE; - gboolean is_confirmed = TRUE; + GListPtr lpc = NULL; + gboolean updates = FALSE; + gboolean is_confirmed = TRUE; - CRM_CHECK(synapse->executed, return FALSE); - CRM_CHECK(synapse->confirmed == FALSE, return TRUE); + CRM_CHECK(synapse->executed, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return TRUE); - is_confirmed = TRUE; - slist_iter( - action, crm_action_t, synapse->actions, lpc, - - crm_debug_3("Processing action %d", action->id); + is_confirmed = TRUE; + for(lpc = synapse->actions; lpc != NULL; lpc = lpc->next) { + crm_action_t *action = (crm_action_t*)lpc->data; + - if(action->id == action_id) { - crm_debug_2("Confirmed: Action %d of Synapse %d", - action_id, synapse->id); - action->confirmed = TRUE; - updates = TRUE; - - } else if(action->confirmed == FALSE) { - is_confirmed = FALSE; - crm_debug_3("Synapse %d still not confirmed after action %d", - synapse->id, action_id); - } + crm_debug_3("Processing action %d", action->id); - ); - - if(is_confirmed && synapse->confirmed == FALSE) { - crm_debug_2("Confirmed: Synapse %d", synapse->id); - synapse->confirmed = TRUE; - updates = TRUE; - } + if(action->id == action_id) { + crm_debug_2("Confirmed: Action %d of Synapse %d", + action_id, synapse->id); + action->confirmed = TRUE; + updates = TRUE; + + } else if(action->confirmed == FALSE) { + is_confirmed = FALSE; + crm_debug_3("Synapse %d still not confirmed after action %d", + synapse->id, action_id); + } + } + + if(is_confirmed && synapse->confirmed == FALSE) { + crm_debug_2("Confirmed: Synapse %d", synapse->id); + synapse->confirmed = TRUE; + updates = TRUE; + } - if(updates) { - crm_debug_3("Updated synapse %d", synapse->id); - } - return updates; + if(updates) { + crm_debug_3("Updated synapse %d", synapse->id); + } + return updates; } gboolean update_graph(crm_graph_t *graph, crm_action_t *action) { - gboolean rc = FALSE; - gboolean updates = FALSE; - slist_iter( - synapse, synapse_t, graph->synapses, lpc, - if (synapse->confirmed) { - crm_debug_2("Synapse complete"); - - } else if (synapse->executed) { - crm_debug_2("Synapse executed"); - rc = update_synapse_confirmed(synapse, action->id); - - } else if(action->failed == FALSE || synapse->priority == INFINITY) { - rc = update_synapse_ready(synapse, action->id); - } - updates = updates || rc; - ); + gboolean rc = FALSE; + gboolean updates = FALSE; + GListPtr lpc = NULL; + for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { + synapse_t *synapse = (synapse_t*)lpc->data; - if(updates) { - crm_debug_2("Updated graph with completed action %d", - action->id); + if (synapse->confirmed) { + crm_debug_2("Synapse complete"); + + } else if (synapse->executed) { + crm_debug_2("Synapse executed"); + rc = update_synapse_confirmed(synapse, action->id); + + } else if(action->failed == FALSE || synapse->priority == INFINITY) { + rc = update_synapse_ready(synapse, action->id); } - return updates; + updates = updates || rc; + } + + if(updates) { + crm_debug_2("Updated graph with completed action %d", + action->id); + } + return updates; } static gboolean should_fire_synapse(synapse_t *synapse) { - CRM_CHECK(synapse->executed == FALSE, return FALSE); - CRM_CHECK(synapse->confirmed == FALSE, return FALSE); + GListPtr lpc = NULL; + CRM_CHECK(synapse->executed == FALSE, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return FALSE); - crm_debug_3("Checking pre-reqs for %d", synapse->id); - /* lookup prereqs */ - synapse->ready = TRUE; - slist_iter( - prereq, crm_action_t, synapse->inputs, lpc, - - crm_debug_3("Processing input %d", prereq->id); - if(prereq->confirmed == FALSE) { - crm_debug_3("Inputs for synapse %d not satisfied", - synapse->id); - synapse->ready = FALSE; - break; - } - ); - - return synapse->ready; + crm_debug_3("Checking pre-reqs for %d", synapse->id); + /* lookup prereqs */ + synapse->ready = TRUE; + for(lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { + crm_action_t *prereq = (crm_action_t*)lpc->data; + crm_debug_3("Processing input %d", prereq->id); + if(prereq->confirmed == FALSE) { + crm_debug_3("Inputs for synapse %d not satisfied", + synapse->id); + synapse->ready = FALSE; + break; + } + } + + return synapse->ready; } static gboolean initiate_action(crm_graph_t *graph, crm_action_t *action) { - const char *id = NULL; - CRM_CHECK(action->executed == FALSE, return FALSE); + const char *id = NULL; + CRM_CHECK(action->executed == FALSE, return FALSE); - id = ID(action->xml); - CRM_CHECK(id != NULL, return FALSE); + id = ID(action->xml); + CRM_CHECK(id != NULL, return FALSE); - action->executed = TRUE; - if(action->type == action_type_pseudo){ - crm_debug_2("Executing pseudo-event: %d", action->id); - return graph_fns->pseudo(graph, action); + action->executed = TRUE; + if(action->type == action_type_pseudo){ + crm_debug_2("Executing pseudo-event: %d", action->id); + return graph_fns->pseudo(graph, action); - } else if(action->type == action_type_rsc) { - crm_debug_2("Executing rsc-event: %d", action->id); - return graph_fns->rsc(graph, action); + } else if(action->type == action_type_rsc) { + crm_debug_2("Executing rsc-event: %d", action->id); + return graph_fns->rsc(graph, action); - } else if(action->type == action_type_crm) { - const char *task = NULL; - task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); - CRM_CHECK(task != NULL, return FALSE); + } else if(action->type == action_type_crm) { + const char *task = NULL; + task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); + CRM_CHECK(task != NULL, return FALSE); - if(safe_str_eq(task, CRM_OP_FENCE)) { - crm_debug_2("Executing STONITH-event: %d", - action->id); - return graph_fns->stonith(graph, action); - } - - crm_debug_2("Executing crm-event: %d", action->id); - return graph_fns->crmd(graph, action); + if(safe_str_eq(task, CRM_OP_FENCE)) { + crm_debug_2("Executing STONITH-event: %d", + action->id); + return graph_fns->stonith(graph, action); } + + crm_debug_2("Executing crm-event: %d", action->id); + return graph_fns->crmd(graph, action); + } - te_log_action(LOG_ERR, - "Failed on unsupported command type: %s (id=%s)", - crm_element_name(action->xml), id); - return FALSE; + te_log_action(LOG_ERR, + "Failed on unsupported command type: %s (id=%s)", + crm_element_name(action->xml), id); + return FALSE; } static gboolean fire_synapse(crm_graph_t *graph, synapse_t *synapse) { - CRM_CHECK(synapse != NULL, return FALSE); - CRM_CHECK(synapse->ready, return FALSE); - CRM_CHECK(synapse->confirmed == FALSE, return TRUE); + GListPtr lpc = NULL; + CRM_CHECK(synapse != NULL, return FALSE); + CRM_CHECK(synapse->ready, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return TRUE); - crm_debug_2("Synapse %d fired", synapse->id); - synapse->executed = TRUE; - slist_iter( - action, crm_action_t, synapse->actions, lpc, - - /* allow some leeway */ - gboolean passed = FALSE; - - /* Invoke the action and start the timer */ - passed = initiate_action(graph, action); - if(passed == FALSE) { - crm_err("Failed initiating <%s id=%d> in synapse %d", - crm_element_name(action->xml), - action->id, synapse->id); - synapse->confirmed = TRUE; - action->confirmed = TRUE; - action->failed = TRUE; - return FALSE; - } - ); + crm_debug_2("Synapse %d fired", synapse->id); + synapse->executed = TRUE; + for(lpc = synapse->actions; lpc != NULL; lpc = lpc->next) { + crm_action_t *action = (crm_action_t*)lpc->data; + + /* allow some leeway */ + gboolean passed = FALSE; + + /* Invoke the action and start the timer */ + passed = initiate_action(graph, action); + if(passed == FALSE) { + crm_err("Failed initiating <%s id=%d> in synapse %d", + crm_element_name(action->xml), + action->id, synapse->id); + synapse->confirmed = TRUE; + action->confirmed = TRUE; + action->failed = TRUE; + return FALSE; + } + } - return TRUE; + return TRUE; } int run_graph(crm_graph_t *graph) { - int stat_log_level = LOG_DEBUG; - int pass_result = transition_active; + GListPtr lpc = NULL; + int stat_log_level = LOG_DEBUG; + int pass_result = transition_active; - const char *status = "In-progress"; + const char *status = "In-progress"; - if(graph_fns == NULL) { - set_default_graph_functions(); + if(graph_fns == NULL) { + set_default_graph_functions(); + } + if(graph == NULL) { + return transition_complete; + } + + graph->fired = 0; + graph->pending = 0; + graph->skipped = 0; + graph->completed = 0; + graph->incomplete = 0; + crm_debug_2("Entering graph %d callback", graph->id); + + /* Pre-calculate the number of completed and in-flight operations */ + for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { + synapse_t *synapse = (synapse_t*)lpc->data; + + if (synapse->confirmed) { + crm_debug_3("Synapse %d complete", synapse->id); + graph->completed++; + + } else if(synapse->executed) { + crm_debug_2("Synapse %d: confirmation pending", synapse->id); + graph->pending++; } - if(graph == NULL) { - return transition_complete; + } + + /* Now check if there is work to do */ + for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { + synapse_t *synapse = (synapse_t*)lpc->data; + + if(graph->batch_limit > 0 && graph->pending >= graph->batch_limit) { + crm_debug("Throttling output: batch limit (%d) reached", + graph->batch_limit); + break; + + } else if (synapse->confirmed || synapse->executed) { + /* Already handled */ + continue; } - graph->fired = 0; - graph->pending = 0; - graph->skipped = 0; - graph->completed = 0; - graph->incomplete = 0; - crm_debug_2("Entering graph %d callback", graph->id); - - /* Pre-calculate the number of completed and in-flight operations */ - slist_iter( - synapse, synapse_t, graph->synapses, lpc, - if (synapse->confirmed) { - crm_debug_3("Synapse %d complete", synapse->id); - graph->completed++; - - } else if(synapse->executed) { - crm_debug_2("Synapse %d: confirmation pending", synapse->id); - graph->pending++; - } - ); - - /* Now check if there is work to do */ - slist_iter( - synapse, synapse_t, graph->synapses, lpc, - - if(graph->batch_limit > 0 && graph->pending >= graph->batch_limit) { - crm_debug("Throttling output: batch limit (%d) reached", - graph->batch_limit); - break; - - } else if (synapse->confirmed || synapse->executed) { - /* Already handled */ - continue; - } - - if(synapse->priority < graph->abort_priority) { - crm_debug_2("Skipping synapse %d: aborting", synapse->id); - graph->skipped++; + if(synapse->priority < graph->abort_priority) { + crm_debug_2("Skipping synapse %d: aborting", synapse->id); + graph->skipped++; - } else if(should_fire_synapse(synapse)) { - crm_debug_2("Synapse %d fired", synapse->id); - graph->fired++; - CRM_CHECK(fire_synapse(graph, synapse), - stat_log_level = LOG_ERR; - graph->abort_priority = INFINITY; - graph->incomplete++; - graph->fired--); + } else if(should_fire_synapse(synapse)) { + crm_debug_2("Synapse %d fired", synapse->id); + graph->fired++; + CRM_CHECK(fire_synapse(graph, synapse), + stat_log_level = LOG_ERR; + graph->abort_priority = INFINITY; + graph->incomplete++; + graph->fired--); - if (synapse->confirmed == FALSE) { - graph->pending++; - } + if (synapse->confirmed == FALSE) { + graph->pending++; + } - } else { - crm_debug_2("Synapse %d cannot fire", synapse->id); - graph->incomplete++; - } - - ); - - if(graph->pending == 0 && graph->fired == 0) { - graph->complete = TRUE; - stat_log_level = LOG_NOTICE; - pass_result = transition_complete; - status = "Complete"; + } else { + crm_debug_2("Synapse %d cannot fire", synapse->id); + graph->incomplete++; + } + } - if(graph->incomplete != 0 && graph->abort_priority <= 0) { - stat_log_level = LOG_WARNING; - pass_result = transition_terminated; - status = "Terminated"; + if(graph->pending == 0 && graph->fired == 0) { + graph->complete = TRUE; + stat_log_level = LOG_NOTICE; + pass_result = transition_complete; + status = "Complete"; - } else if(graph->skipped != 0) { - status = "Stopped"; - } + if(graph->incomplete != 0 && graph->abort_priority <= 0) { + stat_log_level = LOG_WARNING; + pass_result = transition_terminated; + status = "Terminated"; - } else if(graph->fired == 0) { - pass_result = transition_pending; + } else if(graph->skipped != 0) { + status = "Stopped"; } + + } else if(graph->fired == 0) { + pass_result = transition_pending; + } - do_crm_log(stat_log_level+1, - "===================================================="); - do_crm_log(stat_log_level, - "Transition %d (Complete=%d, Pending=%d," - " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s", - graph->id, graph->completed, graph->pending, graph->fired, - graph->skipped, graph->incomplete, graph->source, status); + do_crm_log(stat_log_level+1, + "===================================================="); + do_crm_log(stat_log_level, + "Transition %d (Complete=%d, Pending=%d," + " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s", + graph->id, graph->completed, graph->pending, graph->fired, + graph->skipped, graph->incomplete, graph->source, status); - return pass_result; + return pass_result; } diff --git a/lib/transition/utils.c b/lib/transition/utils.c index a5d62a659f..c059fad1fb 100644 --- a/lib/transition/utils.c +++ b/lib/transition/utils.c @@ -1,282 +1,284 @@ /* * 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 */ /* */ extern crm_graph_functions_t *graph_fns; static gboolean pseudo_action_dummy(crm_graph_t *graph, crm_action_t *action) { static int fail = -1; if(fail < 0) { char *fail_s = getenv("PE_fail"); if(fail_s) { fail = crm_int_helper(fail_s, NULL); } else { fail = 0; } } - crm_debug_2("Dummy event handler: action %d executed", action->id); - if(action->id == fail) { - crm_err("Dummy event handler: pretending action %d failed", action->id); - action->failed = TRUE; - graph->abort_priority = INFINITY; - } - action->confirmed = TRUE; - update_graph(graph, action); - return TRUE; + crm_debug_2("Dummy event handler: action %d executed", action->id); + if(action->id == fail) { + crm_err("Dummy event handler: pretending action %d failed", action->id); + action->failed = TRUE; + graph->abort_priority = INFINITY; + } + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; } crm_graph_functions_t default_fns = { - pseudo_action_dummy, - pseudo_action_dummy, - pseudo_action_dummy, - pseudo_action_dummy + pseudo_action_dummy, + pseudo_action_dummy, + pseudo_action_dummy, + pseudo_action_dummy }; void set_default_graph_functions(void) { - graph_fns = &default_fns; + graph_fns = &default_fns; } void set_graph_functions(crm_graph_functions_t *fns) { - crm_info("Setting custom graph functions"); - graph_fns = fns; + crm_info("Setting custom graph functions"); + graph_fns = fns; - CRM_ASSERT(graph_fns != NULL); - CRM_ASSERT(graph_fns->rsc != NULL); - CRM_ASSERT(graph_fns->crmd != NULL); - CRM_ASSERT(graph_fns->pseudo != NULL); - CRM_ASSERT(graph_fns->stonith != NULL); + CRM_ASSERT(graph_fns != NULL); + CRM_ASSERT(graph_fns->rsc != NULL); + CRM_ASSERT(graph_fns->crmd != NULL); + CRM_ASSERT(graph_fns->pseudo != NULL); + CRM_ASSERT(graph_fns->stonith != NULL); } const char * transition_status(enum transition_status state) { - switch(state) { - case transition_active: - return "active"; - case transition_pending: - return "pending"; - case transition_complete: - return "complete"; - case transition_stopped: - return "stopped"; - case transition_terminated: - return "terminated"; - case transition_action_failed: - return "failed (action)"; - case transition_failed: - return "failed"; - } - return "unknown"; + switch(state) { + case transition_active: + return "active"; + case transition_pending: + return "pending"; + case transition_complete: + return "complete"; + case transition_stopped: + return "stopped"; + case transition_terminated: + return "terminated"; + case transition_action_failed: + return "failed (action)"; + case transition_failed: + return "failed"; + } + return "unknown"; } const char * actiontype2text(action_type_e type) { - switch(type) { - case action_type_pseudo: - return "pseduo"; - case action_type_rsc: - return "rsc"; - case action_type_crm: - return "crm"; + switch(type) { + case action_type_pseudo: + return "pseduo"; + case action_type_rsc: + return "rsc"; + case action_type_crm: + return "crm"; - } - return ""; + } + return ""; } static void print_elem(int log_level, const char *prefix, gboolean as_input, crm_action_t *action) { - int priority = 0; - const char *key = NULL; - const char *host = NULL; - const char *class = "Action"; - const char *state = "Pending"; + int priority = 0; + const char *key = NULL; + const char *host = NULL; + const char *class = "Action"; + const char *state = "Pending"; - if(action->failed) { - state = "Failed"; + if(action->failed) { + state = "Failed"; - } else if(action->confirmed) { - state = "Completed"; + } else if(action->confirmed) { + state = "Completed"; - } else if(action->executed) { - state = "In-flight"; + } else if(action->executed) { + state = "In-flight"; - } else if(action->sent_update) { - state = "Update sent"; - } + } else if(action->sent_update) { + state = "Update sent"; + } - if(as_input) { - class = "Input"; - } + if(as_input) { + class = "Input"; + } - if(as_input == FALSE) { - priority = action->synapse->priority; - } + if(as_input == FALSE) { + priority = action->synapse->priority; + } - key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); - host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); + host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - switch(action->type) { - case action_type_pseudo: - do_crm_log(log_level, - "%s[%s %d]: %s (id: %s, type: %s, priority: %d)", - prefix, class, action->id, state, key, - actiontype2text(action->type), - priority); - break; - case action_type_rsc: - do_crm_log(log_level, - "%s[%s %d]: %s (id: %s, loc: %s, priority: %d)", - prefix, class, action->id, state, key, host, - priority); - break; - case action_type_crm: - do_crm_log(log_level, - "%s[%s %d]: %s (id: %s, loc: %s, type: %s, priority: %d)", - prefix, class, action->id, state, key, host, - actiontype2text(action->type), - priority); - break; - default: - crm_err("%s[%s %d]: %s (id: %s, loc: %s, type: %s (unhandled), priority: %d)", - prefix, class, action->id, state, key, host, - actiontype2text(action->type), - priority); - } + switch(action->type) { + case action_type_pseudo: + do_crm_log(log_level, + "%s[%s %d]: %s (id: %s, type: %s, priority: %d)", + prefix, class, action->id, state, key, + actiontype2text(action->type), + priority); + break; + case action_type_rsc: + do_crm_log(log_level, + "%s[%s %d]: %s (id: %s, loc: %s, priority: %d)", + prefix, class, action->id, state, key, host, + priority); + break; + case action_type_crm: + do_crm_log(log_level, + "%s[%s %d]: %s (id: %s, loc: %s, type: %s, priority: %d)", + prefix, class, action->id, state, key, host, + actiontype2text(action->type), + priority); + break; + default: + crm_err("%s[%s %d]: %s (id: %s, loc: %s, type: %s (unhandled), priority: %d)", + prefix, class, action->id, state, key, host, + actiontype2text(action->type), + priority); + } - if(as_input == FALSE) { - return; - } + if(as_input == FALSE) { + return; + } - if(action->timer) { - do_crm_log(log_level, "%s\ttimeout=%d, timer=%d", prefix, - action->timeout, action->timer->source_id); - } + if(action->timer) { + do_crm_log(log_level, "%s\ttimeout=%d, timer=%d", prefix, + action->timeout, action->timer->source_id); + } - if(action->confirmed == FALSE) { - crm_log_xml(LOG_DEBUG_3, "\t\t\tRaw xml: ", action->xml); - } + if(action->confirmed == FALSE) { + crm_log_xml(LOG_DEBUG_3, "\t\t\tRaw xml: ", action->xml); + } } void print_action(int log_level, const char *prefix, crm_action_t *action) { - print_elem(log_level, prefix, FALSE, action); + print_elem(log_level, prefix, FALSE, action); } void print_graph(unsigned int log_level, crm_graph_t *graph) { - if(graph == NULL || graph->num_actions == 0) { - if(log_level > LOG_DEBUG) { - crm_debug("## Empty transition graph ##"); - } - return; + GListPtr lpc = NULL; + if(graph == NULL || graph->num_actions == 0) { + if(log_level > LOG_DEBUG) { + crm_debug("## Empty transition graph ##"); } + return; + } - do_crm_log(log_level, "Graph %d (%d actions in %d synapses):" - " batch-limit=%d jobs, network-delay=%dms", - graph->id, graph->num_actions, graph->num_synapses, - graph->batch_limit, graph->network_delay); + do_crm_log(log_level, "Graph %d (%d actions in %d synapses):" + " batch-limit=%d jobs, network-delay=%dms", + graph->id, graph->num_actions, graph->num_synapses, + graph->batch_limit, graph->network_delay); - slist_iter( - synapse, synapse_t, graph->synapses, lpc, + for(lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { + synapse_t *synapse = (synapse_t*)lpc->data; - do_crm_log(log_level, "Synapse %d %s (priority: %d)", - synapse->id, - synapse->confirmed?"was confirmed": - synapse->executed?"was executed": - "is pending", - synapse->priority); + do_crm_log(log_level, "Synapse %d %s (priority: %d)", + synapse->id, + synapse->confirmed?"was confirmed": + synapse->executed?"was executed": + "is pending", + synapse->priority); - if(synapse->confirmed == FALSE) { - slist_iter( - action, crm_action_t, synapse->actions, lpc2, - print_elem(log_level, " ", FALSE, action); - ); - } - if(synapse->executed == FALSE) { - slist_iter( - input, crm_action_t, synapse->inputs, lpc2, - print_elem(log_level, " * ", TRUE, input); - ); - } - - ); + if(synapse->confirmed == FALSE) { + GListPtr lpc2 = NULL; + for(lpc2 = synapse->actions; lpc2 != NULL; lpc2 = lpc2->next) { + crm_action_t *action = (crm_action_t*)lpc2->data; + print_elem(log_level, " ", FALSE, action); + } + } + if(synapse->executed == FALSE) { + GListPtr lpc2 = NULL; + for(lpc2 = synapse->inputs; lpc2 != NULL; lpc2 = lpc2->next) { + crm_action_t *input = (crm_action_t*)lpc2->data; + print_elem(log_level, " * ", TRUE, input); + } + } + } } static const char *abort2text(enum transition_action abort_action) { switch(abort_action) { case tg_done: return "done"; case tg_stop: return "stop"; case tg_restart: return "restart"; case tg_shutdown: return "shutdown"; } return "unknown"; } void update_abort_priority( - crm_graph_t *graph, int priority, - enum transition_action action, const char *abort_reason) + crm_graph_t *graph, int priority, + enum transition_action action, const char *abort_reason) { - if(graph == NULL) { - return; - } + if(graph == NULL) { + return; + } - if(graph->abort_priority < priority) { - crm_info("Abort priority upgraded from %d to %d", - graph->abort_priority, priority); - graph->abort_priority = priority; - if(graph->abort_reason != NULL) { - crm_info("'%s' abort superceeded", - graph->abort_reason); - } - graph->abort_reason = abort_reason; + if(graph->abort_priority < priority) { + crm_info("Abort priority upgraded from %d to %d", + graph->abort_priority, priority); + graph->abort_priority = priority; + if(graph->abort_reason != NULL) { + crm_info("'%s' abort superceeded", + graph->abort_reason); } + graph->abort_reason = abort_reason; + } - if(graph->completion_action < action) { - crm_info("Abort action %s superceeded by %s", - abort2text(graph->completion_action), abort2text(action)); - graph->completion_action = action; - } + if(graph->completion_action < action) { + crm_info("Abort action %s superceeded by %s", + abort2text(graph->completion_action), abort2text(action)); + graph->completion_action = action; + } } diff --git a/pengine/allocate.c b/pengine/allocate.c index 2e4fa7b59d..962a00be1f 100644 --- a/pengine/allocate.c +++ b/pengine/allocate.c @@ -1,1936 +1,2026 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include CRM_TRACE_INIT_DATA(pe_allocate); void set_alloc_actions(pe_working_set_t *data_set); void migrate_reload_madness(pe_working_set_t *data_set); resource_alloc_functions_t resource_class_alloc_functions[] = { - { - rsc_merge_weights, - native_color, - native_create_actions, - native_create_probe, - native_internal_constraints, - native_rsc_colocation_lh, - native_rsc_colocation_rh, - native_rsc_location, - native_action_flags, - native_update_actions, - native_expand, - native_append_meta, - }, - { - group_merge_weights, - group_color, - group_create_actions, - native_create_probe, - group_internal_constraints, - group_rsc_colocation_lh, - group_rsc_colocation_rh, - group_rsc_location, - group_action_flags, - group_update_actions, - group_expand, - group_append_meta, - }, - { - rsc_merge_weights, - clone_color, - clone_create_actions, - clone_create_probe, - clone_internal_constraints, - clone_rsc_colocation_lh, - clone_rsc_colocation_rh, - clone_rsc_location, - clone_action_flags, - clone_update_actions, - clone_expand, - clone_append_meta, - }, - { - rsc_merge_weights, - master_color, - master_create_actions, - clone_create_probe, - master_internal_constraints, - clone_rsc_colocation_lh, - master_rsc_colocation_rh, - clone_rsc_location, - clone_action_flags, - clone_update_actions, - clone_expand, - master_append_meta, - } + { + rsc_merge_weights, + native_color, + native_create_actions, + native_create_probe, + native_internal_constraints, + native_rsc_colocation_lh, + native_rsc_colocation_rh, + native_rsc_location, + native_action_flags, + native_update_actions, + native_expand, + native_append_meta, + }, + { + group_merge_weights, + group_color, + group_create_actions, + native_create_probe, + group_internal_constraints, + group_rsc_colocation_lh, + group_rsc_colocation_rh, + group_rsc_location, + group_action_flags, + group_update_actions, + group_expand, + group_append_meta, + }, + { + rsc_merge_weights, + clone_color, + clone_create_actions, + clone_create_probe, + clone_internal_constraints, + clone_rsc_colocation_lh, + clone_rsc_colocation_rh, + clone_rsc_location, + clone_action_flags, + clone_update_actions, + clone_expand, + clone_append_meta, + }, + { + rsc_merge_weights, + master_color, + master_create_actions, + clone_create_probe, + master_internal_constraints, + clone_rsc_colocation_lh, + master_rsc_colocation_rh, + clone_rsc_location, + clone_action_flags, + clone_update_actions, + clone_expand, + master_append_meta, + } }; static gboolean check_rsc_parameters(resource_t *rsc, node_t *node, xmlNode *rsc_entry, pe_working_set_t *data_set) { - int attr_lpc = 0; - gboolean force_restart = FALSE; - gboolean delete_resource = FALSE; + int attr_lpc = 0; + gboolean force_restart = FALSE; + gboolean delete_resource = FALSE; - const char *value = NULL; - const char *old_value = NULL; - const char *attr_list[] = { - XML_ATTR_TYPE, - XML_AGENT_ATTR_CLASS, - XML_AGENT_ATTR_PROVIDER - }; - - for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { - value = crm_element_value(rsc->xml, attr_list[attr_lpc]); - old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); - if(value == old_value /* ie. NULL */ - || crm_str_eq(value, old_value, TRUE)) { - continue; - } - - force_restart = TRUE; - crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", - rsc->id, node->details->uname, attr_list[attr_lpc], - crm_str(old_value), crm_str(value)); - } - if(force_restart) { - /* make sure the restart happens */ - stop_action(rsc, node, FALSE); - set_bit(rsc->flags, pe_rsc_start_pending); - delete_resource = TRUE; + const char *value = NULL; + const char *old_value = NULL; + const char *attr_list[] = { + XML_ATTR_TYPE, + XML_AGENT_ATTR_CLASS, + XML_AGENT_ATTR_PROVIDER + }; + + for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { + value = crm_element_value(rsc->xml, attr_list[attr_lpc]); + old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); + if(value == old_value /* ie. NULL */ + || crm_str_eq(value, old_value, TRUE)) { + continue; } - return delete_resource; + + force_restart = TRUE; + crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", + rsc->id, node->details->uname, attr_list[attr_lpc], + crm_str(old_value), crm_str(value)); + } + if(force_restart) { + /* make sure the restart happens */ + stop_action(rsc, node, FALSE); + set_bit(rsc->flags, pe_rsc_start_pending); + delete_resource = TRUE; + } + return delete_resource; } static void CancelXmlOp(resource_t *rsc, xmlNode *xml_op, node_t *active_node, const char *reason, pe_working_set_t *data_set) { int interval = 0; action_t *cancel = NULL; char *key = NULL; const char *task = NULL; const char *call_id = NULL; const char *interval_s = NULL; CRM_CHECK(xml_op != NULL, return); CRM_CHECK(active_node != NULL, return); task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); /* we need to reconstruct the key because of the way we used to construct resource IDs */ key = generate_op_key(rsc->id, task, interval); crm_info("Action %s on %s will be stopped: %s", key, active_node->details->uname, reason?reason:"unknown"); cancel = custom_action(rsc, crm_strdup(key), RSC_CANCEL, active_node, FALSE, TRUE, data_set); crm_free(cancel->task); cancel->task = crm_strdup(RSC_CANCEL); add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task); add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID, call_id); add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s); custom_action_order(rsc, stop_key(rsc), NULL, rsc, NULL, cancel, pe_order_optional, data_set); crm_free(key); key = NULL; } static gboolean check_action_definition(resource_t *rsc, node_t *active_node, xmlNode *xml_op, pe_working_set_t *data_set) { - char *key = NULL; - int interval = 0; - const char *interval_s = NULL; + char *key = NULL; + int interval = 0; + const char *interval_s = NULL; - gboolean did_change = FALSE; - gboolean start_op = FALSE; + gboolean did_change = FALSE; + gboolean start_op = FALSE; - xmlNode *params_all = NULL; - xmlNode *params_restart = NULL; - GHashTable *local_rsc_params = NULL; + xmlNode *params_all = NULL; + xmlNode *params_restart = NULL; + GHashTable *local_rsc_params = NULL; - char *digest_all_calc = NULL; - const char *digest_all = NULL; + char *digest_all_calc = NULL; + const char *digest_all = NULL; - const char *restart_list = NULL; - const char *digest_restart = NULL; - char *digest_restart_calc = NULL; + const char *restart_list = NULL; + const char *digest_restart = NULL; + char *digest_restart_calc = NULL; - action_t *action = NULL; - const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); - const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); + action_t *action = NULL; + const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); + const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); - CRM_CHECK(active_node != NULL, return FALSE); + CRM_CHECK(active_node != NULL, return FALSE); - interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); - interval = crm_parse_int(interval_s, "0"); - /* we need to reconstruct the key because of the way we used to construct resource IDs */ - key = generate_op_key(rsc->id, task, interval); + interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); + interval = crm_parse_int(interval_s, "0"); + /* we need to reconstruct the key because of the way we used to construct resource IDs */ + key = generate_op_key(rsc->id, task, interval); - if(interval > 0) { - xmlNode *op_match = NULL; + if(interval > 0) { + xmlNode *op_match = NULL; - crm_debug_2("Checking parameters for %s", key); - op_match = find_rsc_op_entry(rsc, key); + crm_debug_2("Checking parameters for %s", key); + op_match = find_rsc_op_entry(rsc, key); - if(op_match == NULL && is_set(data_set->flags, pe_flag_stop_action_orphans)) { - CancelXmlOp(rsc, xml_op, active_node, "orphan", data_set); - crm_free(key); key = NULL; - return TRUE; + if(op_match == NULL && is_set(data_set->flags, pe_flag_stop_action_orphans)) { + CancelXmlOp(rsc, xml_op, active_node, "orphan", data_set); + crm_free(key); key = NULL; + return TRUE; - } else if(op_match == NULL) { - crm_debug("Orphan action detected: %s on %s", - key, active_node->details->uname); - crm_free(key); key = NULL; - return TRUE; - } + } else if(op_match == NULL) { + crm_debug("Orphan action detected: %s on %s", + key, active_node->details->uname); + crm_free(key); key = NULL; + return TRUE; } + } - action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); + action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); - local_rsc_params = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); + local_rsc_params = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, g_hash_destroy_str); - get_rsc_attributes(local_rsc_params, rsc, active_node, data_set); + get_rsc_attributes(local_rsc_params, rsc, active_node, data_set); - params_all = create_xml_node(NULL, XML_TAG_PARAMS); - g_hash_table_foreach(local_rsc_params, hash2field, params_all); - g_hash_table_foreach(action->extra, hash2field, params_all); - g_hash_table_foreach(rsc->parameters, hash2field, params_all); - g_hash_table_foreach(action->meta, hash2metafield, params_all); - - filter_action_parameters(params_all, op_version); - digest_all_calc = calculate_operation_digest(params_all, op_version); - digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); - digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST); - restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART); - - if(crm_str_eq(task, RSC_START, TRUE)) { - start_op = TRUE; - } + params_all = create_xml_node(NULL, XML_TAG_PARAMS); + g_hash_table_foreach(local_rsc_params, hash2field, params_all); + g_hash_table_foreach(action->extra, hash2field, params_all); + g_hash_table_foreach(rsc->parameters, hash2field, params_all); + g_hash_table_foreach(action->meta, hash2metafield, params_all); + + filter_action_parameters(params_all, op_version); + digest_all_calc = calculate_operation_digest(params_all, op_version); + digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); + digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST); + restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART); + + if(crm_str_eq(task, RSC_START, TRUE)) { + start_op = TRUE; + } - if(start_op && digest_restart) { - params_restart = copy_xml(params_all); - if(restart_list) { - filter_reload_parameters(params_restart, restart_list); - } + if(start_op && digest_restart) { + params_restart = copy_xml(params_all); + if(restart_list) { + filter_reload_parameters(params_restart, restart_list); + } - digest_restart_calc = calculate_operation_digest(params_restart, op_version); - if(safe_str_neq(digest_restart_calc, digest_restart)) { - did_change = TRUE; - crm_log_xml_info(params_restart, "params:restart"); - crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (restart:%s) %s", - key, active_node->details->uname, - crm_str(digest_restart), digest_restart_calc, - op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); + digest_restart_calc = calculate_operation_digest(params_restart, op_version); + if(safe_str_neq(digest_restart_calc, digest_restart)) { + did_change = TRUE; + crm_log_xml_info(params_restart, "params:restart"); + crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (restart:%s) %s", + key, active_node->details->uname, + crm_str(digest_restart), digest_restart_calc, + op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); - key = generate_op_key(rsc->id, task, interval); - custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); - goto cleanup; - } + key = generate_op_key(rsc->id, task, interval); + custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); + goto cleanup; } + } - if(safe_str_neq(digest_all_calc, digest_all)) { - action_t *op = NULL; - did_change = TRUE; - crm_log_xml_info(params_all, "params:all"); - crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (all:%s) %s", - key, active_node->details->uname, - crm_str(digest_all), digest_all_calc, op_version, - crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); - - if(interval == 0 && safe_str_neq(task, RSC_STOP)) { - /* Anything except stop actions should result in a restart, - * never a re-probe - */ - task = RSC_START; - } - - key = generate_op_key(rsc->id, task, interval); - op = custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); - if(start_op && digest_restart) { - update_action_flags(op, pe_action_allow_reload_conversion); - - } else if(interval > 0) { - custom_action_order(rsc, start_key(rsc), NULL, - NULL, crm_strdup(op->task), op, - pe_order_runnable_left, data_set); - } + if(safe_str_neq(digest_all_calc, digest_all)) { + action_t *op = NULL; + did_change = TRUE; + crm_log_xml_info(params_all, "params:all"); + crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (all:%s) %s", + key, active_node->details->uname, + crm_str(digest_all), digest_all_calc, op_version, + crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); + + if(interval == 0 && safe_str_neq(task, RSC_STOP)) { + /* Anything except stop actions should result in a restart, + * never a re-probe + */ + task = RSC_START; + } + key = generate_op_key(rsc->id, task, interval); + op = custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); + if(start_op && digest_restart) { + update_action_flags(op, pe_action_allow_reload_conversion); + + } else if(interval > 0) { + custom_action_order(rsc, start_key(rsc), NULL, + NULL, crm_strdup(op->task), op, + pe_order_runnable_left, data_set); } + + } cleanup: - free_xml(params_all); - free_xml(params_restart); - crm_free(digest_all_calc); - crm_free(digest_restart_calc); - g_hash_table_destroy(local_rsc_params); + free_xml(params_all); + free_xml(params_restart); + crm_free(digest_all_calc); + crm_free(digest_restart_calc); + g_hash_table_destroy(local_rsc_params); - pe_free_action(action); + pe_free_action(action); - return did_change; + return did_change; } extern gboolean DeleteRsc(resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set); static void check_actions_for(xmlNode *rsc_entry, resource_t *rsc, node_t *node, pe_working_set_t *data_set) { - int interval = 0; - int stop_index = 0; - int start_index = 0; + GListPtr gIter = NULL; + int offset = -1; + int interval = 0; + int stop_index = 0; + int start_index = 0; - const char *task = NULL; - const char *interval_s = NULL; + const char *task = NULL; + const char *interval_s = NULL; - GListPtr op_list = NULL; - GListPtr sorted_op_list = NULL; - gboolean is_probe = FALSE; + GListPtr op_list = NULL; + GListPtr sorted_op_list = NULL; + gboolean is_probe = FALSE; - CRM_CHECK(node != NULL, return); + CRM_CHECK(node != NULL, return); - if(is_set(rsc->flags, pe_rsc_orphan)) { - crm_debug_2("Skipping param check for %s: orphan", rsc->id); - return; + if(is_set(rsc->flags, pe_rsc_orphan)) { + crm_debug_2("Skipping param check for %s: orphan", rsc->id); + return; - } else if(pe_find_node_id(rsc->running_on, node->details->id) == NULL) { - crm_debug_2("Skipping param check for %s: no longer active on %s", - rsc->id, node->details->uname); - return; - } + } else if(pe_find_node_id(rsc->running_on, node->details->id) == NULL) { + crm_debug_2("Skipping param check for %s: no longer active on %s", + rsc->id, node->details->uname); + return; + } - crm_debug_3("Processing %s on %s", rsc->id, node->details->uname); + crm_debug_3("Processing %s on %s", rsc->id, node->details->uname); - if(check_rsc_parameters(rsc, node, rsc_entry, data_set)) { - DeleteRsc(rsc, node, FALSE, data_set); - } + if(check_rsc_parameters(rsc, node, rsc_entry, data_set)) { + DeleteRsc(rsc, node, FALSE, data_set); + } - xml_child_iter_filter( - rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, - op_list = g_list_prepend(op_list, rsc_op); - ); + xml_child_iter_filter( + rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, + op_list = g_list_prepend(op_list, rsc_op); + ); - sorted_op_list = g_list_sort(op_list, sort_op_by_callid); - calculate_active_ops(sorted_op_list, &start_index, &stop_index); + sorted_op_list = g_list_sort(op_list, sort_op_by_callid); + calculate_active_ops(sorted_op_list, &start_index, &stop_index); - slist_iter( - rsc_op, xmlNode, sorted_op_list, lpc, + gIter = sorted_op_list; + for(; gIter != NULL; gIter = gIter->next) { + xmlNode *rsc_op = (xmlNode*)gIter->data; + offset++; - if(start_index < stop_index) { - /* stopped */ - continue; - } else if(lpc < start_index) { - /* action occurred prior to a start */ - continue; - } + if(start_index < stop_index) { + /* stopped */ + continue; + } else if(offset < start_index) { + /* action occurred prior to a start */ + continue; + } - is_probe = FALSE; - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); + is_probe = FALSE; + task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - interval_s = crm_element_value(rsc_op, XML_LRM_ATTR_INTERVAL); - interval = crm_parse_int(interval_s, "0"); + interval_s = crm_element_value(rsc_op, XML_LRM_ATTR_INTERVAL); + interval = crm_parse_int(interval_s, "0"); - if(interval == 0 && safe_str_eq(task, RSC_STATUS)) { - is_probe = TRUE; - } + if(interval == 0 && safe_str_eq(task, RSC_STATUS)) { + is_probe = TRUE; + } - if(interval > 0 && is_set(data_set->flags, pe_flag_maintenance_mode)) { - CancelXmlOp(rsc, rsc_op, node, "maintenance mode", data_set); + if(interval > 0 && is_set(data_set->flags, pe_flag_maintenance_mode)) { + CancelXmlOp(rsc, rsc_op, node, "maintenance mode", data_set); - } else if(is_probe || safe_str_eq(task, RSC_START) || interval > 0) { - check_action_definition(rsc, node, rsc_op, data_set); - } - ); + } else if(is_probe || safe_str_eq(task, RSC_START) || interval > 0) { + check_action_definition(rsc, node, rsc_op, data_set); + } + } - g_list_free(sorted_op_list); + g_list_free(sorted_op_list); } static GListPtr find_rsc_list( GListPtr result, resource_t *rsc, const char *id, gboolean renamed_clones, gboolean partial, pe_working_set_t *data_set) { + GListPtr gIter = NULL; gboolean match = FALSE; if(id == NULL) { return NULL; } else if(rsc == NULL && data_set) { - slist_iter(child, resource_t, data_set->resources, lpc, - result = find_rsc_list(result, child, id, renamed_clones, partial, NULL)); + + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + + result = find_rsc_list(result, child, id, renamed_clones, partial, NULL); + } + return result; } else if(rsc == NULL) { return NULL; } if(partial) { if(strstr(rsc->id, id)) { match = TRUE; } else if(rsc->long_name && strstr(rsc->long_name, id)) { match = TRUE; } else if(renamed_clones && rsc->clone_name && strstr(rsc->clone_name, id)) { match = TRUE; } } else { if(strcmp(rsc->id, id) == 0){ match = TRUE; } else if(rsc->long_name && strcmp(rsc->long_name, id) == 0) { match = TRUE; } else if(renamed_clones && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) { match = TRUE; } } if(match) { - result = g_list_prepend(result, rsc); + result = g_list_prepend(result, rsc); } if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - result = find_rsc_list(result, child, id, renamed_clones, partial, NULL); - ); + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + result = find_rsc_list(result, child, id, renamed_clones, partial, NULL); + } } return result; } static void check_actions(pe_working_set_t *data_set) { const char *id = NULL; node_t *node = NULL; xmlNode *lrm_rscs = NULL; xmlNode *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); lrm_rscs = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rscs = find_xml_node(lrm_rscs, XML_LRM_TAG_RESOURCES, FALSE); node = pe_find_node_id(data_set->nodes, id); if(node == NULL) { continue; } else if(can_run_resources(node) == FALSE) { crm_debug_2("Skipping param check for %s: cant run resources", node->details->uname); continue; } crm_debug_2("Processing node %s", node->details->uname); if(node->details->online || is_set(data_set->flags, pe_flag_stonith_enabled)) { xml_child_iter_filter( lrm_rscs, rsc_entry, XML_LRM_TAG_RESOURCE, if(xml_has_children(rsc_entry)) { + GListPtr gIter = NULL; GListPtr result = NULL; const char *rsc_id = ID(rsc_entry); CRM_CHECK(rsc_id != NULL, return); result = find_rsc_list(NULL, NULL, rsc_id, TRUE, FALSE, data_set); - slist_iter(rsc, resource_t, result, lpc, - check_actions_for(rsc_entry, rsc, node, data_set)); + gIter = result; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + + check_actions_for(rsc_entry, rsc, node, data_set); + } g_list_free(result); } ); } ); } static gboolean apply_placement_constraints(pe_working_set_t *data_set) { - crm_debug_3("Applying constraints..."); - slist_iter( - cons, rsc_to_node_t, data_set->placement_constraints, lpc, + GListPtr gIter = data_set->placement_constraints; + crm_debug_3("Applying constraints..."); - cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons); - ); + for(; gIter != NULL; gIter = gIter->next) { + rsc_to_node_t *cons = (rsc_to_node_t*)gIter->data; + + cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons); + } - return TRUE; + return TRUE; } static void common_apply_stickiness(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { - int fail_count = 0; - resource_t *failed = rsc; + int fail_count = 0; + resource_t *failed = rsc; - if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - common_apply_stickiness(child_rsc, node, data_set); - ); - return; + if(rsc->children) { + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + common_apply_stickiness(child_rsc, node, data_set); } + return; + } - if(is_set(rsc->flags, pe_rsc_managed) - && rsc->stickiness != 0 - && g_list_length(rsc->running_on) == 1) { - node_t *current = pe_find_node_id(rsc->running_on, node->details->id); - node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id); + if(is_set(rsc->flags, pe_rsc_managed) + && rsc->stickiness != 0 + && g_list_length(rsc->running_on) == 1) { + node_t *current = pe_find_node_id(rsc->running_on, node->details->id); + node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id); - if(current == NULL) { + if(current == NULL) { - } else if(match != NULL || is_set(data_set->flags, pe_flag_symmetric_cluster)) { - resource_t *sticky_rsc = rsc; + } else if(match != NULL || is_set(data_set->flags, pe_flag_symmetric_cluster)) { + resource_t *sticky_rsc = rsc; - resource_location(sticky_rsc, node, rsc->stickiness, "stickiness", data_set); - crm_debug("Resource %s: preferring current location" - " (node=%s, weight=%d)", sticky_rsc->id, - node->details->uname, rsc->stickiness); - } else { - GHashTableIter iter; - node_t *node = NULL; - crm_debug("Ignoring stickiness for %s: the cluster is asymmetric" - " and node %s is not explicitly allowed", - rsc->id, node->details->uname); - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - crm_err("%s[%s] = %d", rsc->id, node->details->uname, node->weight); - } + resource_location(sticky_rsc, node, rsc->stickiness, "stickiness", data_set); + crm_debug("Resource %s: preferring current location" + " (node=%s, weight=%d)", sticky_rsc->id, + node->details->uname, rsc->stickiness); + } else { + GHashTableIter iter; + node_t *node = NULL; + crm_debug("Ignoring stickiness for %s: the cluster is asymmetric" + " and node %s is not explicitly allowed", + rsc->id, node->details->uname); + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + crm_err("%s[%s] = %d", rsc->id, node->details->uname, node->weight); } } + } - if(is_not_set(rsc->flags, pe_rsc_unique)) { - failed = uber_parent(rsc); - } + if(is_not_set(rsc->flags, pe_rsc_unique)) { + failed = uber_parent(rsc); + } - fail_count = get_failcount(node, rsc, NULL, data_set); - if(fail_count > 0 && rsc->migration_threshold != 0) { - if(rsc->migration_threshold <= fail_count) { - resource_location(failed, node, -INFINITY, "__fail_limit__", data_set); - crm_warn("Forcing %s away from %s after %d failures (max=%d)", - failed->id, node->details->uname, fail_count, rsc->migration_threshold); - } else { - crm_notice("%s can fail %d more times on %s before being forced off", - failed->id, rsc->migration_threshold - fail_count, node->details->uname); - } + fail_count = get_failcount(node, rsc, NULL, data_set); + if(fail_count > 0 && rsc->migration_threshold != 0) { + if(rsc->migration_threshold <= fail_count) { + resource_location(failed, node, -INFINITY, "__fail_limit__", data_set); + crm_warn("Forcing %s away from %s after %d failures (max=%d)", + failed->id, node->details->uname, fail_count, rsc->migration_threshold); + } else { + crm_notice("%s can fail %d more times on %s before being forced off", + failed->id, rsc->migration_threshold - fail_count, node->details->uname); } + } } static void complex_set_cmds(resource_t *rsc) { + GListPtr gIter = rsc->children; rsc->cmds = &resource_class_alloc_functions[rsc->variant]; - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; complex_set_cmds(child_rsc); - ); + } } void set_alloc_actions(pe_working_set_t *data_set) { - slist_iter( - rsc, resource_t, data_set->resources, lpc, - complex_set_cmds(rsc); - ); + + GListPtr gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + complex_set_cmds(rsc); + } } static void calculate_system_health (gpointer gKey, gpointer gValue, gpointer user_data) { - const char *key = (const char *)gKey; - const char *value = (const char *)gValue; - int *system_health = (int *)user_data; + const char *key = (const char *)gKey; + const char *value = (const char *)gValue; + int *system_health = (int *)user_data; - if (!gKey || !gValue || !user_data) { - return; - } + if (!gKey || !gValue || !user_data) { + return; + } - /* Does it start with #health? */ - if (0 == strncmp (key, "#health", 7)) { - int score; + /* Does it start with #health? */ + if (0 == strncmp (key, "#health", 7)) { + int score; - /* Convert the value into an integer */ - score = char2score (value); + /* Convert the value into an integer */ + score = char2score (value); - /* Add it to the running total */ - *system_health = merge_weights (score, *system_health); - } + /* Add it to the running total */ + *system_health = merge_weights (score, *system_health); + } } static gboolean apply_system_health(pe_working_set_t *data_set) { + GListPtr gIter = NULL; const char *health_strategy = pe_pref(data_set->config_hash, "node-health-strategy"); if (health_strategy == NULL || safe_str_eq (health_strategy, "none")) { /* Prevent any accidental health -> score translation */ node_score_red = 0; node_score_yellow = 0; node_score_green = 0; return TRUE; } else if (safe_str_eq (health_strategy, "migrate-on-red")) { /* Resources on nodes which have health values of red are * weighted away from that node. */ node_score_red = -INFINITY; node_score_yellow = 0; node_score_green = 0; } else if (safe_str_eq (health_strategy, "only-green")) { /* Resources on nodes which have health values of red or yellow * are forced away from that node. */ node_score_red = -INFINITY; node_score_yellow = -INFINITY; node_score_green = 0; } else if (safe_str_eq (health_strategy, "progressive")) { /* Same as the above, but use the r/y/g scores provided by the user * Defaults are provided by the pe_prefs table */ } else if (safe_str_eq (health_strategy, "custom")) { /* Requires the admin to configure the rsc_location constaints for * processing the stored health scores */ /* TODO: Check for the existance of appropriate node health constraints */ return TRUE; } else { crm_err ("Unknown node health strategy: %s", health_strategy); return FALSE; } crm_info ("Applying automated node health strategy: %s", health_strategy); - slist_iter( - node, node_t, data_set->nodes, lpc, + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { int system_health = 0; + node_t *node = (node_t*)gIter->data; /* Search through the node hash table for system health entries. */ g_hash_table_foreach ( node->details->attrs, calculate_system_health, &system_health); crm_info (" Node %s has an combined system health of %d", node->details->uname, system_health); /* If the health is non-zero, then create a new rsc2node so that the * weight will be added later on. */ if (system_health != 0) { - slist_iter( - rsc, resource_t, data_set->resources, lpc, + + GListPtr gIter2 = data_set->resources; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + resource_t *rsc = (resource_t*)gIter2->data; rsc2node_new (health_strategy, rsc, system_health, node, data_set); - ); + } } - ); + } return TRUE; } gboolean stage0(pe_working_set_t *data_set) { - xmlNode * cib_constraints = get_object_root( - XML_CIB_TAG_CONSTRAINTS, data_set->input); + xmlNode * cib_constraints = get_object_root( + XML_CIB_TAG_CONSTRAINTS, data_set->input); - if(data_set->input == NULL) { - return FALSE; - } + if(data_set->input == NULL) { + return FALSE; + } - if(is_set(data_set->flags, pe_flag_have_status) == FALSE) { - crm_trace("Calculating status"); - cluster_status(data_set); - } + if(is_set(data_set->flags, pe_flag_have_status) == FALSE) { + crm_trace("Calculating status"); + cluster_status(data_set); + } - set_alloc_actions(data_set); - apply_system_health(data_set); - unpack_constraints(cib_constraints, data_set); + set_alloc_actions(data_set); + apply_system_health(data_set); + unpack_constraints(cib_constraints, data_set); - return TRUE; + return TRUE; } static void wait_for_probe( resource_t *rsc, const char *action, action_t *probe_complete, pe_working_set_t *data_set) { if(probe_complete == NULL) { return; } if(rsc->children) { - slist_iter( - child, resource_t, rsc->children, lpc, + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; wait_for_probe(child, action, probe_complete, data_set); - ); + } } else { char *key = generate_op_key(rsc->id, action, 0); custom_action_order( NULL, NULL, probe_complete, rsc, key, NULL, pe_order_optional, data_set); } } /* * Check nodes for resources started outside of the LRM */ gboolean probe_resources(pe_working_set_t *data_set) { - action_t *probe_complete = NULL; - action_t *probe_node_complete = NULL; + action_t *probe_complete = NULL; + action_t *probe_node_complete = NULL; + + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; - slist_iter( - node, node_t, data_set->nodes, lpc, - gboolean force_probe = FALSE; - const char *probed = g_hash_table_lookup( - node->details->attrs, CRM_OP_PROBED); + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + gboolean force_probe = FALSE; + const char *probed = g_hash_table_lookup( + node->details->attrs, CRM_OP_PROBED); - if(node->details->online == FALSE) { - continue; + + if(node->details->online == FALSE) { + continue; - } else if(node->details->unclean) { - continue; + } else if(node->details->unclean) { + continue; - } else if(probe_complete == NULL) { - probe_complete = get_pseudo_op(CRM_OP_PROBED, data_set); - } + } else if(probe_complete == NULL) { + probe_complete = get_pseudo_op(CRM_OP_PROBED, data_set); + } - if(probed != NULL && crm_is_true(probed) == FALSE) { - force_probe = TRUE; - } + if(probed != NULL && crm_is_true(probed) == FALSE) { + force_probe = TRUE; + } - probe_node_complete = custom_action( - NULL, crm_strdup(CRM_OP_PROBED), - CRM_OP_PROBED, node, FALSE, TRUE, data_set); - if(crm_is_true(probed)) { - crm_trace("unset"); - update_action_flags(probe_node_complete, pe_action_optional); - } else { - crm_trace("set"); - update_action_flags(probe_node_complete, pe_action_optional|pe_action_clear); - } - crm_trace("%s - %d", node->details->uname, probe_node_complete->flags & pe_action_optional); - probe_node_complete->priority = INFINITY; - add_hash_param(probe_node_complete->meta, - XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - - if(node->details->pending) { - update_action_flags(probe_node_complete, pe_action_runnable|pe_action_clear); - crm_info("Action %s on %s is unrunnable (pending)", - probe_node_complete->uuid, probe_node_complete->node->details->uname); - } + probe_node_complete = custom_action( + NULL, crm_strdup(CRM_OP_PROBED), + CRM_OP_PROBED, node, FALSE, TRUE, data_set); + if(crm_is_true(probed)) { + crm_trace("unset"); + update_action_flags(probe_node_complete, pe_action_optional); + } else { + crm_trace("set"); + update_action_flags(probe_node_complete, pe_action_optional|pe_action_clear); + } + crm_trace("%s - %d", node->details->uname, probe_node_complete->flags & pe_action_optional); + probe_node_complete->priority = INFINITY; + add_hash_param(probe_node_complete->meta, + XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); + + if(node->details->pending) { + update_action_flags(probe_node_complete, pe_action_runnable|pe_action_clear); + crm_info("Action %s on %s is unrunnable (pending)", + probe_node_complete->uuid, probe_node_complete->node->details->uname); + } - order_actions(probe_node_complete, probe_complete, pe_order_runnable_left/*|pe_order_implies_then*/); + order_actions(probe_node_complete, probe_complete, pe_order_runnable_left/*|pe_order_implies_then*/); - slist_iter( - rsc, resource_t, data_set->resources, lpc2, - - if(rsc->cmds->create_probe( - rsc, node, probe_node_complete, - force_probe, data_set)) { + gIter2 = data_set->resources; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + resource_t *rsc = (resource_t*)gIter2->data; + + if(rsc->cmds->create_probe( + rsc, node, probe_node_complete, + force_probe, data_set)) { - update_action_flags(probe_complete, pe_action_optional|pe_action_clear); - update_action_flags(probe_node_complete, pe_action_optional|pe_action_clear); + update_action_flags(probe_complete, pe_action_optional|pe_action_clear); + update_action_flags(probe_node_complete, pe_action_optional|pe_action_clear); - wait_for_probe(rsc, CRMD_ACTION_START, probe_complete, data_set); - } - ); - ); + wait_for_probe(rsc, CRMD_ACTION_START, probe_complete, data_set); + } + } + } - slist_iter( - rsc, resource_t, data_set->resources, lpc, - wait_for_probe(rsc, CRMD_ACTION_STOP, probe_complete, data_set)); + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; - return TRUE; + wait_for_probe(rsc, CRMD_ACTION_STOP, probe_complete, data_set); + } + + return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage2(pe_working_set_t *data_set) { - crm_debug_3("Applying placement constraints"); + GListPtr gIter = NULL; + crm_debug_3("Applying placement constraints"); - slist_iter( - node, node_t, data_set->nodes, lpc, - if(node == NULL) { - /* error */ - - } else if(node->weight >= 0.0 /* global weight */ - && node->details->online - && node->details->type == node_member) { - data_set->max_valid_nodes++; - } - ); + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + + if(node == NULL) { + /* error */ - apply_placement_constraints(data_set); + } else if(node->weight >= 0.0 /* global weight */ + && node->details->online + && node->details->type == node_member) { + data_set->max_valid_nodes++; + } + } - slist_iter(node, node_t, data_set->nodes, lpc, - slist_iter( - rsc, resource_t, data_set->resources, lpc2, - common_apply_stickiness(rsc, node, data_set); - ); - ); + apply_placement_constraints(data_set); - return TRUE; + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + GListPtr gIter2 = NULL; + node_t *node = (node_t*)gIter->data; + + gIter2 = data_set->resources; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + resource_t *rsc = (resource_t*)gIter2->data; + common_apply_stickiness(rsc, node, data_set); + } + } + + return TRUE; } /* * Create internal resource constraints before allocation */ gboolean stage3(pe_working_set_t *data_set) { - slist_iter( - rsc, resource_t, data_set->resources, lpc, - rsc->cmds->internal_constraints(rsc, data_set); - ); + + GListPtr gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + rsc->cmds->internal_constraints(rsc, data_set); + } - return TRUE; + return TRUE; } /* * Check for orphaned or redefined actions */ gboolean stage4(pe_working_set_t *data_set) { - check_actions(data_set); - return TRUE; + check_actions(data_set); + return TRUE; } gboolean stage5(pe_working_set_t *data_set) { - slist_iter( - node, node_t, data_set->nodes, lpc, - dump_node_capacity(show_utilization?0:utilization_log_level, "Original", node); - ); + GListPtr gIter = NULL; - crm_trace("Allocating services"); - /* Take (next) highest resource, assign it and create its actions */ - slist_iter( - rsc, resource_t, data_set->resources, lpc, - rsc->cmds->allocate(rsc, data_set); - ); + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + dump_node_capacity(show_utilization?0:utilization_log_level, "Original", node); + } - slist_iter( - node, node_t, data_set->nodes, lpc, - dump_node_capacity(show_utilization?0:utilization_log_level, "Remaining", node); - ); + crm_trace("Allocating services"); + /* Take (next) highest resource, assign it and create its actions */ + + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + rsc->cmds->allocate(rsc, data_set); + } + + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + dump_node_capacity(show_utilization?0:utilization_log_level, "Remaining", node); + } - if(is_set(data_set->flags, pe_flag_startup_probes)) { - crm_trace("Calculating needed probes"); - /* This code probably needs optimization - * ptest -x with 100 nodes, 100 clones and clone-max=100: + if(is_set(data_set->flags, pe_flag_startup_probes)) { + crm_trace("Calculating needed probes"); + /* This code probably needs optimization + * ptest -x with 100 nodes, 100 clones and clone-max=100: -With probes: - -ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status -ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints -ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints -ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:292 Check actions -ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: do_calculations: pengine.c:299 Allocate resources -ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: stage5: allocate.c:881 Allocating services -ptest[14781]: 2010/09/27_17:56:49 notice: TRACE: stage5: allocate.c:894 Calculating needed probes -ptest[14781]: 2010/09/27_17:56:51 notice: TRACE: stage5: allocate.c:899 Creating actions -ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: stage5: allocate.c:905 Creating done -ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases -ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints -36s -ptest[14781]: 2010/09/27_17:57:28 notice: TRACE: do_calculations: pengine.c:320 Create transition graph - -Without probes: - -ptest[14637]: 2010/09/27_17:56:21 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status -ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints -ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints -ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:292 Check actions -ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: do_calculations: pengine.c:299 Allocate resources -ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: stage5: allocate.c:881 Allocating services -ptest[14637]: 2010/09/27_17:56:24 notice: TRACE: stage5: allocate.c:899 Creating actions -ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: stage5: allocate.c:905 Creating done -ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases -ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints -ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:320 Create transition graph - */ + With probes: + + ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status + ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints + ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints + ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:292 Check actions + ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: do_calculations: pengine.c:299 Allocate resources + ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: stage5: allocate.c:881 Allocating services + ptest[14781]: 2010/09/27_17:56:49 notice: TRACE: stage5: allocate.c:894 Calculating needed probes + ptest[14781]: 2010/09/27_17:56:51 notice: TRACE: stage5: allocate.c:899 Creating actions + ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: stage5: allocate.c:905 Creating done + ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases + ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints + 36s + ptest[14781]: 2010/09/27_17:57:28 notice: TRACE: do_calculations: pengine.c:320 Create transition graph + + Without probes: + + ptest[14637]: 2010/09/27_17:56:21 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status + ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints + ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints + ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:292 Check actions + ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: do_calculations: pengine.c:299 Allocate resources + ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: stage5: allocate.c:881 Allocating services + ptest[14637]: 2010/09/27_17:56:24 notice: TRACE: stage5: allocate.c:899 Creating actions + ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: stage5: allocate.c:905 Creating done + ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases + ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints + ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:320 Create transition graph + */ - probe_resources(data_set); - } + probe_resources(data_set); + } - crm_trace("Creating actions"); - slist_iter( - rsc, resource_t, data_set->resources, lpc, - rsc->cmds->create_actions(rsc, data_set); - ); + crm_trace("Creating actions"); - crm_trace("Creating done"); - return TRUE; + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + rsc->cmds->create_actions(rsc, data_set); + } + + crm_trace("Creating done"); + return TRUE; } static gboolean is_managed(const resource_t *rsc) { + GListPtr gIter = rsc->children; if(is_set(rsc->flags, pe_rsc_managed)) { return TRUE; } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; if(is_managed(child_rsc)) { return TRUE; } - ); + } return FALSE; } static gboolean any_managed_resouces(pe_working_set_t *data_set) { - slist_iter( - rsc, resource_t, data_set->resources, lpc, + + GListPtr gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; if(is_managed(rsc)) { return TRUE; } - ); + } return FALSE; } /* * Create dependancies for stonith and shutdown operations */ gboolean stage6(pe_working_set_t *data_set) { - action_t *dc_down = NULL; - action_t *dc_fence = NULL; - action_t *stonith_op = NULL; - action_t *last_stonith = NULL; - gboolean integrity_lost = FALSE; - action_t *ready = get_pseudo_op(STONITH_UP, data_set); - action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); - action_t *done = get_pseudo_op(STONITH_DONE, data_set); - gboolean need_stonith = FALSE; + action_t *dc_down = NULL; + action_t *dc_fence = NULL; + action_t *stonith_op = NULL; + action_t *last_stonith = NULL; + gboolean integrity_lost = FALSE; + action_t *ready = get_pseudo_op(STONITH_UP, data_set); + action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); + action_t *done = get_pseudo_op(STONITH_DONE, data_set); + gboolean need_stonith = FALSE; + GListPtr gIter = data_set->nodes; - crm_debug_3("Processing fencing and shutdown cases"); + crm_debug_3("Processing fencing and shutdown cases"); - if(is_set(data_set->flags, pe_flag_stonith_enabled) - && (is_set(data_set->flags, pe_flag_have_quorum) - || data_set->no_quorum_policy == no_quorum_ignore - || data_set->no_quorum_policy == no_quorum_suicide)) { - need_stonith = TRUE; - } + if(is_set(data_set->flags, pe_flag_stonith_enabled) + && (is_set(data_set->flags, pe_flag_have_quorum) + || data_set->no_quorum_policy == no_quorum_ignore + || data_set->no_quorum_policy == no_quorum_suicide)) { + need_stonith = TRUE; + } - if(need_stonith && any_managed_resouces(data_set) == FALSE) { - crm_notice("Delaying fencing operations until there are resources to manage"); - need_stonith = FALSE; - } + if(need_stonith && any_managed_resouces(data_set) == FALSE) { + crm_notice("Delaying fencing operations until there are resources to manage"); + need_stonith = FALSE; + } + + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; - slist_iter( - node, node_t, data_set->nodes, lpc, + stonith_op = NULL; + if(node->details->unclean && need_stonith) { + pe_warn("Scheduling Node %s for STONITH", + node->details->uname); + + stonith_op = custom_action( + NULL, crm_strdup(CRM_OP_FENCE), + CRM_OP_FENCE, node, FALSE, TRUE, data_set); + + add_hash_param( + stonith_op->meta, XML_LRM_ATTR_TARGET, + node->details->uname); + + add_hash_param( + stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, + node->details->id); + + add_hash_param( + stonith_op->meta, "stonith_action", + data_set->stonith_action); + + stonith_constraints(node, stonith_op, data_set); + order_actions(ready, stonith_op, pe_order_runnable_left); + order_actions(stonith_op, all_stopped, pe_order_implies_then); - stonith_op = NULL; - if(node->details->unclean && need_stonith) { - pe_warn("Scheduling Node %s for STONITH", - node->details->uname); + clear_bit_inplace(ready->flags, pe_action_optional); + + if(node->details->is_dc) { + dc_down = stonith_op; + dc_fence = stonith_op; - stonith_op = custom_action( - NULL, crm_strdup(CRM_OP_FENCE), - CRM_OP_FENCE, node, FALSE, TRUE, data_set); + } else { + if(last_stonith) { + order_actions(last_stonith, stonith_op, pe_order_optional); + } + last_stonith = stonith_op; + } - add_hash_param( - stonith_op->meta, XML_LRM_ATTR_TARGET, - node->details->uname); + } else if(node->details->online && node->details->shutdown) { + action_t *down_op = NULL; + crm_notice("Scheduling Node %s for shutdown", + node->details->uname); - add_hash_param( - stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, - node->details->id); + down_op = custom_action( + NULL, crm_strdup(CRM_OP_SHUTDOWN), + CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); - add_hash_param( - stonith_op->meta, "stonith_action", - data_set->stonith_action); - - stonith_constraints(node, stonith_op, data_set); - order_actions(ready, stonith_op, pe_order_runnable_left); - order_actions(stonith_op, all_stopped, pe_order_implies_then); + shutdown_constraints(node, down_op, data_set); + add_hash_param(down_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - clear_bit_inplace(ready->flags, pe_action_optional); - - if(node->details->is_dc) { - dc_down = stonith_op; - dc_fence = stonith_op; - - } else { - if(last_stonith) { - order_actions(last_stonith, stonith_op, pe_order_optional); - } - last_stonith = stonith_op; - } - - } else if(node->details->online && node->details->shutdown) { - action_t *down_op = NULL; - crm_notice("Scheduling Node %s for shutdown", - node->details->uname); - - down_op = custom_action( - NULL, crm_strdup(CRM_OP_SHUTDOWN), - CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); - - shutdown_constraints(node, down_op, data_set); - add_hash_param(down_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - - if(node->details->is_dc) { - dc_down = down_op; - } - } + if(node->details->is_dc) { + dc_down = down_op; + } + } - if(node->details->unclean && stonith_op == NULL) { - integrity_lost = TRUE; - pe_warn("Node %s is unclean!", node->details->uname); - } - ); + if(node->details->unclean && stonith_op == NULL) { + integrity_lost = TRUE; + pe_warn("Node %s is unclean!", node->details->uname); + } + } - if(integrity_lost) { - if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) { - pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); - pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); + if(integrity_lost) { + if(is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) { + pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); + pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); - } else if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE) { - crm_notice("Cannot fence unclean nodes until quorum is" - " attained (or no-quorum-policy is set to ignore)"); - } + } else if(is_set(data_set->flags, pe_flag_have_quorum) == FALSE) { + crm_notice("Cannot fence unclean nodes until quorum is" + " attained (or no-quorum-policy is set to ignore)"); } + } - if(dc_down != NULL) { - GListPtr shutdown_matches = find_actions( - data_set->actions, CRM_OP_SHUTDOWN, NULL); - crm_debug_2("Ordering shutdowns before %s on %s (DC)", - dc_down->task, dc_down->node->details->uname); + if(dc_down != NULL) { + GListPtr shutdown_matches = find_actions( + data_set->actions, CRM_OP_SHUTDOWN, NULL); + crm_debug_2("Ordering shutdowns before %s on %s (DC)", + dc_down->task, dc_down->node->details->uname); - add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); + add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - slist_iter( - node_stop, action_t, shutdown_matches, lpc, - if(node_stop->node->details->is_dc) { - continue; - } - crm_debug("Ordering shutdown on %s before %s on %s", - node_stop->node->details->uname, - dc_down->task, dc_down->node->details->uname); - - order_actions(node_stop, dc_down, pe_order_optional); - ); - - if(last_stonith && dc_down != last_stonith) { - order_actions(last_stonith, dc_down, pe_order_optional); - } - g_list_free(shutdown_matches); - } + gIter = shutdown_matches; + for(; gIter != NULL; gIter = gIter->next) { + action_t *node_stop = (action_t*)gIter->data; - if(last_stonith) { - order_actions(last_stonith, done, pe_order_implies_then); + if(node_stop->node->details->is_dc) { + continue; + } + crm_debug("Ordering shutdown on %s before %s on %s", + node_stop->node->details->uname, + dc_down->task, dc_down->node->details->uname); - } else if(dc_fence) { - order_actions(dc_down, done, pe_order_implies_then); + order_actions(node_stop, dc_down, pe_order_optional); } - order_actions(ready, done, pe_order_optional); - return TRUE; + + if(last_stonith && dc_down != last_stonith) { + order_actions(last_stonith, dc_down, pe_order_optional); + } + g_list_free(shutdown_matches); + } + + if(last_stonith) { + order_actions(last_stonith, done, pe_order_implies_then); + + } else if(dc_fence) { + order_actions(dc_down, done, pe_order_implies_then); + } + order_actions(ready, done, pe_order_optional); + return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependencies of un-runnable actions un-runnable * */ static GListPtr find_actions_by_task(GListPtr actions, resource_t *rsc, const char *original_key) { GListPtr list = NULL; list = find_actions(actions, original_key, NULL); if(list == NULL) { /* we're potentially searching a child of the original resource */ char *key = NULL; char *tmp = NULL; char *task = NULL; int interval = 0; if(parse_op_key(original_key, &tmp, &task, &interval)) { key = generate_op_key(rsc->id, task, interval); /* crm_err("looking up %s instead of %s", key, original_key); */ /* slist_iter(action, action_t, actions, lpc, */ /* crm_err(" - %s", action->uuid)); */ list = find_actions(actions, key, NULL); } else { crm_err("search key: %s", original_key); } crm_free(key); crm_free(tmp); crm_free(task); } return list; } static void rsc_order_then( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { + GListPtr gIter = NULL; GListPtr rh_actions = NULL; action_t *rh_action = NULL; enum pe_ordering type = order->type; CRM_CHECK(rsc != NULL, return); CRM_CHECK(order != NULL, return); rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_prepend(NULL, rh_action); } else if(rsc != NULL) { rh_actions = find_actions_by_task( rsc->actions, rsc, order->rh_action_task); } if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id,order->rh_action_task); if(lh_action) { crm_debug_4("LH-Side was: %s", lh_action->uuid); } return; } if(lh_action->rsc == rsc && is_set(lh_action->flags, pe_action_dangle)) { crm_trace("Detected dangling operation %s -> %s", lh_action->uuid, order->rh_action_task); clear_bit_inplace(type, pe_order_implies_then); } - slist_iter( - rh_action_iter, action_t, rh_actions, lpc, + gIter = rh_actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *rh_action_iter = (action_t*)gIter->data; if(lh_action) { order_actions(lh_action, rh_action_iter, type); } else if(type & pe_order_implies_then) { update_action_flags(rh_action_iter, pe_action_runnable|pe_action_clear); crm_warn("Unrunnable %s 0x%.6x", rh_action_iter->uuid, type); } else { crm_warn("neither %s 0x%.6x", rh_action_iter->uuid, type); } - - ); + } pe_free_shallow_adv(rh_actions, FALSE); } static void rsc_order_first(resource_t *lh_rsc, order_constraint_t *order, pe_working_set_t *data_set) { + GListPtr gIter = NULL; GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; resource_t *rh_rsc = order->rh_rsc; crm_debug_3("Processing LH of ordering constraint %d", order->id); CRM_ASSERT(lh_rsc != NULL); if(lh_action != NULL) { lh_actions = g_list_prepend(NULL, lh_action); } else if(lh_action == NULL) { lh_actions = find_actions_by_task( lh_rsc->actions, lh_rsc, order->lh_action_task); } if(lh_actions == NULL && lh_rsc != rh_rsc) { char *key = NULL; char *rsc_id = NULL; char *op_type = NULL; int interval = 0; parse_op_key(order->lh_action_task, &rsc_id, &op_type, &interval); key = generate_op_key(lh_rsc->id, op_type, interval); if(lh_rsc->fns->state(lh_rsc, TRUE) != RSC_ROLE_STOPPED || safe_str_neq(op_type, RSC_STOP)) { crm_debug_4("No LH-Side (%s/%s) found for constraint %d with %s - creating", lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task); lh_action = custom_action(lh_rsc, key, op_type, NULL, TRUE, TRUE, data_set); lh_actions = g_list_prepend(NULL, lh_action); } else { crm_free(key); crm_debug_4("No LH-Side (%s/%s) found for constraint %d with %s - ignoring", lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task); } crm_free(op_type); crm_free(rsc_id); } - slist_iter( - lh_action_iter, action_t, lh_actions, lpc, + gIter = lh_actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *lh_action_iter = (action_t*)gIter->data; + if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { rsc_order_then(lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions(lh_action_iter, order->rh_action, order->type); } - ); + } pe_free_shallow_adv(lh_actions, FALSE); } extern gboolean update_action(action_t *action); gboolean stage7(pe_working_set_t *data_set) { - crm_debug_4("Applying ordering constraints"); + GListPtr gIter = NULL; + crm_debug_4("Applying ordering constraints"); - /* Don't ask me why, but apparently they need to be processed in - * the order they were created in... go figure - * - * Also g_list_prepend() has horrendous performance characteristics - * So we need to use g_list_prepend() and then reverse the list here - */ - data_set->ordering_constraints = g_list_reverse( - data_set->ordering_constraints); + /* Don't ask me why, but apparently they need to be processed in + * the order they were created in... go figure + * + * Also g_list_prepend() has horrendous performance characteristics + * So we need to use g_list_prepend() and then reverse the list here + */ + data_set->ordering_constraints = g_list_reverse( + data_set->ordering_constraints); - slist_iter( - order, order_constraint_t, data_set->ordering_constraints, lpc, + gIter = data_set->ordering_constraints; + for(; gIter != NULL; gIter = gIter->next) { + order_constraint_t *order = (order_constraint_t*)gIter->data; + resource_t *rsc = order->lh_rsc; - resource_t *rsc = order->lh_rsc; - crm_debug_3("Applying ordering constraint: %d", order->id); + crm_debug_3("Applying ordering constraint: %d", order->id); - if(rsc != NULL) { - crm_debug_4("rsc_action-to-*"); - rsc_order_first(rsc, order, data_set); - continue; - } + if(rsc != NULL) { + crm_debug_4("rsc_action-to-*"); + rsc_order_first(rsc, order, data_set); + continue; + } - rsc = order->rh_rsc; - if(rsc != NULL) { - crm_debug_4("action-to-rsc_action"); - rsc_order_then(order->lh_action, rsc, order); + rsc = order->rh_rsc; + if(rsc != NULL) { + crm_debug_4("action-to-rsc_action"); + rsc_order_then(order->lh_action, rsc, order); - } else { - crm_debug_4("action-to-action"); - order_actions( - order->lh_action, order->rh_action, order->type); - } - ); + } else { + crm_debug_4("action-to-action"); + order_actions( + order->lh_action, order->rh_action, order->type); + } + } - crm_debug_2("Updating %d actions", g_list_length(data_set->actions)); - slist_iter( - action, action_t, data_set->actions, lpc, + crm_debug_2("Updating %d actions", g_list_length(data_set->actions)); - update_action(action); - ); + gIter = data_set->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + update_action(action); + } - crm_debug_2("Processing migrations"); - slist_iter( - rsc, resource_t, data_set->resources, lpc, + crm_debug_2("Processing migrations"); - rsc_migrate_reload(rsc, data_set); - LogActions(rsc, data_set); - ); + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; - return TRUE; + rsc_migrate_reload(rsc, data_set); + LogActions(rsc, data_set); + } + + return TRUE; } static gint sort_notify_entries(gconstpointer a, gconstpointer b) { - int tmp; - const notify_entry_t *entry_a = a; - const notify_entry_t *entry_b = b; + int tmp; + const notify_entry_t *entry_a = a; + const notify_entry_t *entry_b = b; - if(entry_a == NULL && entry_b == NULL) { return 0; } - if(entry_a == NULL) { return 1; } - if(entry_b == NULL) { return -1; } + if(entry_a == NULL && entry_b == NULL) { return 0; } + if(entry_a == NULL) { return 1; } + if(entry_b == NULL) { return -1; } - if(entry_a->rsc == NULL && entry_b->rsc == NULL) { return 0; } - if(entry_a->rsc == NULL) { return 1; } - if(entry_b->rsc == NULL) { return -1; } + if(entry_a->rsc == NULL && entry_b->rsc == NULL) { return 0; } + if(entry_a->rsc == NULL) { return 1; } + if(entry_b->rsc == NULL) { return -1; } - tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id); - if(tmp != 0) { - return tmp; - } + tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id); + if(tmp != 0) { + return tmp; + } - if(entry_a->node == NULL && entry_b->node == NULL) { return 0; } - if(entry_a->node == NULL) { return 1; } - if(entry_b->node == NULL) { return -1; } + if(entry_a->node == NULL && entry_b->node == NULL) { return 0; } + if(entry_a->node == NULL) { return 1; } + if(entry_b->node == NULL) { return -1; } - return strcmp(entry_a->node->details->id, entry_b->node->details->id); + return strcmp(entry_a->node->details->id, entry_b->node->details->id); } static void expand_list(GListPtr list, char **rsc_list, char **node_list) { - const char *uname = NULL; - const char *rsc_id = NULL; - const char *last_rsc_id = NULL; - - if(list == NULL) { - *rsc_list = crm_strdup(" "); - if(node_list) { - *node_list = crm_strdup(" "); - } - return; - } - - *rsc_list = NULL; + GListPtr gIter = list; + const char *uname = NULL; + const char *rsc_id = NULL; + const char *last_rsc_id = NULL; + + if(list == NULL) { + *rsc_list = crm_strdup(" "); if(node_list) { - *node_list = NULL; + *node_list = crm_strdup(" "); } + return; + } + + *rsc_list = NULL; + if(node_list) { + *node_list = NULL; + } - slist_iter(entry, notify_entry_t, list, lpc, - - CRM_CHECK(entry != NULL, continue); - CRM_CHECK(entry->rsc != NULL, continue); - CRM_CHECK(node_list == NULL || entry->node != NULL, continue); - - uname = NULL; - rsc_id = entry->rsc->id; - CRM_ASSERT(rsc_id != NULL); - - /* filter dups */ - if(safe_str_eq(rsc_id, last_rsc_id)) { - continue; - } - last_rsc_id = rsc_id; - - if(rsc_list != NULL) { - int existing_len = 0; - int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */ - if(rsc_list && *rsc_list) { - existing_len = strlen(*rsc_list); - } - - crm_debug_5("Adding %s (%dc) at offset %d", - rsc_id, len-2, existing_len); - crm_realloc(*rsc_list, len + existing_len); - sprintf(*rsc_list + existing_len, "%s ", rsc_id); - } - - if(entry->node != NULL) { - uname = entry->node->details->uname; - } + for(; gIter != NULL; gIter = gIter->next) { + notify_entry_t *entry = (notify_entry_t*)gIter->data; + + CRM_CHECK(entry != NULL, continue); + CRM_CHECK(entry->rsc != NULL, continue); + CRM_CHECK(node_list == NULL || entry->node != NULL, continue); + + uname = NULL; + rsc_id = entry->rsc->id; + CRM_ASSERT(rsc_id != NULL); + + /* filter dups */ + if(safe_str_eq(rsc_id, last_rsc_id)) { + continue; + } + last_rsc_id = rsc_id; + + if(rsc_list != NULL) { + int existing_len = 0; + int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */ + if(rsc_list && *rsc_list) { + existing_len = strlen(*rsc_list); + } + + crm_debug_5("Adding %s (%dc) at offset %d", + rsc_id, len-2, existing_len); + crm_realloc(*rsc_list, len + existing_len); + sprintf(*rsc_list + existing_len, "%s ", rsc_id); + } + + if(entry->node != NULL) { + uname = entry->node->details->uname; + } - if(node_list != NULL && uname) { - int existing_len = 0; - int len = 2 + strlen(uname); - if(node_list && *node_list) { - existing_len = strlen(*node_list); - } + if(node_list != NULL && uname) { + int existing_len = 0; + int len = 2 + strlen(uname); + if(node_list && *node_list) { + existing_len = strlen(*node_list); + } - crm_debug_5("Adding %s (%dc) at offset %d", - uname, len-2, existing_len); - crm_realloc(*node_list, len + existing_len); - sprintf(*node_list + existing_len, "%s ", uname); - } - ); + crm_debug_5("Adding %s (%dc) at offset %d", + uname, len-2, existing_len); + crm_realloc(*node_list, len + existing_len); + sprintf(*node_list + existing_len, "%s ", uname); + } + } + } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { add_hash_param(user_data, key, value); } static action_t * 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; - const char *value = NULL; - const char *task = NULL; + char *key = NULL; + action_t *trigger = NULL; + const char *value = NULL; + const char *task = NULL; - if(op == NULL || confirm == NULL) { - crm_debug_2("Op=%p confirm=%p", op, confirm); - return NULL; - } + if(op == NULL || confirm == NULL) { + crm_debug_2("Op=%p confirm=%p", op, confirm); + return NULL; + } - CRM_CHECK(node != NULL, return NULL); + CRM_CHECK(node != NULL, return NULL); - if(node->details->online == FALSE) { - crm_debug_2("Skipping notification for %s: node offline", rsc->id); - return NULL; - } else if(is_set(op->flags, pe_action_runnable) == FALSE) { - crm_debug_2("Skipping notification for %s: not runnable", op->uuid); - return NULL; - } + if(node->details->online == FALSE) { + crm_debug_2("Skipping notification for %s: node offline", rsc->id); + return NULL; + } else if(is_set(op->flags, pe_action_runnable) == FALSE) { + crm_debug_2("Skipping notification for %s: not runnable", op->uuid); + return NULL; + } - value = g_hash_table_lookup(op->meta, "notify_type"); - task = g_hash_table_lookup(op->meta, "notify_operation"); + value = g_hash_table_lookup(op->meta, "notify_type"); + task = g_hash_table_lookup(op->meta, "notify_operation"); - crm_debug_2("Creating notify actions for %s: %s (%s-%s)", - op->uuid, rsc->id, value, task); + crm_debug_2("Creating notify actions for %s: %s (%s-%s)", + op->uuid, rsc->id, value, task); - key = generate_notify_key(rsc->id, value, task); - trigger = custom_action(rsc, key, op->task, node, - is_set(op->flags, pe_action_optional), TRUE, data_set); - g_hash_table_foreach(op->meta, dup_attr, trigger->meta); - g_hash_table_foreach(n_data->keys, dup_attr, trigger->meta); + key = generate_notify_key(rsc->id, value, task); + trigger = custom_action(rsc, key, op->task, node, + is_set(op->flags, pe_action_optional), TRUE, data_set); + g_hash_table_foreach(op->meta, dup_attr, trigger->meta); + g_hash_table_foreach(n_data->keys, dup_attr, trigger->meta); - /* pseudo_notify before notify */ - crm_debug_3("Ordering %s before %s (%d->%d)", + /* pseudo_notify before notify */ + crm_debug_3("Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id, op->id); - order_actions(op, trigger, pe_order_optional); - order_actions(trigger, confirm, pe_order_optional); - return trigger; + order_actions(op, trigger, pe_order_optional); + order_actions(trigger, confirm, pe_order_optional); + return trigger; } static void pe_post_notify(resource_t *rsc, node_t *node, notify_data_t *n_data, pe_working_set_t *data_set) { - action_t *notify = NULL; + action_t *notify = NULL; - CRM_CHECK(rsc != NULL, return); + CRM_CHECK(rsc != NULL, return); - if(n_data->post == NULL) { - return; /* Nothing to do */ - } + if(n_data->post == NULL) { + return; /* Nothing to do */ + } - notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set); + notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set); - if(notify != NULL) { - notify->priority = INFINITY; - } + if(notify != NULL) { + notify->priority = INFINITY; + } - if(n_data->post_done) { - slist_iter( - mon, action_t, rsc->actions, lpc, - - const char *interval = g_hash_table_lookup(mon->meta, "interval"); - if(interval == NULL || safe_str_eq(interval, "0")) { - crm_debug_3("Skipping %s: interval", mon->uuid); - continue; - } else if(safe_str_eq(mon->task, "cancel")) { - crm_debug_3("Skipping %s: cancel", mon->uuid); - continue; - } - - order_actions(n_data->post_done, mon, pe_order_optional); - ); + if(n_data->post_done) { + GListPtr gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *mon = (action_t*)gIter->data; + const char *interval = g_hash_table_lookup(mon->meta, "interval"); + + if(interval == NULL || safe_str_eq(interval, "0")) { + crm_debug_3("Skipping %s: interval", mon->uuid); + continue; + } else if(safe_str_eq(mon->task, "cancel")) { + crm_debug_3("Skipping %s: cancel", mon->uuid); + continue; + } + + order_actions(n_data->post_done, mon, pe_order_optional); } + } } notify_data_t * create_notification_boundaries( resource_t *rsc, const char *action, action_t *start, action_t *end, pe_working_set_t *data_set) { /* Create the pseudo ops that preceed and follow the actual notifications */ /* * Creates two sequences (conditional on start and end being supplied): * pre_notify -> pre_notify_complete -> start, and * end -> post_notify -> post_notify_complete * * 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones */ char *key = NULL; notify_data_t *n_data = NULL; if(is_not_set(rsc->flags, pe_rsc_notify)) { return NULL; } crm_malloc0(n_data, sizeof(notify_data_t)); n_data->action = action; n_data->keys = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(start) { /* create pre-event notification wrappers */ key = generate_notify_key(rsc->id, "pre", start->task); n_data->pre = custom_action( rsc, key, RSC_NOTIFY, NULL, is_set(start->flags, pe_action_optional), TRUE, data_set); update_action_flags(n_data->pre, pe_action_pseudo); update_action_flags(n_data->pre, pe_action_runnable); add_hash_param(n_data->pre->meta, "notify_type", "pre"); add_hash_param(n_data->pre->meta, "notify_operation", n_data->action); /* create pre_notify_complete */ key = generate_notify_key(rsc->id, "confirmed-pre", start->task); n_data->pre_done = custom_action( rsc, key, RSC_NOTIFIED, NULL, is_set(start->flags, pe_action_optional), TRUE, data_set); update_action_flags(n_data->pre_done, pe_action_pseudo); update_action_flags(n_data->pre_done, pe_action_runnable); add_hash_param(n_data->pre_done->meta, "notify_type", "pre"); add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action); order_actions(n_data->pre_done, start, pe_order_optional); order_actions(n_data->pre, n_data->pre_done, pe_order_optional); } if(end) { /* create post-event notification wrappers */ key = generate_notify_key(rsc->id, "post", end->task); n_data->post = custom_action( rsc, key, RSC_NOTIFY, NULL, is_set(end->flags, pe_action_optional), TRUE, data_set); n_data->post->priority = INFINITY; update_action_flags(n_data->post, pe_action_pseudo); if(is_set(end->flags, pe_action_runnable)) { update_action_flags(n_data->post, pe_action_runnable); } else { update_action_flags(n_data->post, pe_action_runnable|pe_action_clear); } add_hash_param(n_data->post->meta, "notify_type", "post"); add_hash_param(n_data->post->meta, "notify_operation", n_data->action); /* create post_notify_complete */ key = generate_notify_key(rsc->id, "confirmed-post", end->task); n_data->post_done = custom_action( rsc, key, RSC_NOTIFIED, NULL, is_set(end->flags, pe_action_optional), TRUE, data_set); n_data->post_done->priority = INFINITY; update_action_flags(n_data->post_done, pe_action_pseudo); if(is_set(end->flags, pe_action_runnable)) { update_action_flags(n_data->post_done, pe_action_runnable); } else { update_action_flags(n_data->post_done, pe_action_runnable|pe_action_clear); } add_hash_param(n_data->post_done->meta, "notify_type", "pre"); add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action); order_actions(end, n_data->post, pe_order_implies_then); order_actions(n_data->post, n_data->post_done, pe_order_implies_then); } if(start && end) { order_actions(n_data->pre_done, n_data->post, pe_order_optional); } if(safe_str_eq(action, RSC_STOP)) { action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); order_actions(n_data->post_done, all_stopped, pe_order_optional); } return n_data; } void collect_notification_data(resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data) { if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - collect_notification_data(child, state, activity, n_data); - ); + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + collect_notification_data(child, state, activity, n_data); + } return; } if(state) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; if(rsc->running_on) { /* we only take the first one */ entry->node = rsc->running_on->data; } crm_debug_2("%s state: %s", rsc->id, role2text(rsc->role)); switch(rsc->role) { case RSC_ROLE_STOPPED: n_data->inactive = g_list_prepend(n_data->inactive, entry); break; case RSC_ROLE_STARTED: n_data->active = g_list_prepend(n_data->active, entry); break; case RSC_ROLE_SLAVE: n_data->slave = g_list_prepend(n_data->slave, entry); break; case RSC_ROLE_MASTER: n_data->master = g_list_prepend(n_data->master, entry); break; default: crm_err("Unsupported notify role"); crm_free(entry); break; } } if(activity) { notify_entry_t *entry = NULL; enum action_tasks task; - slist_iter( - op, action_t, rsc->actions, lpc, - + GListPtr gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *op = (action_t*)gIter->data; + if(is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) { crm_malloc0(entry, sizeof(notify_entry_t)); entry->node = op->node; entry->rsc = rsc; task = text2task(op->task); switch(task) { case start_rsc: n_data->start = g_list_prepend(n_data->start, entry); break; case stop_rsc: n_data->stop = g_list_prepend(n_data->stop, entry); break; case action_promote: n_data->promote = g_list_prepend(n_data->promote, entry); break; case action_demote: n_data->demote = g_list_prepend(n_data->demote, entry); break; default: crm_free(entry); break; } } - ); + } } } gboolean expand_notification_data(notify_data_t *n_data) { /* Expand the notification entries into a key=value hashtable * This hashtable is later used in action2xml() */ gboolean required = FALSE; char *rsc_list = NULL; char *node_list = NULL; if(n_data->stop) { n_data->stop = g_list_sort(n_data->stop, sort_notify_entries); } expand_list(n_data->stop, &rsc_list, &node_list); if(rsc_list != NULL && safe_str_neq(" ", rsc_list)) { if(safe_str_eq(n_data->action, RSC_STOP)) { required = TRUE; } } g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_uname"), node_list); if(n_data->start) { n_data->start = g_list_sort(n_data->start, sort_notify_entries); if(rsc_list && safe_str_eq(n_data->action, RSC_START)) { required = TRUE; } } expand_list(n_data->start, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_start_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_start_uname"), node_list); if(n_data->demote) { n_data->demote = g_list_sort(n_data->demote, sort_notify_entries); if(safe_str_eq(n_data->action, RSC_DEMOTE)) { required = TRUE; } } expand_list(n_data->demote, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_demote_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_demote_uname"), node_list); if(n_data->promote) { n_data->promote = g_list_sort(n_data->promote, sort_notify_entries); if(safe_str_eq(n_data->action, RSC_PROMOTE)) { required = TRUE; } } expand_list(n_data->promote, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_promote_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_promote_uname"), node_list); if(n_data->active) { n_data->active = g_list_sort(n_data->active, sort_notify_entries); } expand_list(n_data->active, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_active_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_active_uname"), node_list); if(n_data->slave) { n_data->slave = g_list_sort(n_data->slave, sort_notify_entries); } expand_list(n_data->slave, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_slave_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_slave_uname"), node_list); if(n_data->master) { n_data->master = g_list_sort(n_data->master, sort_notify_entries); } expand_list(n_data->master, &rsc_list, &node_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_master_resource"), rsc_list); g_hash_table_insert(n_data->keys, crm_strdup("notify_master_uname"), node_list); if(n_data->inactive) { n_data->inactive = g_list_sort(n_data->inactive, sort_notify_entries); } expand_list(n_data->inactive, &rsc_list, NULL); g_hash_table_insert(n_data->keys, crm_strdup("notify_inactive_resource"), rsc_list); if(required && n_data->pre) { update_action_flags(n_data->pre, pe_action_optional|pe_action_clear); update_action_flags(n_data->pre_done, pe_action_optional|pe_action_clear); } if(required && n_data->post) { update_action_flags(n_data->post, pe_action_optional|pe_action_clear); update_action_flags(n_data->post_done, pe_action_optional|pe_action_clear); } return required; } void create_notifications(resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set) { + GListPtr gIter = NULL; action_t *stop = NULL; action_t *start = NULL; enum action_tasks task = text2task(n_data->action); if(rsc->children) { - slist_iter( - child, resource_t, rsc->children, lpc, + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; create_notifications(child, n_data, data_set); - ); + } return; } /* Copy notification details into standard ops */ - slist_iter( - op, action_t, rsc->actions, lpc, + + gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *op = (action_t*)gIter->data; if(is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) { enum action_tasks t = text2task(op->task); switch(t) { case start_rsc: case stop_rsc: case action_promote: case action_demote: g_hash_table_foreach(n_data->keys, dup_attr, op->meta); break; default: break; } } - ); + } crm_debug_2("Creating notificaitons for: %s.%s (%s->%s)", n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role)); stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL); start = find_first_action(rsc->actions, NULL, RSC_START, NULL); /* 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_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set); - if(task == action_demote || stop == NULL || is_set(stop->flags, pe_action_optional)) { - pe_post_notify(rsc, current_node, n_data, data_set); - } - ); + gIter = rsc->running_on; + for(; gIter != NULL; gIter = gIter->next) { + node_t *current_node = (node_t*)gIter->data; + + pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set); + if(task == action_demote || stop == NULL || is_set(stop->flags, pe_action_optional)) { + pe_post_notify(rsc, current_node, n_data, data_set); + } + } } } /* start / promote */ if(rsc->next_role != RSC_ROLE_STOPPED) { if(rsc->allocated_to == NULL) { pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role), rsc->id); } else if(task == start_rsc || task == action_promote) { if(task != start_rsc || start == NULL || is_set(start->flags, pe_action_optional)) { pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set); } pe_post_notify(rsc, rsc->allocated_to, n_data, data_set); } } } void free_notification_data(notify_data_t *n_data) { if(n_data == NULL) { return; } pe_free_shallow(n_data->stop); pe_free_shallow(n_data->start); pe_free_shallow(n_data->demote); pe_free_shallow(n_data->promote); pe_free_shallow(n_data->master); pe_free_shallow(n_data->slave); pe_free_shallow(n_data->active); pe_free_shallow(n_data->inactive); g_hash_table_destroy(n_data->keys); crm_free(n_data); } int transition_id = -1; /* * Create a dependency graph to send to the transitioner (via the CRMd) */ gboolean stage8(pe_working_set_t *data_set) { - const char *value = NULL; + GListPtr gIter = NULL; + const char *value = NULL; - transition_id++; - crm_debug_2("Creating transition graph %d.", transition_id); + transition_id++; + crm_debug_2("Creating transition graph %d.", transition_id); - data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); + data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); - value = pe_pref(data_set->config_hash, "cluster-delay"); - crm_xml_add(data_set->graph, "cluster-delay", value); + value = pe_pref(data_set->config_hash, "cluster-delay"); + crm_xml_add(data_set->graph, "cluster-delay", value); - value = pe_pref(data_set->config_hash, "stonith-timeout"); - crm_xml_add(data_set->graph, "stonith-timeout", value); + value = pe_pref(data_set->config_hash, "stonith-timeout"); + crm_xml_add(data_set->graph, "stonith-timeout", value); - crm_xml_add(data_set->graph, "failed-stop-offset", "INFINITY"); + crm_xml_add(data_set->graph, "failed-stop-offset", "INFINITY"); - if(is_set(data_set->flags, pe_flag_start_failure_fatal)) { - crm_xml_add(data_set->graph, "failed-start-offset", "INFINITY"); - } else { - crm_xml_add(data_set->graph, "failed-start-offset", "1"); - } + if(is_set(data_set->flags, pe_flag_start_failure_fatal)) { + crm_xml_add(data_set->graph, "failed-start-offset", "INFINITY"); + } else { + crm_xml_add(data_set->graph, "failed-start-offset", "1"); + } - value = pe_pref(data_set->config_hash, "batch-limit"); - crm_xml_add(data_set->graph, "batch-limit", value); + value = pe_pref(data_set->config_hash, "batch-limit"); + crm_xml_add(data_set->graph, "batch-limit", value); - crm_xml_add_int(data_set->graph, "transition_id", transition_id); + crm_xml_add_int(data_set->graph, "transition_id", transition_id); /* errors... - slist_iter(action, action_t, action_list, lpc, - if(action->optional == FALSE && action->runnable == FALSE) { - print_action("Ignoring", action, TRUE); - } - ); + slist_iter(action, action_t, action_list, lpc, + if(action->optional == FALSE && action->runnable == FALSE) { + print_action("Ignoring", action, TRUE); + } + ); */ - slist_iter( - rsc, resource_t, data_set->resources, lpc, - - crm_debug_4("processing actions for rsc=%s", rsc->id); - rsc->cmds->expand(rsc, data_set); - ); - crm_log_xml_debug_3( - data_set->graph, "created resource-driven action list"); + + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + crm_debug_4("processing actions for rsc=%s", rsc->id); + rsc->cmds->expand(rsc, data_set); + } + + crm_log_xml_debug_3( + data_set->graph, "created resource-driven action list"); - /* catch any non-resource specific actions */ - crm_debug_4("processing non-resource actions"); - slist_iter( - action, action_t, data_set->actions, lpc, + /* catch any non-resource specific actions */ + crm_debug_4("processing non-resource actions"); - graph_element_from_action(action, data_set); - ); + gIter = data_set->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + graph_element_from_action(action, data_set); + } - crm_log_xml_debug_3(data_set->graph, "created generic action list"); - crm_debug_2("Created transition graph %d.", transition_id); + crm_log_xml_debug_3(data_set->graph, "created generic action list"); + crm_debug_2("Created transition graph %d.", transition_id); - return TRUE; + return TRUE; } void cleanup_alloc_calculations(pe_working_set_t *data_set) { - if(data_set == NULL) { - return; - } + if(data_set == NULL) { + return; + } - crm_debug_3("deleting %d order cons: %p", - g_list_length(data_set->ordering_constraints), data_set->ordering_constraints); - pe_free_ordering(data_set->ordering_constraints); - data_set->ordering_constraints = NULL; + crm_debug_3("deleting %d order cons: %p", + g_list_length(data_set->ordering_constraints), data_set->ordering_constraints); + pe_free_ordering(data_set->ordering_constraints); + data_set->ordering_constraints = NULL; - crm_debug_3("deleting %d node cons: %p", - g_list_length(data_set->placement_constraints), data_set->placement_constraints); - pe_free_rsc_to_node(data_set->placement_constraints); - data_set->placement_constraints = NULL; - - crm_debug_3("deleting %d inter-resource cons: %p", - g_list_length(data_set->colocation_constraints), data_set->colocation_constraints); - pe_free_shallow(data_set->colocation_constraints); - data_set->colocation_constraints = NULL; + crm_debug_3("deleting %d node cons: %p", + g_list_length(data_set->placement_constraints), data_set->placement_constraints); + pe_free_rsc_to_node(data_set->placement_constraints); + data_set->placement_constraints = NULL; + + crm_debug_3("deleting %d inter-resource cons: %p", + g_list_length(data_set->colocation_constraints), data_set->colocation_constraints); + pe_free_shallow(data_set->colocation_constraints); + data_set->colocation_constraints = NULL; - cleanup_calculations(data_set); + cleanup_calculations(data_set); } diff --git a/pengine/clone.c b/pengine/clone.c index 9dc00c42d1..a91ec2ed29 100644 --- a/pengine/clone.c +++ b/pengine/clone.c @@ -1,1376 +1,1460 @@ /* * 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 #define VARIANT_CLONE 1 #include gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set); static node_t * parent_node_instance(const resource_t *rsc, node_t *node) { - node_t *ret = NULL; - if(node != NULL) { - ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id); - } - return ret; + node_t *ret = NULL; + if(node != NULL) { + ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id); + } + return ret; } static gboolean did_fail(const resource_t *rsc) { + GListPtr gIter = rsc->children; + if(is_set(rsc->flags, pe_rsc_failed)) { return TRUE; } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; if(did_fail(child_rsc)) { return TRUE; } - ); + } return FALSE; } gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set) { - int level = LOG_DEBUG_3; - node_t *node1 = NULL; - node_t *node2 = NULL; + int level = LOG_DEBUG_3; + node_t *node1 = NULL; + node_t *node2 = NULL; - gboolean can1 = TRUE; - gboolean can2 = TRUE; - gboolean with_scores = TRUE; + gboolean can1 = TRUE; + gboolean can2 = TRUE; + gboolean with_scores = TRUE; - const resource_t *resource1 = (const resource_t*)a; - const resource_t *resource2 = (const resource_t*)b; - - CRM_ASSERT(resource1 != NULL); - CRM_ASSERT(resource2 != NULL); - - /* allocation order: - * - active instances - * - instances running on nodes with the least copies - * - active instances on nodes that cant support them or are to be fenced - * - failed instances - * - inactive instances - */ - - do_crm_log_unlikely(level+1, "%s ? %s", resource1->id, resource2->id); - if(resource1->running_on && resource2->running_on) { - if(g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) { - do_crm_log_unlikely(level, "%s < %s: running_on", resource1->id, resource2->id); - return -1; + const resource_t *resource1 = (const resource_t*)a; + const resource_t *resource2 = (const resource_t*)b; + + CRM_ASSERT(resource1 != NULL); + CRM_ASSERT(resource2 != NULL); + + /* allocation order: + * - active instances + * - instances running on nodes with the least copies + * - active instances on nodes that cant support them or are to be fenced + * - failed instances + * - inactive instances + */ + + do_crm_log_unlikely(level+1, "%s ? %s", resource1->id, resource2->id); + if(resource1->running_on && resource2->running_on) { + if(g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) { + do_crm_log_unlikely(level, "%s < %s: running_on", resource1->id, resource2->id); + return -1; - } else if(g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) { - do_crm_log_unlikely(level, "%s > %s: running_on", resource1->id, resource2->id); - return 1; - } + } else if(g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) { + do_crm_log_unlikely(level, "%s > %s: running_on", resource1->id, resource2->id); + return 1; } + } - if(resource1->running_on) { - node1 = resource1->running_on->data; - } - if(resource2->running_on) { - node2 = resource2->running_on->data; - } + if(resource1->running_on) { + node1 = resource1->running_on->data; + } + if(resource2->running_on) { + node2 = resource2->running_on->data; + } - if(node1) { - node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id); - if(match == NULL || match->weight < 0) { - do_crm_log_unlikely(level, "%s: current location is unavailable", resource1->id); - node1 = NULL; - can1 = FALSE; - } + if(node1) { + node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id); + if(match == NULL || match->weight < 0) { + do_crm_log_unlikely(level, "%s: current location is unavailable", resource1->id); + node1 = NULL; + can1 = FALSE; } + } - if(node2) { - node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id); - if(match == NULL || match->weight < 0) { - do_crm_log_unlikely(level, "%s: current location is unavailable", resource2->id); - node2 = NULL; - can2 = FALSE; - } + if(node2) { + node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id); + if(match == NULL || match->weight < 0) { + do_crm_log_unlikely(level, "%s: current location is unavailable", resource2->id); + node2 = NULL; + can2 = FALSE; } + } - if(can1 != can2) { - if(can1) { - do_crm_log_unlikely(level, "%s < %s: availability of current location", resource1->id, resource2->id); - return -1; - } - do_crm_log_unlikely(level, "%s > %s: availability of current location", resource1->id, resource2->id); - return 1; + if(can1 != can2) { + if(can1) { + do_crm_log_unlikely(level, "%s < %s: availability of current location", resource1->id, resource2->id); + return -1; } + do_crm_log_unlikely(level, "%s > %s: availability of current location", resource1->id, resource2->id); + return 1; + } - if(resource1->priority < resource2->priority) { - do_crm_log_unlikely(level, "%s < %s: priority", resource1->id, resource2->id); - return 1; + if(resource1->priority < resource2->priority) { + do_crm_log_unlikely(level, "%s < %s: priority", resource1->id, resource2->id); + return 1; - } else if(resource1->priority > resource2->priority) { - do_crm_log_unlikely(level, "%s > %s: priority", resource1->id, resource2->id); - return -1; - } + } else if(resource1->priority > resource2->priority) { + do_crm_log_unlikely(level, "%s > %s: priority", resource1->id, resource2->id); + return -1; + } - if(node1 == NULL && node2 == NULL) { - do_crm_log_unlikely(level, "%s == %s: not active", - resource1->id, resource2->id); - return 0; - } + if(node1 == NULL && node2 == NULL) { + do_crm_log_unlikely(level, "%s == %s: not active", + resource1->id, resource2->id); + return 0; + } - if(node1 != node2) { - if(node1 == NULL) { - do_crm_log_unlikely(level, "%s > %s: active", resource1->id, resource2->id); - return 1; - } else if(node2 == NULL) { - do_crm_log_unlikely(level, "%s < %s: active", resource1->id, resource2->id); - return -1; - } + if(node1 != node2) { + if(node1 == NULL) { + do_crm_log_unlikely(level, "%s > %s: active", resource1->id, resource2->id); + return 1; + } else if(node2 == NULL) { + do_crm_log_unlikely(level, "%s < %s: active", resource1->id, resource2->id); + return -1; } + } - can1 = can_run_resources(node1); - can2 = can_run_resources(node2); - if(can1 != can2) { - if(can1) { - do_crm_log_unlikely(level, "%s < %s: can", resource1->id, resource2->id); - return -1; - } - do_crm_log_unlikely(level, "%s > %s: can", resource1->id, resource2->id); - return 1; + can1 = can_run_resources(node1); + can2 = can_run_resources(node2); + if(can1 != can2) { + if(can1) { + do_crm_log_unlikely(level, "%s < %s: can", resource1->id, resource2->id); + return -1; } + do_crm_log_unlikely(level, "%s > %s: can", resource1->id, resource2->id); + return 1; + } - node1 = parent_node_instance(resource1, node1); - node2 = parent_node_instance(resource2, node2); - if(node1 != NULL && node2 == NULL) { - do_crm_log_unlikely(level, "%s < %s: not allowed", resource1->id, resource2->id); - return -1; - } else if(node1 == NULL && node2 != NULL) { - do_crm_log_unlikely(level, "%s > %s: not allowed", resource1->id, resource2->id); - return 1; - } + node1 = parent_node_instance(resource1, node1); + node2 = parent_node_instance(resource2, node2); + if(node1 != NULL && node2 == NULL) { + do_crm_log_unlikely(level, "%s < %s: not allowed", resource1->id, resource2->id); + return -1; + } else if(node1 == NULL && node2 != NULL) { + do_crm_log_unlikely(level, "%s > %s: not allowed", resource1->id, resource2->id); + return 1; + } - if(node1 == NULL) { - do_crm_log_unlikely(level, "%s == %s: not allowed", resource1->id, resource2->id); - return 0; - } + if(node1 == NULL) { + do_crm_log_unlikely(level, "%s == %s: not allowed", resource1->id, resource2->id); + return 0; + } - if(node1->count < node2->count) { - do_crm_log_unlikely(level, "%s < %s: count", resource1->id, resource2->id); - return -1; + if(node1->count < node2->count) { + do_crm_log_unlikely(level, "%s < %s: count", resource1->id, resource2->id); + return -1; - } else if(node1->count > node2->count) { - do_crm_log_unlikely(level, "%s > %s: count", resource1->id, resource2->id); - return 1; - } + } else if(node1->count > node2->count) { + do_crm_log_unlikely(level, "%s > %s: count", resource1->id, resource2->id); + return 1; + } - if(with_scores) { - int rc = 0; - int max = 0; - int lpc = 0; - GListPtr list1 = g_hash_table_get_values(resource1->allowed_nodes); - GListPtr list2 = g_hash_table_get_values(resource2->allowed_nodes); + if(with_scores) { + int rc = 0; + int max = 0; + int lpc = 0; + GListPtr list1 = g_hash_table_get_values(resource1->allowed_nodes); + GListPtr list2 = g_hash_table_get_values(resource2->allowed_nodes); - list1 = g_list_sort_with_data(list1, sort_node_weight, g_list_nth_data(resource1->running_on, 0)); - list2 = g_list_sort_with_data(list2, sort_node_weight, g_list_nth_data(resource2->running_on, 0)); - max = g_list_length(list1); - if(max < g_list_length(list2)) { - max = g_list_length(list2); - } + list1 = g_list_sort_with_data(list1, sort_node_weight, g_list_nth_data(resource1->running_on, 0)); + list2 = g_list_sort_with_data(list2, sort_node_weight, g_list_nth_data(resource2->running_on, 0)); + max = g_list_length(list1); + if(max < g_list_length(list2)) { + max = g_list_length(list2); + } - for(;lpc < max; lpc++) { - node1 = g_list_nth_data(list1, lpc); - node2 = g_list_nth_data(list2, lpc); - if(node1 == NULL) { - do_crm_log_unlikely(level, "%s < %s: node score NULL", resource1->id, resource2->id); - rc = 1; - break; + for(;lpc < max; lpc++) { + node1 = g_list_nth_data(list1, lpc); + node2 = g_list_nth_data(list2, lpc); + if(node1 == NULL) { + do_crm_log_unlikely(level, "%s < %s: node score NULL", resource1->id, resource2->id); + rc = 1; + break; - } else if(node2 == NULL) { - do_crm_log_unlikely(level, "%s > %s: node score NULL", resource1->id, resource2->id); - rc = -1; - break; - } + } else if(node2 == NULL) { + do_crm_log_unlikely(level, "%s > %s: node score NULL", resource1->id, resource2->id); + rc = -1; + break; + } - if(node1->weight < node2->weight) { - do_crm_log_unlikely(level, "%s < %s: node score", resource1->id, resource2->id); - rc = 1; - break; + if(node1->weight < node2->weight) { + do_crm_log_unlikely(level, "%s < %s: node score", resource1->id, resource2->id); + rc = 1; + break; - } else if(node1->weight > node2->weight) { - do_crm_log_unlikely(level, "%s > %s: node score", resource1->id, resource2->id); - rc = -1; - break; - } + } else if(node1->weight > node2->weight) { + do_crm_log_unlikely(level, "%s > %s: node score", resource1->id, resource2->id); + rc = -1; + break; } + } - g_list_free(list1); - g_list_free(list2); - if(rc != 0) { - return rc; - } + g_list_free(list1); + g_list_free(list2); + if(rc != 0) { + return rc; } + } - can1 = did_fail(resource1); - can2 = did_fail(resource2); - if(can1 != can2) { - if(can1) { - do_crm_log_unlikely(level, "%s > %s: failed", resource1->id, resource2->id); - return 1; - } - do_crm_log_unlikely(level, "%s < %s: failed", resource1->id, resource2->id); - return -1; + can1 = did_fail(resource1); + can2 = did_fail(resource2); + if(can1 != can2) { + if(can1) { + do_crm_log_unlikely(level, "%s > %s: failed", resource1->id, resource2->id); + return 1; } + do_crm_log_unlikely(level, "%s < %s: failed", resource1->id, resource2->id); + return -1; + } - if(node1 && node2) { - int rc = 0; - int max = 0; - int lpc = 0; - node_t *n = NULL; - GListPtr list1 = NULL; - GListPtr list2 = NULL; - GHashTable *hash1 = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_hash_destroy_str); - GHashTable *hash2 = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_hash_destroy_str); + if(node1 && node2) { + int rc = 0; + int lpc = 0; + int max = 0; + node_t *n = NULL; + GListPtr gIter = NULL; + GListPtr list1 = NULL; + GListPtr list2 = NULL; + GHashTable *hash1 = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_hash_destroy_str); + GHashTable *hash2 = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_hash_destroy_str); - n = node_copy(resource1->running_on->data); - g_hash_table_insert(hash1, (gpointer)n->details->id, n); + n = node_copy(resource1->running_on->data); + g_hash_table_insert(hash1, (gpointer)n->details->id, n); - n = node_copy(resource2->running_on->data); - g_hash_table_insert(hash2, (gpointer)n->details->id, n); + n = node_copy(resource2->running_on->data); + g_hash_table_insert(hash2, (gpointer)n->details->id, n); - /* Possibly a replacement for the with_scores block above */ + /* Possibly a replacement for the with_scores block above */ - slist_iter( - constraint, rsc_colocation_t, resource1->parent->rsc_cons_lhs, lpc, - do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource1->id); + for(gIter = resource1->parent->rsc_cons_lhs; gIter; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + + do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource1->id); - hash1 = rsc_merge_weights( - constraint->rsc_lh, resource1->id, hash1, - constraint->node_attribute, - constraint->score/INFINITY, FALSE, TRUE); - ); - - slist_iter( - constraint, rsc_colocation_t, resource2->parent->rsc_cons_lhs, lpc, - do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource2->id); + hash1 = rsc_merge_weights( + constraint->rsc_lh, resource1->id, hash1, + constraint->node_attribute, + constraint->score/INFINITY, FALSE, TRUE); + } + + for(gIter = resource2->parent->rsc_cons_lhs; gIter; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + + do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource2->id); - hash2 = rsc_merge_weights( - constraint->rsc_lh, resource2->id, hash2, - constraint->node_attribute, - constraint->score/INFINITY, FALSE, TRUE); - ); - - list1 = g_hash_table_get_values(hash1); - list2 = g_hash_table_get_values(hash2); + hash2 = rsc_merge_weights( + constraint->rsc_lh, resource2->id, hash2, + constraint->node_attribute, + constraint->score/INFINITY, FALSE, TRUE); + } + + list1 = g_hash_table_get_values(hash1); + list2 = g_hash_table_get_values(hash2); - list1 = g_list_sort_with_data(list1, sort_node_weight, g_list_nth_data(resource1->running_on, 0)); - list2 = g_list_sort_with_data(list2, sort_node_weight, g_list_nth_data(resource2->running_on, 0)); - max = g_list_length(list1); - if(max < g_list_length(list2)) { - max = g_list_length(list2); - } + list1 = g_list_sort_with_data(list1, sort_node_weight, g_list_nth_data(resource1->running_on, 0)); + list2 = g_list_sort_with_data(list2, sort_node_weight, g_list_nth_data(resource2->running_on, 0)); + max = g_list_length(list1); + if(max < g_list_length(list2)) { + max = g_list_length(list2); + } - for(;lpc < max; lpc++) { - node1 = g_list_nth_data(list1, lpc); - node2 = g_list_nth_data(list2, lpc); - if(node1 == NULL) { - do_crm_log_unlikely(level, "%s < %s: colocated score NULL", resource1->id, resource2->id); - rc = 1; - break; - - } else if(node2 == NULL) { - do_crm_log_unlikely(level, "%s > %s: colocated score NULL", resource1->id, resource2->id); - rc = -1; - break; - } + for(;lpc < max; lpc++) { + node1 = g_list_nth_data(list1, lpc); + node2 = g_list_nth_data(list2, lpc); + if(node1 == NULL) { + do_crm_log_unlikely(level, "%s < %s: colocated score NULL", resource1->id, resource2->id); + rc = 1; + break; + + } else if(node2 == NULL) { + do_crm_log_unlikely(level, "%s > %s: colocated score NULL", resource1->id, resource2->id); + rc = -1; + break; + } - if(node1->weight < node2->weight) { - do_crm_log_unlikely(level, "%s < %s: colocated score", resource1->id, resource2->id); - rc = 1; - break; + if(node1->weight < node2->weight) { + do_crm_log_unlikely(level, "%s < %s: colocated score", resource1->id, resource2->id); + rc = 1; + break; - } else if(node1->weight > node2->weight) { - do_crm_log_unlikely(level, "%s > %s: colocated score", resource1->id, resource2->id); - rc = -1; - break; - } + } else if(node1->weight > node2->weight) { + do_crm_log_unlikely(level, "%s > %s: colocated score", resource1->id, resource2->id); + rc = -1; + break; } + } - g_hash_table_destroy(hash1); /* Free mem */ - g_hash_table_destroy(hash2); /* Free mem */ - g_list_free(list1); - g_list_free(list2); + g_hash_table_destroy(hash1); /* Free mem */ + g_hash_table_destroy(hash2); /* Free mem */ + g_list_free(list1); + g_list_free(list2); - if(rc != 0) { - return rc; - } + if(rc != 0) { + return rc; } + } - do_crm_log_unlikely(level, "%s == %s: default %d", resource1->id, resource2->id, node2->weight); - return 0; + do_crm_log_unlikely(level, "%s == %s: default %d", resource1->id, resource2->id, node2->weight); + return 0; } static node_t * can_run_instance(resource_t *rsc, node_t *node) { - node_t *local_node = NULL; - clone_variant_data_t *clone_data = NULL; - if(can_run_resources(node) == FALSE) { - goto bail; + node_t *local_node = NULL; + clone_variant_data_t *clone_data = NULL; + if(can_run_resources(node) == FALSE) { + goto bail; - } else if(is_set(rsc->flags, pe_rsc_orphan)) { - goto bail; - } + } else if(is_set(rsc->flags, pe_rsc_orphan)) { + goto bail; + } - local_node = parent_node_instance(rsc, node); - get_clone_variant_data(clone_data, rsc->parent); + local_node = parent_node_instance(rsc, node); + get_clone_variant_data(clone_data, rsc->parent); - if(local_node == NULL) { - crm_warn("%s cannot run on %s: node not allowed", - rsc->id, node->details->uname); - goto bail; + if(local_node == NULL) { + crm_warn("%s cannot run on %s: node not allowed", + rsc->id, node->details->uname); + goto bail; - } else if(local_node->count < clone_data->clone_node_max) { - return local_node; + } else if(local_node->count < clone_data->clone_node_max) { + return local_node; - } else { - crm_debug_2("%s cannot run on %s: node full", - rsc->id, node->details->uname); - } + } else { + crm_debug_2("%s cannot run on %s: node full", + rsc->id, node->details->uname); + } bail: - if(node) { - common_update_score(rsc, node->details->id, -INFINITY); - } - return NULL; + if(node) { + common_update_score(rsc, node->details->id, -INFINITY); + } + return NULL; } static node_t * color_instance(resource_t *rsc, pe_working_set_t *data_set) { - node_t *chosen = NULL; - node_t *local_node = NULL; + node_t *chosen = NULL; + node_t *local_node = NULL; - crm_debug_2("Processing %s", rsc->id); + crm_debug_2("Processing %s", rsc->id); - if(is_not_set(rsc->flags, pe_rsc_provisional)) { - return rsc->fns->location(rsc, NULL, FALSE); + if(is_not_set(rsc->flags, pe_rsc_provisional)) { + return rsc->fns->location(rsc, NULL, FALSE); - } else if(is_set(rsc->flags, pe_rsc_allocating)) { - crm_debug("Dependency loop detected involving %s", rsc->id); - return NULL; - } + } else if(is_set(rsc->flags, pe_rsc_allocating)) { + crm_debug("Dependency loop detected involving %s", rsc->id); + return NULL; + } - if(rsc->allowed_nodes) { - GHashTableIter iter; - node_t *try_node = NULL; - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&try_node)) { - can_run_instance(rsc, try_node); - } + if(rsc->allowed_nodes) { + GHashTableIter iter; + node_t *try_node = NULL; + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&try_node)) { + can_run_instance(rsc, try_node); } + } - chosen = rsc->cmds->allocate(rsc, data_set); - if(chosen) { - local_node = pe_hash_table_lookup( - rsc->parent->allowed_nodes, chosen->details->id); - - if(local_node) { - local_node->count++; - } else if(is_set(rsc->flags, pe_rsc_managed)) { - /* what to do? we can't enforce per-node limits in this case */ - crm_config_err("%s not found in %s (list=%d)", - chosen->details->id, rsc->parent->id, - g_hash_table_size(rsc->parent->allowed_nodes)); - } + chosen = rsc->cmds->allocate(rsc, data_set); + if(chosen) { + local_node = pe_hash_table_lookup( + rsc->parent->allowed_nodes, chosen->details->id); + + if(local_node) { + local_node->count++; + } else if(is_set(rsc->flags, pe_rsc_managed)) { + /* what to do? we can't enforce per-node limits in this case */ + crm_config_err("%s not found in %s (list=%d)", + chosen->details->id, rsc->parent->id, + g_hash_table_size(rsc->parent->allowed_nodes)); } + } - return chosen; + return chosen; } static void append_parent_colocation(resource_t *rsc, resource_t *child, gboolean all) { - slist_iter(cons, rsc_colocation_t, rsc->rsc_cons, lpc, - if(all || cons->score < 0 || cons->score == INFINITY) { - child->rsc_cons = g_list_prepend(child->rsc_cons, cons); - } - - ); - slist_iter(cons, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, - if(all || cons->score < 0) { - child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons); - } - ); + + GListPtr gIter = NULL; + + gIter = rsc->rsc_cons; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *cons = (rsc_colocation_t*)gIter->data; + + if(all || cons->score < 0 || cons->score == INFINITY) { + child->rsc_cons = g_list_prepend(child->rsc_cons, cons); + } + } + + gIter = rsc->rsc_cons_lhs; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *cons = (rsc_colocation_t*)gIter->data; + + if(all || cons->score < 0) { + child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons); + } + } } node_t * clone_color(resource_t *rsc, pe_working_set_t *data_set) { - int allocated = 0; - GHashTableIter iter; - node_t *node = NULL; - int available_nodes = 0; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + int allocated = 0; + GHashTableIter iter; + GListPtr gIter = NULL; + node_t *node = NULL; + int available_nodes = 0; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - if(is_not_set(rsc->flags, pe_rsc_provisional)) { - return NULL; + if(is_not_set(rsc->flags, pe_rsc_provisional)) { + return NULL; - } else if(is_set(rsc->flags, pe_rsc_allocating)) { - crm_debug("Dependency loop detected involving %s", rsc->id); - return NULL; - } + } else if(is_set(rsc->flags, pe_rsc_allocating)) { + crm_debug("Dependency loop detected involving %s", rsc->id); + return NULL; + } + + set_bit(rsc->flags, pe_rsc_allocating); + crm_debug_2("Processing %s", rsc->id); - set_bit(rsc->flags, pe_rsc_allocating); - crm_debug_2("Processing %s", rsc->id); + /* this information is used by sort_clone_instance() when deciding in which + * order to allocate clone instances + */ - /* this information is used by sort_clone_instance() when deciding in which - * order to allocate clone instances - */ - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, + gIter = rsc->rsc_cons_lhs; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; - rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( - constraint->rsc_lh, rsc->id, rsc->allowed_nodes, - constraint->node_attribute, constraint->score/INFINITY, TRUE, TRUE); - ); + rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( + constraint->rsc_lh, rsc->id, rsc->allowed_nodes, + constraint->node_attribute, constraint->score/INFINITY, TRUE, TRUE); + } - dump_node_scores(show_scores?0:scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes); + dump_node_scores(show_scores?0:scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes); - /* count now tracks the number of clones currently allocated */ - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - node->count = 0; - } + /* count now tracks the number of clones currently allocated */ + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + node->count = 0; + } - slist_iter(child, resource_t, rsc->children, lpc, - if(g_list_length(child->running_on) > 0) { - node_t *child_node = child->running_on->data; - node_t *local_node = parent_node_instance( - child, child->running_on->data); - if(local_node) { - local_node->count++; - } else { - crm_err("%s is running on %s which isn't allowed", - child->id, child_node->details->uname); - } - } - ); + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + + if(g_list_length(child->running_on) > 0) { + node_t *child_node = child->running_on->data; + node_t *local_node = parent_node_instance(child, child->running_on->data); + if(local_node) { + local_node->count++; + } else { + crm_err("%s is running on %s which isn't allowed", + child->id, child_node->details->uname); + } + } + } - rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set); + rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set); - /* count now tracks the number of clones we have allocated */ - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - node->count = 0; - } + /* count now tracks the number of clones we have allocated */ + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + node->count = 0; + } - /* - allowed = g_hash_table_get_values(rsc->allowed_nodes); - allowed = g_list_sort_with_data( - allowed, sort_node_weight, data_set); - */ + /* + allowed = g_hash_table_get_values(rsc->allowed_nodes); + allowed = g_list_sort_with_data( + allowed, sort_node_weight, data_set); + */ - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - if(can_run_resources(node)) { - available_nodes++; - } + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + if(can_run_resources(node)) { + available_nodes++; } + } - slist_iter(child, resource_t, rsc->children, lpc, - if(allocated >= clone_data->clone_max) { - crm_debug("Child %s not allocated - limit reached", child->id); - resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set); + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + + if(allocated >= clone_data->clone_max) { + crm_debug("Child %s not allocated - limit reached", child->id); + resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set); - } else if (clone_data->clone_max < available_nodes) { - /* Only include positive colocation preferences of dependant resources - * if not every node will get a copy of the clone - */ - append_parent_colocation(rsc, child, TRUE); + } else if (clone_data->clone_max < available_nodes) { + /* Only include positive colocation preferences of dependant resources + * if not every node will get a copy of the clone + */ + append_parent_colocation(rsc, child, TRUE); - } else { - append_parent_colocation(rsc, child, FALSE); - } + } else { + append_parent_colocation(rsc, child, FALSE); + } - if(color_instance(child, data_set)) { - allocated++; - } - ); + if(color_instance(child, data_set)) { + allocated++; + } + } + - crm_debug("Allocated %d %s instances of a possible %d", - allocated, rsc->id, clone_data->clone_max); + crm_debug("Allocated %d %s instances of a possible %d", + allocated, rsc->id, clone_data->clone_max); - clear_bit(rsc->flags, pe_rsc_provisional); - clear_bit(rsc->flags, pe_rsc_allocating); + clear_bit(rsc->flags, pe_rsc_provisional); + clear_bit(rsc->flags, pe_rsc_allocating); - return NULL; + return NULL; } static void clone_update_pseudo_status( resource_t *rsc, gboolean *stopping, gboolean *starting, gboolean *active) { - if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - clone_update_pseudo_status(child, stopping, starting, active) - ); - return; + GListPtr gIter = NULL; + if(rsc->children) { + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + + clone_update_pseudo_status(child, stopping, starting, active); } + + return; + } - CRM_ASSERT(active != NULL); - CRM_ASSERT(starting != NULL); - CRM_ASSERT(stopping != NULL); + CRM_ASSERT(active != NULL); + CRM_ASSERT(starting != NULL); + CRM_ASSERT(stopping != NULL); - if(rsc->running_on) { - *active = TRUE; - } + if(rsc->running_on) { + *active = TRUE; + } - slist_iter( - action, action_t, rsc->actions, lpc, - - if(*starting && *stopping) { - return; - - } else if(is_set(action->flags, pe_action_optional)) { - crm_debug_3("Skipping optional: %s", action->uuid); - continue; - - } else if(is_set(action->flags, pe_action_pseudo) == FALSE && is_set(action->flags, pe_action_runnable) == FALSE){ - crm_debug_3("Skipping unrunnable: %s", action->uuid); - continue; - - } else if(safe_str_eq(RSC_STOP, action->task)) { - crm_debug_2("Stopping due to: %s", action->uuid); - *stopping = TRUE; - - } else if(safe_str_eq(RSC_START, action->task)) { - if(is_set(action->flags, pe_action_runnable) == FALSE) { - crm_debug_3("Skipping pseudo-op: %s run=%d, pseudo=%d", - action->uuid, is_set(action->flags, pe_action_runnable), - is_set(action->flags, pe_action_pseudo)); - } else { - crm_debug_2("Starting due to: %s", action->uuid); - crm_debug_3("%s run=%d, pseudo=%d", - action->uuid, is_set(action->flags, pe_action_runnable), - is_set(action->flags, pe_action_pseudo)); - *starting = TRUE; - } - } - ); + gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + if(*starting && *stopping) { + return; + + } else if(is_set(action->flags, pe_action_optional)) { + crm_debug_3("Skipping optional: %s", action->uuid); + continue; + } else if(is_set(action->flags, pe_action_pseudo) == FALSE && is_set(action->flags, pe_action_runnable) == FALSE){ + crm_debug_3("Skipping unrunnable: %s", action->uuid); + continue; + + } else if(safe_str_eq(RSC_STOP, action->task)) { + crm_debug_2("Stopping due to: %s", action->uuid); + *stopping = TRUE; + + } else if(safe_str_eq(RSC_START, action->task)) { + if(is_set(action->flags, pe_action_runnable) == FALSE) { + crm_debug_3("Skipping pseudo-op: %s run=%d, pseudo=%d", + action->uuid, is_set(action->flags, pe_action_runnable), + is_set(action->flags, pe_action_pseudo)); + } else { + crm_debug_2("Starting due to: %s", action->uuid); + crm_debug_3("%s run=%d, pseudo=%d", + action->uuid, is_set(action->flags, pe_action_runnable), + is_set(action->flags, pe_action_pseudo)); + *starting = TRUE; + } + } + } } static action_t * find_rsc_action(resource_t *rsc, const char *key, gboolean active_only, GListPtr *list) { action_t *match = NULL; GListPtr possible = NULL; GListPtr active = NULL; possible = find_actions(rsc->actions, key, NULL); if(active_only) { - slist_iter(op, action_t, possible, lpc, - if(is_set(op->flags, pe_action_optional) == FALSE) { - active = g_list_prepend(active, op); - } - ); + GListPtr gIter = possible; + for(; gIter != NULL; gIter = gIter->next) { + action_t *op = (action_t*)gIter->data; + + if(is_set(op->flags, pe_action_optional) == FALSE) { + active = g_list_prepend(active, op); + } + } if(active && g_list_length(active) == 1) { match = g_list_nth_data(active, 0); } if(list) { *list = active; active = NULL; } } else if(possible && g_list_length(possible) == 1) { match = g_list_nth_data(possible, 0); } if(list) { *list = possible; possible = NULL; } if(possible) { g_list_free(possible); } if(active) { g_list_free(active); } return match; } static void child_ordering_constraints(resource_t *rsc, pe_working_set_t *data_set) { char *key = NULL; action_t *stop = NULL; action_t *start = NULL; action_t *last_stop = NULL; action_t *last_start = NULL; + GListPtr gIter = rsc->children; gboolean active_only = TRUE; /* change to false to get the old behavior */ clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->ordered == FALSE) { return; } - slist_iter( - child, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; key = stop_key(child); stop = find_rsc_action(child, key, active_only, NULL); crm_free(key); key = start_key(child); start = find_rsc_action(child, key, active_only, NULL); crm_free(key); if(stop) { if(last_stop) { /* child/child relative stop */ order_actions(stop, last_stop, pe_order_optional); } last_stop = stop; } if(start) { if(last_start) { /* child/child relative start */ order_actions(last_start, start, pe_order_optional); } last_start = start; } - ); + } } void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set) { - gboolean child_active = FALSE; - gboolean child_starting = FALSE; - gboolean child_stopping = FALSE; + gboolean child_active = FALSE; + gboolean child_starting = FALSE; + gboolean child_stopping = FALSE; - action_t *stop = NULL; - action_t *stopped = NULL; + action_t *stop = NULL; + action_t *stopped = NULL; - action_t *start = NULL; - action_t *started = NULL; + action_t *start = NULL; + action_t *started = NULL; - resource_t *last_start_rsc = NULL; - resource_t *last_stop_rsc = NULL; - clone_variant_data_t *clone_data = NULL; + GListPtr gIter = rsc->children; + resource_t *last_start_rsc = NULL; + resource_t *last_stop_rsc = NULL; + clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + get_clone_variant_data(clone_data, rsc); - crm_debug_2("Creating actions for %s", rsc->id); + crm_debug_2("Creating actions for %s", rsc->id); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - child_rsc->cmds->create_actions(child_rsc, data_set); - clone_update_pseudo_status( - child_rsc, &child_stopping, &child_starting, &child_active); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + + child_rsc->cmds->create_actions(child_rsc, data_set); + clone_update_pseudo_status( + child_rsc, &child_stopping, &child_starting, &child_active); - if(is_set(child_rsc->flags, pe_rsc_starting)) { - last_start_rsc = child_rsc; - } - if(is_set(child_rsc->flags, pe_rsc_stopping)) { - last_stop_rsc = child_rsc; - } - ); + if(is_set(child_rsc->flags, pe_rsc_starting)) { + last_start_rsc = child_rsc; + } + if(is_set(child_rsc->flags, pe_rsc_stopping)) { + last_stop_rsc = child_rsc; + } + } - /* start */ - start = start_action(rsc, NULL, !child_starting); - started = custom_action(rsc, started_key(rsc), - RSC_STARTED, NULL, !child_starting, TRUE, data_set); + /* start */ + start = start_action(rsc, NULL, !child_starting); + started = custom_action(rsc, started_key(rsc), + RSC_STARTED, NULL, !child_starting, TRUE, data_set); - update_action_flags(start, pe_action_pseudo|pe_action_runnable); - update_action_flags(started, pe_action_pseudo); - started->priority = INFINITY; + update_action_flags(start, pe_action_pseudo|pe_action_runnable); + update_action_flags(started, pe_action_pseudo); + started->priority = INFINITY; - if(child_active || child_starting) { - update_action_flags(started, pe_action_runnable); - } + if(child_active || child_starting) { + update_action_flags(started, pe_action_runnable); + } - child_ordering_constraints(rsc, data_set); - if(clone_data->start_notify == NULL) { - clone_data->start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set); - } + child_ordering_constraints(rsc, data_set); + if(clone_data->start_notify == NULL) { + clone_data->start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set); + } - /* stop */ - stop = stop_action(rsc, NULL, !child_stopping); - stopped = custom_action(rsc, stopped_key(rsc), - RSC_STOPPED, NULL, !child_stopping, TRUE, data_set); - - stopped->priority = INFINITY; - update_action_flags(stop, pe_action_pseudo|pe_action_runnable); - update_action_flags(stopped, pe_action_pseudo|pe_action_runnable); - if(clone_data->stop_notify == NULL) { - clone_data->stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set); - - if(clone_data->stop_notify && clone_data->start_notify) { - order_actions(clone_data->stop_notify->post_done, clone_data->start_notify->pre, pe_order_optional); - } + /* stop */ + stop = stop_action(rsc, NULL, !child_stopping); + stopped = custom_action(rsc, stopped_key(rsc), + RSC_STOPPED, NULL, !child_stopping, TRUE, data_set); + + stopped->priority = INFINITY; + update_action_flags(stop, pe_action_pseudo|pe_action_runnable); + update_action_flags(stopped, pe_action_pseudo|pe_action_runnable); + if(clone_data->stop_notify == NULL) { + clone_data->stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set); + + if(clone_data->stop_notify && clone_data->start_notify) { + order_actions(clone_data->stop_notify->post_done, clone_data->start_notify->pre, pe_order_optional); } + } } void clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { - resource_t *last_rsc = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + resource_t *last_rsc = NULL; + GListPtr gIter = rsc->children; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - crm_trace("Internal constraints for %s", rsc->id); - new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); - new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); - new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); + crm_trace("Internal constraints for %s", rsc->id); + new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); + new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); + new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); - if(rsc->variant == pe_master) { - new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set); - new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set); - } + if(rsc->variant == pe_master) { + new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set); + new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set); + } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - child_rsc->cmds->internal_constraints(child_rsc, data_set); + child_rsc->cmds->internal_constraints(child_rsc, data_set); - order_start_start(rsc, child_rsc, pe_order_runnable_left|pe_order_implies_first_printed); - new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed, data_set); - if(clone_data->ordered && last_rsc){ - order_start_start(last_rsc, child_rsc, pe_order_optional); - } + order_start_start(rsc, child_rsc, pe_order_runnable_left|pe_order_implies_first_printed); + new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed, data_set); + if(clone_data->ordered && last_rsc){ + order_start_start(last_rsc, child_rsc, pe_order_optional); + } - order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed); - new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed, data_set); - if(clone_data->ordered && last_rsc){ - order_stop_stop(child_rsc, last_rsc, pe_order_optional); - } + order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed); + new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed, data_set); + if(clone_data->ordered && last_rsc){ + order_stop_stop(child_rsc, last_rsc, pe_order_optional); + } - last_rsc = child_rsc; - ); + last_rsc = child_rsc; + } } static void assign_node(resource_t *rsc, node_t *node, gboolean force) { if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - native_assign_node(child_rsc, NULL, node, force); - ); + + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + native_assign_node(child_rsc, NULL, node, force); + } + return; } native_assign_node(rsc, NULL, node, force); } static resource_t* find_compatible_child_by_node( resource_t *local_child, node_t *local_node, resource_t *rsc, enum rsc_role_e filter, gboolean current) { - node_t *node = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + node_t *node = NULL; + GListPtr gIter = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - if(local_node == NULL) { - crm_err("Can't colocate unrunnable child %s with %s", - local_child->id, rsc->id); - return NULL; - } + if(local_node == NULL) { + crm_err("Can't colocate unrunnable child %s with %s", + local_child->id, rsc->id); + return NULL; + } - crm_trace("Looking for compatible child from %s for %s on %s", - local_child->id, rsc->id, local_node->details->uname); + crm_trace("Looking for compatible child from %s for %s on %s", + local_child->id, rsc->id, local_node->details->uname); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current); - /* enum rsc_role_e next_role = minimum_resource_state(child_rsc, current); */ - enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current); - node = child_rsc->fns->location(child_rsc, NULL, current); + /* enum rsc_role_e next_role = minimum_resource_state(child_rsc, current); */ + node = child_rsc->fns->location(child_rsc, NULL, current); - if(filter != RSC_ROLE_UNKNOWN && next_role != filter) { - crm_trace("Filtered %s", child_rsc->id); - continue; - } + if(filter != RSC_ROLE_UNKNOWN && next_role != filter) { + crm_trace("Filtered %s", child_rsc->id); + continue; + } - if(node && local_node && node->details == local_node->details) { - crm_debug_2("Pairing %s with %s on %s", - local_child->id, child_rsc->id, node->details->uname); - return child_rsc; + if(node && local_node && node->details == local_node->details) { + crm_debug_2("Pairing %s with %s on %s", + local_child->id, child_rsc->id, node->details->uname); + return child_rsc; - } else if(node) { - crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname, local_node->details->uname); + } else if(node) { + crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname, local_node->details->uname); - } else { - crm_trace("%s - not allocated %d", child_rsc->id, current); - } - ); + } else { + crm_trace("%s - not allocated %d", child_rsc->id, current); + } + } - crm_debug_3("Can't pair %s with %s", local_child->id, rsc->id); - return NULL; + crm_debug_3("Can't pair %s with %s", local_child->id, rsc->id); + return NULL; } resource_t* find_compatible_child( resource_t *local_child, resource_t *rsc, enum rsc_role_e filter, gboolean current) { - resource_t *pair = NULL; - GListPtr scratch = NULL; - node_t *local_node = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + resource_t *pair = NULL; + GListPtr gIter = NULL; + GListPtr scratch = NULL; + node_t *local_node = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - local_node = local_child->fns->location(local_child, NULL, current); - if(local_node) { - return find_compatible_child_by_node(local_child, local_node, rsc, filter, current); - } + local_node = local_child->fns->location(local_child, NULL, current); + if(local_node) { + return find_compatible_child_by_node(local_child, local_node, rsc, filter, current); + } - scratch = g_hash_table_get_values(local_child->allowed_nodes); - scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL); + scratch = g_hash_table_get_values(local_child->allowed_nodes); + scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL); - slist_iter( - node, node_t, scratch, lpc, + gIter = scratch; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; - pair = find_compatible_child_by_node( - local_child, node, rsc, filter, current); - if(pair) { - goto done; - } - ); + pair = find_compatible_child_by_node( + local_child, node, rsc, filter, current); + if(pair) { + goto done; + } + } - crm_debug("Can't pair %s with %s", local_child->id, rsc->id); + crm_debug("Can't pair %s with %s", local_child->id, rsc->id); done: - g_list_free(scratch); - return pair; + g_list_free(scratch); + return pair; } void clone_rsc_colocation_lh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - /* -- Never called -- - * - * Instead we add the colocation constraints to the child and call from there - */ + /* -- Never called -- + * + * Instead we add the colocation constraints to the child and call from there + */ - CRM_CHECK(FALSE, crm_err("This functionality is not thought to be used. Please report a bug.")); - CRM_CHECK(rsc_lh, return); - CRM_CHECK(rsc_rh, return); + GListPtr gIter = rsc_lh->children; + CRM_CHECK(FALSE, crm_err("This functionality is not thought to be used. Please report a bug.")); + CRM_CHECK(rsc_lh, return); + CRM_CHECK(rsc_rh, return); - slist_iter( - child_rsc, resource_t, rsc_lh->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint); - ); + child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint); + } - return; + return; } void clone_rsc_colocation_rh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - gboolean do_interleave = FALSE; - clone_variant_data_t *clone_data = NULL; - clone_variant_data_t *clone_data_lh = NULL; + GListPtr gIter = NULL; + gboolean do_interleave = FALSE; + clone_variant_data_t *clone_data = NULL; + clone_variant_data_t *clone_data_lh = NULL; - CRM_CHECK(rsc_lh != NULL, return); - CRM_CHECK(rsc_lh->variant == pe_native, return); + CRM_CHECK(rsc_lh != NULL, return); + CRM_CHECK(rsc_lh->variant == pe_native, return); - get_clone_variant_data(clone_data, constraint->rsc_rh); - crm_debug_3("Processing constraint %s: %s -> %s %d", - constraint->id, rsc_lh->id, rsc_rh->id, constraint->score); - - if(constraint->rsc_lh->variant >= pe_clone) { - - get_clone_variant_data(clone_data_lh, constraint->rsc_lh); - if(clone_data->clone_node_max != clone_data_lh->clone_node_max) { - crm_config_err("Cannot interleave "XML_CIB_TAG_INCARNATION - " %s and %s because" - " they do not support the same number of" - " resources per node", - constraint->rsc_lh->id, constraint->rsc_rh->id); + get_clone_variant_data(clone_data, constraint->rsc_rh); + crm_debug_3("Processing constraint %s: %s -> %s %d", + constraint->id, rsc_lh->id, rsc_rh->id, constraint->score); + + if(constraint->rsc_lh->variant >= pe_clone) { + + get_clone_variant_data(clone_data_lh, constraint->rsc_lh); + if(clone_data->clone_node_max != clone_data_lh->clone_node_max) { + crm_config_err("Cannot interleave "XML_CIB_TAG_INCARNATION + " %s and %s because" + " they do not support the same number of" + " resources per node", + constraint->rsc_lh->id, constraint->rsc_rh->id); - /* only the LHS side needs to be labeled as interleave */ - } else if(clone_data_lh->interleave) { - do_interleave = TRUE; - } + /* only the LHS side needs to be labeled as interleave */ + } else if(clone_data_lh->interleave) { + do_interleave = TRUE; } + } - if(rsc_rh == NULL) { - pe_err("rsc_rh was NULL for %s", constraint->id); - return; + if(rsc_rh == NULL) { + pe_err("rsc_rh was NULL for %s", constraint->id); + return; - } else if(is_set(rsc_rh->flags, pe_rsc_provisional)) { - crm_debug_3("%s is still provisional", rsc_rh->id); - return; + } else if(is_set(rsc_rh->flags, pe_rsc_provisional)) { + crm_debug_3("%s is still provisional", rsc_rh->id); + return; - } else if(do_interleave) { - resource_t *rh_child = NULL; + } else if(do_interleave) { + resource_t *rh_child = NULL; - rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN, FALSE); + rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN, FALSE); - if(rh_child) { - crm_debug("Pairing %s with %s", rsc_lh->id, rh_child->id); - rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint); + if(rh_child) { + crm_debug("Pairing %s with %s", rsc_lh->id, rh_child->id); + rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint); - } else if(constraint->score >= INFINITY) { - crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id); - assign_node(rsc_lh, NULL, TRUE); + } else if(constraint->score >= INFINITY) { + crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id); + assign_node(rsc_lh, NULL, TRUE); - } else { - crm_debug("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id); - } + } else { + crm_debug("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id); + } - return; + return; - } else if(constraint->score >= INFINITY) { - GListPtr rhs = NULL; - - slist_iter( - child_rsc, resource_t, rsc_rh->children, lpc, - node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); - if(chosen != NULL) { - rhs = g_list_prepend(rhs, chosen); - } - ); - - node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE); - g_list_free(rhs); - return; + } else if(constraint->score >= INFINITY) { + GListPtr rhs = NULL; + + gIter = rsc_rh->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); + + if(chosen != NULL) { + rhs = g_list_prepend(rhs, chosen); + } } - slist_iter( - child_rsc, resource_t, rsc_rh->children, lpc, + node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE); + g_list_free(rhs); + return; + } + + gIter = rsc_rh->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); - ); + child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); + } } static enum action_tasks clone_child_action(action_t *action) { enum action_tasks result = no_action; if(safe_str_eq(action->task, "notify") - || safe_str_eq(action->task, "notified")) { + || safe_str_eq(action->task, "notified")) { /* Find the action we're notifying about instead */ int stop = 0; char *key = action->uuid; int lpc = strlen(key); for(; lpc > 0; lpc--) { if(key[lpc] == '_' && stop == 0) { stop = lpc; } else if(key[lpc] == '_') { char *task_mutable = NULL; lpc++; task_mutable = crm_strdup(key+lpc); task_mutable[stop-lpc] = 0; crm_trace("Extracted action '%s' from '%s'", task_mutable, key); result = text2task(task_mutable); crm_free(task_mutable); break; } } } else { result = text2task(action->task); } switch(result) { case stopped_rsc: case started_rsc: case action_demoted: case action_promoted: result--; break; default: break; } return result; } enum pe_action_flags clone_action_flags(action_t *action, node_t *node) { + GListPtr gIter = NULL; gboolean any_runnable = FALSE; gboolean check_runnable = TRUE; enum action_tasks task = clone_child_action(action); enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo); const char *task_s = task2text(task); - slist_iter( - child, resource_t, action->rsc->children, lpc, - + gIter = action->rsc->children; + for(; gIter != NULL; gIter = gIter->next) { action_t *child_action = NULL; + resource_t *child = (resource_t*)gIter->data; + child_action = find_first_action(child->actions, NULL, task_s, child->children?NULL:node); crm_trace("Checking for %s in %s on %s", task_s, child->id, node?node->details->uname:"none"); if(child_action) { enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node); if(is_set(flags, pe_action_optional) && is_set(child_flags, pe_action_optional) == FALSE) { crm_trace("%s is manditory because of %s", action->uuid, child_action->uuid); clear_bit_inplace(flags, pe_action_optional); clear_bit_inplace(action->flags, pe_action_optional); } if(is_set(child_flags, pe_action_runnable)) { any_runnable = TRUE; } + } else { - slist_iter(op, action_t, child->actions, lpc2, - crm_trace("%s on %s (%s)", op->uuid, op->node?op->node->details->uname:"none", op->task)); + + GListPtr gIter2 = child->actions; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + action_t *op = (action_t*)gIter2->data; + crm_trace("%s on %s (%s)", op->uuid, op->node?op->node->details->uname:"none", op->task); + } } - ); + } if(check_runnable && any_runnable == FALSE) { crm_trace("%s is not runnable because no children are", action->uuid); clear_bit_inplace(flags, pe_action_runnable); if(node == NULL) { clear_bit_inplace(action->flags, pe_action_runnable); } } return flags; } static enum pe_graph_flags clone_update_actions_interleave( action_t *first, action_t *then, node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type) { gboolean current = FALSE; resource_t *first_child = NULL; + GListPtr gIter = then->rsc->children; enum pe_graph_flags changed = pe_graph_none; /*pe_graph_disable*/ enum action_tasks task = clone_child_action(first); const char *first_task = task2text(task); /* Fix this - lazy */ if(strstr(first->uuid, "_stopped_0") || strstr(first->uuid, "_demoted_0")) { current = TRUE; } - slist_iter( - then_child, resource_t, then->rsc->children, lpc, - + for(; gIter != NULL; gIter = gIter->next) { + resource_t *then_child = (resource_t*)gIter->data; + CRM_ASSERT(then_child != NULL); first_child = find_compatible_child(then_child, first->rsc, RSC_ROLE_UNKNOWN, current); if(first_child == NULL && current) { crm_trace("Ignore"); } else if(first_child == NULL) { crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid, then->uuid); /* Me no like this hack - but what else can we do? * * If there is no-one active or about to be active * on the same node as then_child, then they must * not be allowed to start */ if(type & (pe_order_runnable_left|pe_order_implies_then) /* Mandatory */) { crm_info("Inhibiting %s from being active", then_child->id); assign_node(then_child, NULL, TRUE); } } else { action_t *first_action = NULL; action_t *then_action = NULL; crm_debug("Pairing %s with %s", first_child->id, then_child->id); first_action = find_first_action(first_child->actions, NULL, first_task, node); then_action = find_first_action(then_child->actions, NULL, then->task, node); CRM_CHECK(first_action != NULL, crm_err("No action found for %s in %s (first)", first_task, first_child->id)); CRM_CHECK(then_action != NULL, crm_err("No action found for %s in %s (then)", then->task, then_child->id)); if(first_action == NULL || then_action == NULL) { continue; } if(order_actions(first_action, then_action, type)) { crm_debug("Created constraint for %s -> %s", first_action->uuid, then_action->uuid); changed |= (pe_graph_updated_first|pe_graph_updated_then); } changed |= then_child->cmds->update_actions(first_action, then_action, node, then_child->cmds->action_flags(then_action, node), filter, type); - } - - ); + } + } return changed; } enum pe_graph_flags clone_update_actions( action_t *first, action_t *then, node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type) { const char *rsc = "none"; gboolean interleave = FALSE; enum pe_graph_flags changed = pe_graph_none; if(first->rsc != then->rsc && first->rsc && first->rsc->variant >= pe_clone && then->rsc && then->rsc->variant >= pe_clone) { clone_variant_data_t *clone_data = NULL; if(strstr(then->uuid, "_stop_0") || strstr(then->uuid, "_demote_0")) { get_clone_variant_data(clone_data, first->rsc); rsc = first->rsc->id; } else { get_clone_variant_data(clone_data, then->rsc); rsc = then->rsc->id; } interleave = clone_data->interleave; } crm_trace("Interleave %s -> %s: %s (based on %s)", first->uuid, then->uuid, interleave?"yes":"no", rsc); if(interleave) { changed = clone_update_actions_interleave(first, then, node, flags, filter, type); } else { + GListPtr gIter = then->rsc->children; changed |= native_update_actions(first, then, node, flags, filter, type); - - slist_iter( - child, resource_t, then->rsc->children, lpc, - + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; action_t *child_action = find_first_action(child->actions, NULL, then->task, node); + if(child_action) { enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node); if(is_set(child_flags, pe_action_runnable)) { changed |= child->cmds->update_actions(first, child_action, node, flags, filter, type); } } - ); + } } return changed; } void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + GListPtr gIter = rsc->children; + crm_debug_3("Processing location constraint %s for %s", + constraint->id, rsc->id); - crm_debug_3("Processing location constraint %s for %s", - constraint->id, rsc->id); + native_rsc_location(rsc, constraint); - native_rsc_location(rsc, constraint); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - - child_rsc->cmds->rsc_location(child_rsc, constraint); - ); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->rsc_location(child_rsc, constraint); + } } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - slist_iter(op, action_t, rsc->actions, lpc, - rsc->cmds->action_flags(op, NULL); - ); - - if(clone_data->start_notify) { - collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify); - expand_notification_data(clone_data->start_notify); - create_notifications(rsc, clone_data->start_notify, data_set); - } + GListPtr gIter = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - if(clone_data->stop_notify) { - collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify); - expand_notification_data(clone_data->stop_notify); - create_notifications(rsc, clone_data->stop_notify, data_set); - } + gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *op = (action_t*)gIter->data; + rsc->cmds->action_flags(op, NULL); + } + + if(clone_data->start_notify) { + collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify); + expand_notification_data(clone_data->start_notify); + create_notifications(rsc, clone_data->start_notify, data_set); + } + + if(clone_data->stop_notify) { + collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify); + expand_notification_data(clone_data->stop_notify); + create_notifications(rsc, clone_data->stop_notify, data_set); + } - if(clone_data->promote_notify) { - collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify); - expand_notification_data(clone_data->promote_notify); - create_notifications(rsc, clone_data->promote_notify, data_set); - } + if(clone_data->promote_notify) { + collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify); + expand_notification_data(clone_data->promote_notify); + create_notifications(rsc, clone_data->promote_notify, data_set); + } - if(clone_data->demote_notify) { - collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify); - expand_notification_data(clone_data->demote_notify); - create_notifications(rsc, clone_data->demote_notify, data_set); - } + if(clone_data->demote_notify) { + collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify); + expand_notification_data(clone_data->demote_notify); + create_notifications(rsc, clone_data->demote_notify, data_set); + } - /* Now that the notifcations have been created we can expand the children */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - child_rsc->cmds->expand(child_rsc, data_set)); - - native_expand(rsc, data_set); - - /* The notifications are in the graph now, we can destroy the notify_data */ - free_notification_data(clone_data->demote_notify); clone_data->demote_notify = NULL; - free_notification_data(clone_data->stop_notify); clone_data->stop_notify = NULL; - free_notification_data(clone_data->start_notify); clone_data->start_notify = NULL; - free_notification_data(clone_data->promote_notify); clone_data->promote_notify = NULL; + /* Now that the notifcations have been created we can expand the children */ + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->expand(child_rsc, data_set); + } + + native_expand(rsc, data_set); + + /* The notifications are in the graph now, we can destroy the notify_data */ + free_notification_data(clone_data->demote_notify); clone_data->demote_notify = NULL; + free_notification_data(clone_data->stop_notify); clone_data->stop_notify = NULL; + free_notification_data(clone_data->start_notify); clone_data->start_notify = NULL; + free_notification_data(clone_data->promote_notify); clone_data->promote_notify = NULL; } static gint sort_rsc_id(gconstpointer a, gconstpointer b) { - const resource_t *resource1 = (const resource_t*)a; - const resource_t *resource2 = (const resource_t*)b; + const resource_t *resource1 = (const resource_t*)a; + const resource_t *resource2 = (const resource_t*)b; - CRM_ASSERT(resource1 != NULL); - CRM_ASSERT(resource2 != NULL); + CRM_ASSERT(resource1 != NULL); + CRM_ASSERT(resource2 != NULL); - return strcmp(resource1->id, resource2->id); + return strcmp(resource1->id, resource2->id); } node_t *rsc_known_on(resource_t *rsc, GListPtr *list) { + GListPtr gIter = NULL; node_t *one = NULL; GListPtr result = NULL; if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - rsc_known_on(child, &result); - ); + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + rsc_known_on(child, &result); + } } else if(rsc->known_on) { result = g_hash_table_get_values(rsc->known_on); } if(result && g_list_length(result) == 1) { one = g_list_nth_data(result, 0); } if(list) { - slist_iter(node, node_t, result, lpc, - if(*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) { - *list = g_list_prepend(*list, node); - } - ); + GListPtr gIter = NULL; + gIter = result; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + + if(*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) { + *list = g_list_prepend(*list, node); + } + } } g_list_free(result); return one; } static resource_t *find_instance_on(resource_t *rsc, node_t *node) { - slist_iter(child, resource_t, rsc->children, lpc, - GListPtr known_list = NULL; - rsc_known_on(child, &known_list); - slist_iter(known, node_t, known_list, lpc2, - if(node->details == known->details) { - g_list_free(known_list); - return child; - } - ); - g_list_free(known_list); - ); + GListPtr gIter = NULL; + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + GListPtr gIter2 = NULL; + GListPtr known_list = NULL; + resource_t *child = (resource_t*)gIter->data; + + rsc_known_on(child, &known_list); + + gIter2 = known_list; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + node_t *known = (node_t*)gIter2->data; + + if(node->details == known->details) { + g_list_free(known_list); + return child; + } + } + g_list_free(known_list); + } + return NULL; } gboolean clone_create_probe(resource_t *rsc, node_t *node, action_t *complete, - gboolean force, pe_working_set_t *data_set) + gboolean force, pe_working_set_t *data_set) { - gboolean any_created = FALSE; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + GListPtr gIter = NULL; + gboolean any_created = FALSE; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - rsc->children = g_list_sort(rsc->children, sort_rsc_id); - if(rsc->children == NULL) { - pe_warn("Clone %s has no children", rsc->id); - return FALSE; - } + rsc->children = g_list_sort(rsc->children, sort_rsc_id); + if(rsc->children == NULL) { + pe_warn("Clone %s has no children", rsc->id); + return FALSE; + } - if(is_not_set(rsc->flags, pe_rsc_unique) - && clone_data->clone_node_max == 1) { - /* only look for one copy */ - resource_t *child = NULL; - - /* Try whoever we probed last time */ - child = find_instance_on(rsc, node); - if(child) { - return child->cmds->create_probe( - child, node, complete, force, data_set); - } + if(is_not_set(rsc->flags, pe_rsc_unique) + && clone_data->clone_node_max == 1) { + /* only look for one copy */ + resource_t *child = NULL; + + /* Try whoever we probed last time */ + child = find_instance_on(rsc, node); + if(child) { + return child->cmds->create_probe( + child, node, complete, force, data_set); + } - /* Try whoever we plan on starting there */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + /* Try whoever we plan on starting there */ + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + node_t *local_node = child_rsc->fns->location(child_rsc, NULL, FALSE); - node_t *local_node = child_rsc->fns->location(child_rsc, NULL, FALSE); - if(local_node == NULL) { - continue; - } + if(local_node == NULL) { + continue; + } - if(local_node->details == node->details) { - return child_rsc->cmds->create_probe( - child_rsc, node, complete, force, data_set); - } - ); - - /* Fall back to the first clone instance */ - child = rsc->children->data; - return child->cmds->create_probe(child, node, complete, force, data_set); + if(local_node->details == node->details) { + return child_rsc->cmds->create_probe( + child_rsc, node, complete, force, data_set); + } } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - if(child_rsc->cmds->create_probe( - child_rsc, node, complete, force, data_set)) { - any_created = TRUE; - } + /* Fall back to the first clone instance */ + child = rsc->children->data; + return child->cmds->create_probe(child, node, complete, force, data_set); + } + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + + if(child_rsc->cmds->create_probe( + child_rsc, node, complete, force, data_set)) { + any_created = TRUE; + } - if(any_created - && is_not_set(rsc->flags, pe_rsc_unique) - && clone_data->clone_node_max == 1) { - /* only look for one copy (clone :0) */ - break; - } - ); + if(any_created + && is_not_set(rsc->flags, pe_rsc_unique) + && clone_data->clone_node_max == 1) { + /* only look for one copy (clone :0) */ + break; + } + } - return any_created; + return any_created; } void clone_append_meta(resource_t *rsc, xmlNode *xml) { char *name = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); name = crm_meta_name(XML_RSC_ATTR_UNIQUE); crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_unique)?"true":"false"); crm_free(name); name = crm_meta_name(XML_RSC_ATTR_NOTIFY); crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_notify)?"true":"false"); crm_free(name); name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX); crm_xml_add_int(xml, name, clone_data->clone_max); crm_free(name); name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX); crm_xml_add_int(xml, name, clone_data->clone_node_max); crm_free(name); } diff --git a/pengine/constraints.c b/pengine/constraints.c index c0226484b9..a261abb4fb 100644 --- a/pengine/constraints.c +++ b/pengine/constraints.c @@ -1,1341 +1,1344 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum pe_order_kind { pe_order_kind_optional, pe_order_kind_mandatory, pe_order_kind_serialize, }; enum pe_ordering get_flags( const char *id, enum pe_order_kind kind, const char *action_first, const char *action_then, gboolean invert); gboolean unpack_constraints(xmlNode * xml_constraints, pe_working_set_t *data_set) { xmlNode *lifetime = NULL; xml_child_iter( xml_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { crm_config_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_debug_3("Processing constraint %s %s", crm_element_name(xml_obj),id); lifetime = first_named_child(xml_obj, "lifetime"); if(lifetime) { crm_config_warn("Support for the lifetime tag, used by %s, is deprecated." " The rules it contains should instead be direct decendants of the constraint object", id); } if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) { crm_info("Constraint %s %s is not active", crm_element_name(xml_obj), id); } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location(xml_obj, data_set); } else { pe_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } static const char * invert_action(const char *action) { if(safe_str_eq(action, RSC_START)) { return RSC_STOP; } else if(safe_str_eq(action, RSC_STOP)) { return RSC_START; } else if(safe_str_eq(action, RSC_PROMOTE)) { return RSC_DEMOTE; } else if(safe_str_eq(action, RSC_DEMOTE)) { return RSC_PROMOTE; } else if(safe_str_eq(action, RSC_PROMOTED)) { return RSC_DEMOTED; } else if(safe_str_eq(action, RSC_DEMOTED)) { return RSC_PROMOTED; } else if(safe_str_eq(action, RSC_STARTED)) { return RSC_STOPPED; } else if(safe_str_eq(action, RSC_STOPPED)) { return RSC_STARTED; } crm_config_warn("Unknown action: %s", action); return NULL; } static enum pe_order_kind get_ordering_type(xmlNode *xml_obj) { enum pe_order_kind kind_e = pe_order_kind_mandatory; const char *kind = crm_element_value(xml_obj, XML_ORDER_ATTR_KIND); if(kind == NULL) { const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); kind_e = pe_order_kind_mandatory; if(score) { int score_i = char2score(score); if(score_i == 0) { kind_e = pe_order_kind_optional; } /* } else if(rsc_then->variant == pe_native && rsc_first->variant > pe_group) { */ /* kind_e = pe_order_kind_optional; */ } } else if(safe_str_eq(kind, "Mandatory")) { kind_e = pe_order_kind_mandatory; } else if(safe_str_eq(kind, "Optional")) { kind_e = pe_order_kind_optional; } else if(safe_str_eq(kind, "Serialize")) { kind_e = pe_order_kind_serialize; } else { const char *id = crm_element_value(xml_obj, XML_ATTR_ID); crm_config_err("Constraint %s: Unknown type '%s'", id, kind); } return kind_e; } static gboolean unpack_simple_rsc_order(xmlNode * xml_obj, pe_working_set_t *data_set) { int order_id = 0; resource_t *rsc_then = NULL; resource_t *rsc_first = NULL; gboolean invert_bool = TRUE; enum pe_order_kind kind = pe_order_kind_mandatory; enum pe_ordering cons_weight = pe_order_optional; const char *id_first = NULL; const char *id_then = NULL; const char *action_then = NULL; const char *action_first = NULL; const char *instance_then = NULL; const char *instance_first = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *invert = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL); crm_str_to_boolean(invert, &invert_bool); if(xml_obj == NULL) { crm_config_err("No constraint object to process."); return FALSE; } else if(id == NULL) { crm_config_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } id_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN); id_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST); action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION); action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION); instance_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_INSTANCE); instance_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_INSTANCE); if(action_first == NULL) { action_first = RSC_START; } if(action_then == NULL) { action_then = action_first; } if(id_then == NULL || id_first == NULL) { crm_config_err("Constraint %s needs two sides lh: %s rh: %s", id, crm_str(id_then), crm_str(id_first)); return FALSE; } rsc_then = pe_find_resource(data_set->resources, id_then); rsc_first = pe_find_resource(data_set->resources, id_first); if(rsc_then == NULL) { crm_config_err("Constraint %s: no resource found for name '%s'", id, id_then); return FALSE; } else if(rsc_first == NULL) { crm_config_err("Constraint %s: no resource found for name '%s'", id, id_first); return FALSE; } else if(instance_then && rsc_then->variant < pe_clone) { crm_config_err("Invalid constraint '%s':" " Resource '%s' is not a clone but instance %s was requested", id, id_then, instance_then); return FALSE; } else if(instance_first && rsc_first->variant < pe_clone) { crm_config_err("Invalid constraint '%s':" " Resource '%s' is not a clone but instance %s was requested", id, id_first, instance_first); return FALSE; } if(instance_then) { rsc_then = find_clone_instance(rsc_then, instance_then, data_set); if(rsc_then == NULL) { crm_config_warn("Invalid constraint '%s': No instance '%s' of '%s'", id, instance_then, id_then); return FALSE; } } if(instance_first) { rsc_first = find_clone_instance(rsc_first, instance_first, data_set); if(rsc_first == NULL) { crm_config_warn("Invalid constraint '%s': No instance '%s' of '%s'", id, instance_first, id_first); return FALSE; } } cons_weight = pe_order_optional; kind = get_ordering_type(xml_obj); if(kind == pe_order_kind_optional && rsc_then->restart_type == pe_restart_restart) { crm_debug_2("Upgrade : recovery - implies right"); cons_weight |= pe_order_implies_then; } cons_weight |= get_flags(id, kind, action_first, action_then, FALSE); order_id = new_rsc_order( rsc_first, action_first, rsc_then, action_then, cons_weight, data_set); crm_debug_2("order-%d (%s): %s_%s before %s_%s flags=0x%.6x", order_id, id, rsc_first->id, action_first, rsc_then->id, action_then, cons_weight); if(invert_bool == FALSE) { return TRUE; } else if(invert && kind == pe_order_kind_serialize) { crm_config_warn("Cannot invert serialized constraint set %s", id); return TRUE; } else if(kind == pe_order_kind_serialize) { return TRUE; } action_then = invert_action(action_then); action_first = invert_action(action_first); if(action_then == NULL || action_first == NULL) { crm_config_err("Cannot invert rsc_order constraint %s." " Please specify the inverse manually.", id); return TRUE; } cons_weight = pe_order_optional; if(kind == pe_order_kind_optional && rsc_then->restart_type == pe_restart_restart) { crm_debug_2("Upgrade : recovery - implies left"); cons_weight |= pe_order_implies_first; } cons_weight |= get_flags(id, kind, action_first, action_then, TRUE); order_id = new_rsc_order( rsc_then, action_then, rsc_first, action_first, cons_weight, data_set); crm_debug_2("order-%d (%s): %s_%s before %s_%s flags=0x%.6x", order_id, id, rsc_then->id, action_then, rsc_first->id, action_first, cons_weight); return TRUE; } gboolean unpack_rsc_location(xmlNode * xml_obj, pe_working_set_t *data_set) { gboolean empty = TRUE; rsc_to_node_t *location = NULL; const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); const char *node = crm_element_value(xml_obj, "node"); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *domain = crm_element_value(xml_obj, XML_CIB_TAG_DOMAIN); const char *role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE); if(rsc_lh == NULL) { /* only a warn as BSC adds the constraint then the resource */ crm_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } if(domain) { GListPtr nodes = g_hash_table_lookup(data_set->domains, domain); if(domain == NULL) { crm_config_err("Invalid constraint %s: Domain %s does not exist", id, domain); return FALSE; } location = rsc2node_new(id, rsc_lh, 0, NULL, data_set); location->node_list_rh = node_list_dup(nodes, FALSE, FALSE); } else if(node != NULL && score != NULL) { int score_i = char2score(score); node_t *match = pe_find_node(data_set->nodes, node); if(!match) { return FALSE; } location = rsc2node_new(id, rsc_lh, score_i, match, data_set); } else { xml_child_iter_filter( xml_obj, rule_xml, XML_TAG_RULE, empty = FALSE; crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); generate_location_rule(rsc_lh, rule_xml, data_set); ); if(empty) { crm_config_err("Invalid location constraint %s:" " rsc_location must contain at least one rule", ID(xml_obj)); } } if(location && role) { if(text2role(role) == RSC_ROLE_UNKNOWN) { pe_err("Invalid constraint %s: Bad role %s", id, role); return FALSE; } else { location->role_filter = text2role(role); if(location->role_filter == RSC_ROLE_SLAVE) { /* Fold slave back into Started for simplicity * At the point Slave location constraints are evaluated, * all resources are still either stopped or started */ location->role_filter = RSC_ROLE_STARTED; } } } return TRUE; } static int get_node_score(const char *rule, const char *score, gboolean raw, node_t *node) { int score_f = 0; if(score == NULL) { pe_err("Rule %s: no score specified. Assuming 0.", rule); } else if(raw) { score_f = char2score(score); } else { const char *attr_score = g_hash_table_lookup( node->details->attrs, score); if(attr_score == NULL) { crm_debug("Rule %s: node %s did not have a value for %s", rule, node->details->uname, score); score_f = -INFINITY; } else { crm_debug("Rule %s: node %s had value %s for %s", rule, node->details->uname, attr_score, score); score_f = char2score(attr_score); } } return score_f; } rsc_to_node_t * generate_location_rule( - resource_t *rsc, xmlNode *rule_xml, pe_working_set_t *data_set) + resource_t *rsc, xmlNode *rule_xml, pe_working_set_t *data_set) { - const char *rule_id = NULL; - const char *score = NULL; - const char *boolean = NULL; - const char *role = NULL; + const char *rule_id = NULL; + const char *score = NULL; + const char *boolean = NULL; + const char *role = NULL; - GListPtr match_L = NULL; + GListPtr gIter = NULL; + GListPtr match_L = NULL; - int score_f = 0; - gboolean do_and = TRUE; - gboolean accept = TRUE; - gboolean raw_score = TRUE; + int score_f = 0; + gboolean do_and = TRUE; + gboolean accept = TRUE; + gboolean raw_score = TRUE; - rsc_to_node_t *location_rule = NULL; + rsc_to_node_t *location_rule = NULL; - rule_xml = expand_idref(rule_xml, data_set->input); - rule_id = crm_element_value(rule_xml, XML_ATTR_ID); - boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); - role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); + rule_xml = expand_idref(rule_xml, data_set->input); + rule_id = crm_element_value(rule_xml, XML_ATTR_ID); + boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); + role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); - crm_debug_2("Processing rule: %s", rule_id); + crm_debug_2("Processing rule: %s", rule_id); - if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { - pe_err("Bad role specified for %s: %s", rule_id, role); - return NULL; - } + if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { + pe_err("Bad role specified for %s: %s", rule_id, role); + return NULL; + } - score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); - if(score != NULL) { - score_f = char2score(score); + score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); + if(score != NULL) { + score_f = char2score(score); - } else { - score = crm_element_value( - rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); - if(score == NULL) { - score = crm_element_value( - rule_xml, XML_RULE_ATTR_SCORE_MANGLED); - } - if(score != NULL) { - raw_score = FALSE; - } + } else { + score = crm_element_value( + rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); + if(score == NULL) { + score = crm_element_value( + rule_xml, XML_RULE_ATTR_SCORE_MANGLED); } - if(safe_str_eq(boolean, "or")) { - do_and = FALSE; + if(score != NULL) { + raw_score = FALSE; } + } + if(safe_str_eq(boolean, "or")) { + do_and = FALSE; + } - location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); + location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); - if(location_rule == NULL) { - return NULL; - } - if(role != NULL) { - crm_debug_2("Setting role filter: %s", role); - location_rule->role_filter = text2role(role); - if(location_rule->role_filter == RSC_ROLE_SLAVE) { - /* Fold slave back into Started for simplicity - * At the point Slave location constraints are evaluated, - * all resources are still either stopped or started - */ - location_rule->role_filter = RSC_ROLE_STARTED; - } + if(location_rule == NULL) { + return NULL; + } + if(role != NULL) { + crm_debug_2("Setting role filter: %s", role); + location_rule->role_filter = text2role(role); + if(location_rule->role_filter == RSC_ROLE_SLAVE) { + /* Fold slave back into Started for simplicity + * At the point Slave location constraints are evaluated, + * all resources are still either stopped or started + */ + location_rule->role_filter = RSC_ROLE_STARTED; } - if(do_and) { - match_L = node_list_dup(data_set->nodes, TRUE, FALSE); - slist_iter( - node, node_t, match_L, lpc, - node->weight = get_node_score(rule_id, score, raw_score, node); - ); + } + if(do_and) { + GListPtr gIter = NULL; + match_L = node_list_dup(data_set->nodes, TRUE, FALSE); + gIter = match_L; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + node->weight = get_node_score(rule_id, score, raw_score, node); } + } - slist_iter( - node, node_t, data_set->nodes, lpc, - - accept = test_rule( - rule_xml, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); + gIter = data_set->nodes; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; - crm_debug_2("Rule %s %s on %s", ID(rule_xml), accept?"passed":"failed", node->details->uname); + accept = test_rule( + rule_xml, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); - score_f = get_node_score(rule_id, score, raw_score, node); + crm_debug_2("Rule %s %s on %s", ID(rule_xml), accept?"passed":"failed", node->details->uname); + + score_f = get_node_score(rule_id, score, raw_score, node); /* if(accept && score_f == -INFINITY) { */ /* accept = FALSE; */ /* } */ - - if(accept) { - node_t *local = pe_find_node_id( - match_L, node->details->id); - if(local == NULL && do_and) { - continue; - - } else if(local == NULL) { - local = node_copy(node); - match_L = g_list_append(match_L, local); - } - - if(do_and == FALSE) { - local->weight = merge_weights( - local->weight, score_f); - } - crm_debug_2("node %s now has weight %d", - node->details->uname, local->weight); - - } else if(do_and && !accept) { - /* remove it */ - node_t *delete = pe_find_node_id( - match_L, node->details->id); - if(delete != NULL) { - match_L = g_list_remove(match_L,delete); - crm_debug_5("node %s did not match", - node->details->uname); - } - crm_free(delete); - } - ); + + if(accept) { + node_t *local = pe_find_node_id(match_L, node->details->id); + if(local == NULL && do_and) { + continue; + + } else if(local == NULL) { + local = node_copy(node); + match_L = g_list_append(match_L, local); + } + + if(do_and == FALSE) { + local->weight = merge_weights(local->weight, score_f); + } + crm_debug_2("node %s now has weight %d", + node->details->uname, local->weight); + + } else if(do_and && !accept) { + /* remove it */ + node_t *delete = pe_find_node_id(match_L, node->details->id); + if(delete != NULL) { + match_L = g_list_remove(match_L,delete); + crm_debug_5("node %s did not match", + node->details->uname); + } + crm_free(delete); + } + } - location_rule->node_list_rh = match_L; - if(location_rule->node_list_rh == NULL) { - crm_debug_2("No matching nodes for rule %s", rule_id); - return NULL; - } - - crm_debug_3("%s: %d nodes matched", - rule_id, g_list_length(location_rule->node_list_rh)); - return location_rule; + location_rule->node_list_rh = match_L; + if(location_rule->node_list_rh == NULL) { + crm_debug_2("No matching nodes for rule %s", rule_id); + return NULL; + } + + crm_debug_3("%s: %d nodes matched", + rule_id, g_list_length(location_rule->node_list_rh)); + return location_rule; } static gint sort_cons_priority_lh(gconstpointer a, gconstpointer b) { - const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; - const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; + const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; + const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } + if(a == NULL) { return 1; } + if(b == NULL) { return -1; } - CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); - CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); + CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); + CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); - if(rsc_constraint1->rsc_lh->priority > rsc_constraint2->rsc_lh->priority) { - return -1; - } + if(rsc_constraint1->rsc_lh->priority > rsc_constraint2->rsc_lh->priority) { + return -1; + } - if(rsc_constraint1->rsc_lh->priority < rsc_constraint2->rsc_lh->priority) { - return 1; - } + if(rsc_constraint1->rsc_lh->priority < rsc_constraint2->rsc_lh->priority) { + return 1; + } - return strcmp(rsc_constraint1->rsc_lh->id, rsc_constraint2->rsc_lh->id); + return strcmp(rsc_constraint1->rsc_lh->id, rsc_constraint2->rsc_lh->id); } static gint sort_cons_priority_rh(gconstpointer a, gconstpointer b) { - const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; - const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; + const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; + const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } + if(a == NULL) { return 1; } + if(b == NULL) { return -1; } - CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); - CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); + CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); + CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); - if(rsc_constraint1->rsc_rh->priority > rsc_constraint2->rsc_rh->priority) { - return -1; - } + if(rsc_constraint1->rsc_rh->priority > rsc_constraint2->rsc_rh->priority) { + return -1; + } - if(rsc_constraint1->rsc_rh->priority < rsc_constraint2->rsc_rh->priority) { - return 1; - } - return strcmp(rsc_constraint1->rsc_rh->id, rsc_constraint2->rsc_rh->id); + if(rsc_constraint1->rsc_rh->priority < rsc_constraint2->rsc_rh->priority) { + return 1; + } + return strcmp(rsc_constraint1->rsc_rh->id, rsc_constraint2->rsc_rh->id); } gboolean rsc_colocation_new(const char *id, const char *node_attr, int score, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh, pe_working_set_t *data_set) { - rsc_colocation_t *new_con = NULL; - if(rsc_lh == NULL){ - crm_config_err("No resource found for LHS %s", id); - return FALSE; + rsc_colocation_t *new_con = NULL; + if(rsc_lh == NULL){ + crm_config_err("No resource found for LHS %s", id); + return FALSE; - } else if(rsc_rh == NULL){ - crm_config_err("No resource found for RHS of %s", id); - return FALSE; - } + } else if(rsc_rh == NULL){ + crm_config_err("No resource found for RHS of %s", id); + return FALSE; + } - crm_malloc0(new_con, sizeof(rsc_colocation_t)); - if(new_con == NULL) { - return FALSE; - } + crm_malloc0(new_con, sizeof(rsc_colocation_t)); + if(new_con == NULL) { + return FALSE; + } - if(state_lh == NULL - || safe_str_eq(state_lh, RSC_ROLE_STARTED_S)) { - state_lh = RSC_ROLE_UNKNOWN_S; - } + if(state_lh == NULL + || safe_str_eq(state_lh, RSC_ROLE_STARTED_S)) { + state_lh = RSC_ROLE_UNKNOWN_S; + } - if(state_rh == NULL - || safe_str_eq(state_rh, RSC_ROLE_STARTED_S)) { - state_rh = RSC_ROLE_UNKNOWN_S; - } - - new_con->id = id; - new_con->rsc_lh = rsc_lh; - new_con->rsc_rh = rsc_rh; - new_con->score = score; - new_con->role_lh = text2role(state_lh); - new_con->role_rh = text2role(state_rh); - new_con->node_attribute = node_attr; - - if(node_attr == NULL) { - node_attr = "#"XML_ATTR_UNAME; - } + if(state_rh == NULL + || safe_str_eq(state_rh, RSC_ROLE_STARTED_S)) { + state_rh = RSC_ROLE_UNKNOWN_S; + } + + new_con->id = id; + new_con->rsc_lh = rsc_lh; + new_con->rsc_rh = rsc_rh; + new_con->score = score; + new_con->role_lh = text2role(state_lh); + new_con->role_rh = text2role(state_rh); + new_con->node_attribute = node_attr; + + if(node_attr == NULL) { + node_attr = "#"XML_ATTR_UNAME; + } - crm_debug_3("%s ==> %s (%s %d)", rsc_lh->id, rsc_rh->id, node_attr, score); + crm_debug_3("%s ==> %s (%s %d)", rsc_lh->id, rsc_rh->id, node_attr, score); - rsc_lh->rsc_cons = g_list_insert_sorted( - rsc_lh->rsc_cons, new_con, sort_cons_priority_rh); + rsc_lh->rsc_cons = g_list_insert_sorted( + rsc_lh->rsc_cons, new_con, sort_cons_priority_rh); - rsc_rh->rsc_cons_lhs = g_list_insert_sorted( - rsc_rh->rsc_cons_lhs, new_con, sort_cons_priority_lh); + rsc_rh->rsc_cons_lhs = g_list_insert_sorted( + rsc_rh->rsc_cons_lhs, new_con, sort_cons_priority_lh); - data_set->colocation_constraints = g_list_append( - data_set->colocation_constraints, new_con); + data_set->colocation_constraints = g_list_append( + data_set->colocation_constraints, new_con); - return TRUE; + return TRUE; } /* LHS before RHS */ int new_rsc_order(resource_t *lh_rsc, const char *lh_task, resource_t *rh_rsc, const char *rh_task, enum pe_ordering type, pe_working_set_t *data_set) { char *lh_key = NULL; char *rh_key = NULL; CRM_CHECK(lh_rsc != NULL, return -1); CRM_CHECK(lh_task != NULL, return -1); CRM_CHECK(rh_rsc != NULL, return -1); CRM_CHECK(rh_task != NULL, return -1); lh_key = generate_op_key(lh_rsc->id, lh_task, 0); rh_key = generate_op_key(rh_rsc->id, rh_task, 0); return custom_action_order(lh_rsc, lh_key, NULL, rh_rsc, rh_key, NULL, type, data_set); } /* LHS before RHS */ int custom_action_order( resource_t *lh_rsc, char *lh_action_task, action_t *lh_action, resource_t *rh_rsc, char *rh_action_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set) { order_constraint_t *order = NULL; if(lh_rsc == NULL && lh_action) { lh_rsc = lh_action->rsc; } if(rh_rsc == NULL && rh_action) { rh_rsc = rh_action->rsc; } if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL)){ crm_config_err("Invalid inputs %p.%p %p.%p", lh_rsc, lh_action, rh_rsc, rh_action); crm_free(lh_action_task); crm_free(rh_action_task); return -1; } crm_malloc0(order, sizeof(order_constraint_t)); order->id = data_set->order_id++; order->type = type; order->lh_rsc = lh_rsc; order->rh_rsc = rh_rsc; order->lh_action = lh_action; order->rh_action = rh_action; order->lh_action_task = lh_action_task; order->rh_action_task = rh_action_task; data_set->ordering_constraints = g_list_prepend( data_set->ordering_constraints, order); return order->id; } enum pe_ordering get_flags( const char *id, enum pe_order_kind kind, const char *action_first, const char *action_then, gboolean invert) { enum pe_ordering flags = pe_order_optional; if(invert && kind == pe_order_kind_mandatory) { crm_debug_2("Upgrade %s: implies left", id); flags |= pe_order_implies_first; } else if(kind == pe_order_kind_mandatory) { crm_debug_2("Upgrade %s: implies right", id); flags |= pe_order_implies_then; if(safe_str_eq(action_first, RSC_START) || safe_str_eq(action_first, RSC_PROMOTE)) { crm_debug_2("Upgrade %s: runnable", id); flags |= pe_order_runnable_left; } } else if(kind == pe_order_kind_serialize) { flags |= pe_order_serialize_only; } return flags; } static gboolean unpack_order_set(xmlNode *set, enum pe_order_kind kind, resource_t **rsc, action_t **begin, action_t **end, action_t **inv_begin, action_t **inv_end, const char *symmetrical, pe_working_set_t *data_set) { GListPtr set_iter = NULL; GListPtr resources = NULL; resource_t *last = NULL; resource_t *resource = NULL; int local_kind = kind; gboolean sequential = FALSE; enum pe_ordering flags = pe_order_optional; char *key = NULL; const char *id = ID(set); const char *action = crm_element_value(set, "action"); const char *sequential_s = crm_element_value(set, "sequential"); const char *kind_s = crm_element_value(set, XML_ORDER_ATTR_KIND); /* char *pseudo_id = NULL; char *end_id = NULL; char *begin_id = NULL; */ if(action == NULL) { action = RSC_START; } if(kind_s) { local_kind = get_ordering_type(set); } if(sequential_s == NULL) { sequential_s = "1"; } sequential = crm_is_true(sequential_s); flags = get_flags(id, local_kind, action, action, FALSE); xml_child_iter_filter( set, xml_rsc, XML_TAG_RESOURCE_REF, resource = pe_find_resource(data_set->resources, ID(xml_rsc)); resources = g_list_append(resources, resource); ); if(g_list_length(resources) == 1) { crm_debug_2("Single set: %s", id); *rsc = resource; *end = NULL; *begin = NULL; *inv_end = NULL; *inv_begin = NULL; goto done; } /* pseudo_id = crm_concat(id, action, '-'); end_id = crm_concat(pseudo_id, "end", '-'); begin_id = crm_concat(pseudo_id, "begin", '-'); */ *rsc = NULL; /* *end = get_pseudo_op(end_id, data_set); *begin = get_pseudo_op(begin_id, data_set); crm_free(pseudo_id); crm_free(begin_id); crm_free(end_id); */ set_iter = resources; while(set_iter != NULL) { resource = (resource_t *) set_iter->data; set_iter = set_iter->next; key = generate_op_key(resource->id, action, 0); /* custom_action_order(NULL, NULL, *begin, resource, crm_strdup(key), NULL, flags|pe_order_implies_first_printed, data_set); custom_action_order(resource, crm_strdup(key), NULL, NULL, NULL, *end, flags|pe_order_implies_then_printed, data_set); */ if(local_kind == pe_order_kind_serialize) { /* Serialize before everything that comes after */ - slist_iter( - then_rsc, resource_t, set_iter, lpc, + GListPtr gIter = NULL; + gIter = set_iter; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *then_rsc = (resource_t*)gIter->data; char *then_key = generate_op_key(then_rsc->id, action, 0); custom_action_order(resource, crm_strdup(key), NULL, then_rsc, then_key, NULL, flags, data_set); - ); + } } else if(sequential) { if(last != NULL) { new_rsc_order(last, action, resource, action, flags, data_set); } last = resource; } crm_free(key); } if(crm_is_true(symmetrical) == FALSE) { goto done; } else if(symmetrical && local_kind == pe_order_kind_serialize) { crm_config_warn("Cannot invert serialized constraint set %s", id); goto done; } else if(local_kind == pe_order_kind_serialize) { goto done; } last = NULL; action = invert_action(action); /* pseudo_id = crm_concat(id, action, '-'); end_id = crm_concat(pseudo_id, "end", '-'); begin_id = crm_concat(pseudo_id, "begin", '-'); *inv_end = get_pseudo_op(end_id, data_set); *inv_begin = get_pseudo_op(begin_id, data_set); crm_free(pseudo_id); crm_free(begin_id); crm_free(end_id); */ flags = get_flags(id, local_kind, action, action, TRUE); set_iter = resources; while(set_iter != NULL) { resource = (resource_t *) set_iter->data; set_iter = set_iter->next; /* key = generate_op_key(resource->id, action, 0); custom_action_order(NULL, NULL, *inv_begin, resource, crm_strdup(key), NULL, flags|pe_order_implies_first_printed, data_set); custom_action_order(resource, key, NULL, NULL, NULL, *inv_end, flags|pe_order_implies_then_printed, data_set); */ if(sequential) { if(last != NULL) { new_rsc_order(resource, action, last, action, flags, data_set); } last = resource; } } done: g_list_free(resources); return TRUE; } static gboolean order_rsc_sets( const char *id, xmlNode *set1, xmlNode *set2, enum pe_order_kind kind, pe_working_set_t *data_set, gboolean invert) { resource_t *rsc_1 = NULL; resource_t *rsc_2 = NULL; const char *action_1 = crm_element_value(set1, "action"); const char *action_2 = crm_element_value(set2, "action"); const char *sequential_1 = crm_element_value(set1, "sequential"); const char *sequential_2 = crm_element_value(set2, "sequential"); enum pe_ordering flags = pe_order_none; if (action_1 == NULL) { action_1 = RSC_START; }; if (action_2 == NULL) { action_2 = RSC_START; }; if (invert == FALSE) { flags = get_flags(id, kind, action_1, action_2, FALSE); } else { action_1 = invert_action(action_1); action_2 = invert_action(action_2); flags = get_flags(id, kind, action_2, action_1, TRUE); } if(crm_is_true(sequential_1)) { if(invert == FALSE) { /* get the last one */ const char *rid = NULL; xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rid = ID(xml_rsc); ); rsc_1 = pe_find_resource(data_set->resources, rid); } else { /* get the first one */ xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); break; ); } } if(crm_is_true(sequential_2)) { if(invert == FALSE) { /* get the first one */ xml_child_iter_filter( set2, xml_rsc, XML_TAG_RESOURCE_REF, rsc_2 = pe_find_resource(data_set->resources, ID(xml_rsc)); break; ); } else { /* get the last one */ const char *rid = NULL; xml_child_iter_filter( set2, xml_rsc, XML_TAG_RESOURCE_REF, rid = ID(xml_rsc); ); rsc_2 = pe_find_resource(data_set->resources, rid); } } if(rsc_1 != NULL && rsc_2 != NULL) { new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set); } else if(rsc_1 != NULL) { xml_child_iter_filter( set2, xml_rsc, XML_TAG_RESOURCE_REF, rsc_2 = pe_find_resource(data_set->resources, ID(xml_rsc)); new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set); ); } else if(rsc_2 != NULL) { xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set); ); } else { xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); xml_child_iter_filter( set2, xml_rsc_2, XML_TAG_RESOURCE_REF, rsc_2 = pe_find_resource(data_set->resources, ID(xml_rsc_2)); new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set); ); ); } return TRUE; } /* static char *null_or_opkey(resource_t *rsc, const char *action) { if(rsc == NULL) { return NULL; } return generate_op_key(rsc->id, action, 0); } */ gboolean unpack_rsc_order(xmlNode *xml_obj, pe_working_set_t *data_set) { gboolean any_sets = FALSE; resource_t *rsc = NULL; /* resource_t *last_rsc = NULL; */ action_t *set_end = NULL; action_t *set_begin = NULL; action_t *set_inv_end = NULL; action_t *set_inv_begin = NULL; xmlNode *last = NULL; /* action_t *last_end = NULL; action_t *last_begin = NULL; action_t *last_inv_end = NULL; action_t *last_inv_begin = NULL; */ const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *invert = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL); enum pe_order_kind kind = get_ordering_type(xml_obj); if(invert == NULL) { invert = "true"; } xml_child_iter_filter( xml_obj, set, XML_CONS_TAG_RSC_SET, any_sets = TRUE; set = expand_idref(set, data_set->input); if(unpack_order_set(set, kind, &rsc, &set_begin, &set_end, &set_inv_begin, &set_inv_end, invert, data_set) == FALSE) { return FALSE; /* Expand orders in order_rsc_sets() instead of via pseudo actions. */ /* } else if(last) { const char *set_action = crm_element_value(set, "action"); const char *last_action = crm_element_value(last, "action"); enum pe_ordering flags = get_flags(id, kind, last_action, set_action, FALSE); if(!set_action) { set_action = RSC_START; } if(!last_action) { last_action = RSC_START; } if(rsc == NULL && last_rsc == NULL) { order_actions(last_end, set_begin, flags); } else { custom_action_order( last_rsc, null_or_opkey(last_rsc, last_action), last_end, rsc, null_or_opkey(rsc, set_action), set_begin, flags, data_set); } if(crm_is_true(invert)) { set_action = invert_action(set_action); last_action = invert_action(last_action); flags = get_flags(id, kind, last_action, set_action, TRUE); if(rsc == NULL && last_rsc == NULL) { order_actions(last_inv_begin, set_inv_end, flags); } else { custom_action_order( last_rsc, null_or_opkey(last_rsc, last_action), last_inv_begin, rsc, null_or_opkey(rsc, set_action), set_inv_end, flags, data_set); } } */ } else if(/* never called -- Now call it for supporting clones in resource sets */last) { if(order_rsc_sets(id, last, set, kind, data_set, FALSE) == FALSE) { return FALSE; } if(crm_is_true(invert) && order_rsc_sets(id, set, last, kind, data_set, TRUE) == FALSE) { return FALSE; } } last = set; /* last_rsc = rsc; last_end = set_end; last_begin = set_begin; last_inv_end = set_inv_end; last_inv_begin = set_inv_begin; */ ); if(any_sets == FALSE) { return unpack_simple_rsc_order(xml_obj, data_set); } return TRUE; } static gboolean unpack_colocation_set(xmlNode *set, int score, pe_working_set_t *data_set) { resource_t *with = NULL; resource_t *resource = NULL; const char *set_id = ID(set); const char *role = crm_element_value(set, "role"); const char *sequential = crm_element_value(set, "sequential"); int local_score = score; const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE); if(score_s) { local_score = char2score(score_s); } if(sequential != NULL && crm_is_true(sequential) == FALSE) { return TRUE; } else if(local_score >= 0) { xml_child_iter_filter( set, xml_rsc, XML_TAG_RESOURCE_REF, resource = pe_find_resource(data_set->resources, ID(xml_rsc)); if(with != NULL) { crm_debug_2("Colocating %s with %s", resource->id, with->id); rsc_colocation_new(set_id, NULL, local_score, resource, with, role, role, data_set); } with = resource; ); } else { /* Anti-colocating with every prior resource is * the only way to ensure the intuitive result * (ie. that no-one in the set can run with anyone * else in the set) */ xml_child_iter_filter( set, xml_rsc, XML_TAG_RESOURCE_REF, resource = pe_find_resource(data_set->resources, ID(xml_rsc)); xml_child_iter_filter( set, xml_rsc_with, XML_TAG_RESOURCE_REF, if(safe_str_eq(resource->id, ID(xml_rsc_with))) { break; } with = pe_find_resource(data_set->resources, ID(xml_rsc_with)); crm_debug_2("Anti-Colocating %s with %s", resource->id, with->id); rsc_colocation_new(set_id, NULL, local_score, resource, with, role, role, data_set); ); ); } return TRUE; } static gboolean colocate_rsc_sets( const char *id, xmlNode *set1, xmlNode *set2, int score, pe_working_set_t *data_set) { resource_t *rsc_1 = NULL; resource_t *rsc_2 = NULL; const char *role_1 = crm_element_value(set1, "role"); const char *role_2 = crm_element_value(set2, "role"); const char *sequential_1 = crm_element_value(set1, "sequential"); const char *sequential_2 = crm_element_value(set2, "sequential"); if(crm_is_true(sequential_1)) { /* get the first one */ xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); break; ); } if(crm_is_true(sequential_2)) { /* get the last one */ const char *rid = NULL; xml_child_iter_filter( set2, xml_rsc, XML_TAG_RESOURCE_REF, rid = ID(xml_rsc); ); rsc_2 = pe_find_resource(data_set->resources, rid); } if(rsc_1 != NULL && rsc_2 != NULL) { rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set); } else if(rsc_1 != NULL) { xml_child_iter_filter( set2, xml_rsc, XML_TAG_RESOURCE_REF, rsc_2 = pe_find_resource(data_set->resources, ID(xml_rsc)); rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set); ); } else if(rsc_2 != NULL) { xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set); ); } else { xml_child_iter_filter( set1, xml_rsc, XML_TAG_RESOURCE_REF, rsc_1 = pe_find_resource(data_set->resources, ID(xml_rsc)); xml_child_iter_filter( set2, xml_rsc_2, XML_TAG_RESOURCE_REF, rsc_2 = pe_find_resource(data_set->resources, ID(xml_rsc_2)); rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set); ); ); } return TRUE; } static gboolean unpack_simple_colocation(xmlNode *xml_obj, pe_working_set_t *data_set) { int score_i = 0; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *id_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE); const char *id_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET); const char *state_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE); const char *state_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE); const char *instance_lh = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_INSTANCE); const char *instance_rh = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_INSTANCE); const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR); const char *symmetrical = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); if(rsc_lh == NULL) { crm_config_err("Invalid constraint '%s': No resource named '%s'", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_config_err("Invalid constraint '%s': No resource named '%s'", id, id_rh); return FALSE; } else if(instance_lh && rsc_lh->variant < pe_clone) { crm_config_err("Invalid constraint '%s': Resource '%s' is not a clone but instance %s was requested", id, id_lh, instance_lh); return FALSE; } else if(instance_rh && rsc_rh->variant < pe_clone) { crm_config_err("Invalid constraint '%s': Resource '%s' is not a clone but instance %s was requested", id, id_rh, instance_rh); return FALSE; } if(instance_lh) { rsc_lh = find_clone_instance(rsc_lh, instance_lh, data_set); if(rsc_lh == NULL) { crm_config_warn("Invalid constraint '%s': No instance '%s' of '%s'", id, instance_lh, id_lh); return FALSE; } } if(instance_rh) { rsc_rh = find_clone_instance(rsc_rh, instance_rh, data_set); if(rsc_rh == NULL) { crm_config_warn("Invalid constraint '%s': No instance '%s' of '%s'", id, instance_rh, id_rh); return FALSE; } } if(crm_is_true(symmetrical)) { crm_config_warn("The %s colocation constraint attribute has been removed." " It didn't do what you think it did anyway.", XML_CONS_ATTR_SYMMETRICAL); } if(score) { score_i = char2score(score); } rsc_colocation_new(id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh, data_set); return TRUE; } gboolean unpack_rsc_colocation(xmlNode *xml_obj, pe_working_set_t *data_set) { int score_i = 0; xmlNode *last = NULL; gboolean any_sets = FALSE; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); if(score) { score_i = char2score(score); } xml_child_iter_filter( xml_obj, set, XML_CONS_TAG_RSC_SET, any_sets = TRUE; set = expand_idref(set, data_set->input); if(unpack_colocation_set(set, score_i, data_set) == FALSE) { return FALSE; } else if(last && colocate_rsc_sets(id, last, set, score_i, data_set) == FALSE) { return FALSE; } last = set; ); if(any_sets == FALSE) { return unpack_simple_colocation(xml_obj, data_set); } return TRUE; } gboolean is_active(rsc_to_node_t *cons) { return TRUE; } diff --git a/pengine/graph.c b/pengine/graph.c index da1b53d110..f4c612904e 100644 --- a/pengine/graph.c +++ b/pengine/graph.c @@ -1,643 +1,645 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include gboolean update_action(action_t *action); gboolean rsc_update_action(action_t *first, action_t *then, enum pe_ordering type); static action_t *rsc_expand_action(action_t *action) { action_t *result = action; if(action->rsc && action->rsc->variant >= pe_group) { /* Expand 'first' */ char *uuid = NULL; gboolean notify = FALSE; if(action->rsc->parent == NULL) { /* Only outter-most resources have notification actions */ notify = is_set(action->rsc->flags, pe_rsc_notify); } uuid = convert_non_atomic_uuid(action->uuid, action->rsc, notify, FALSE); crm_trace("Converted %s to %s %d", action->uuid, uuid, is_set(action->rsc->flags, pe_rsc_notify)); result = find_first_action(action->rsc->actions, uuid, NULL, NULL); CRM_CHECK(result != NULL, crm_err("Couldn't expand %s", action->uuid); result = action); crm_free(uuid); } return result; } static enum pe_graph_flags graph_update_action(action_t *first, action_t *then, node_t *node, enum pe_action_flags flags, enum pe_ordering type) { enum pe_graph_flags changed = pe_graph_none; gboolean processed = FALSE; /* TODO: Do as many of these in parallel as possible */ if(type & pe_order_implies_then) { crm_trace("implies right"); processed = TRUE; if(then->rsc) { changed |= then->rsc->cmds->update_actions( first, then, node, flags & pe_action_optional, pe_action_optional, pe_order_implies_then); } else if(is_set(flags, pe_action_optional) == FALSE) { if(update_action_flags(then, pe_action_optional|pe_action_clear)) { changed |= pe_graph_updated_then; } } } if(type & pe_order_restart) { enum pe_action_flags restart = (pe_action_optional|pe_action_runnable); crm_trace("restart"); processed = TRUE; changed |= then->rsc->cmds->update_actions( first, then, node, flags & restart, restart, pe_order_restart); } if(type & pe_order_implies_first) { crm_trace("implies left"); processed = TRUE; if(first->rsc) { changed |= first->rsc->cmds->update_actions( first, then, node, flags & pe_action_optional, pe_action_optional, pe_order_implies_first); } else if(is_set(flags, pe_action_optional) == FALSE) { if(update_action_flags(first, pe_action_runnable|pe_action_clear)) { changed |= pe_graph_updated_first; } } } if(type & pe_order_runnable_left) { crm_trace("runnable"); processed = TRUE; if(then->rsc) { changed |= then->rsc->cmds->update_actions( first, then, node, flags & pe_action_runnable, pe_action_runnable, pe_order_runnable_left); } else if(is_set(flags, pe_action_runnable) == FALSE) { if(update_action_flags(then, pe_action_runnable|pe_action_clear)) { changed |= pe_graph_updated_then; } } } if(type & pe_order_optional) { crm_trace("optional"); processed = TRUE; if(then->rsc) { changed |= then->rsc->cmds->update_actions( first, then, node, flags & pe_action_runnable, pe_action_runnable, pe_order_optional); } } if((type & pe_order_implies_then_printed) && (flags & pe_action_optional) == 0) { processed = TRUE; crm_trace("%s implies %s printed", first->uuid, then->uuid); update_action_flags(then, pe_action_print_always); /* dont care about changed */ } if((type & pe_order_implies_first_printed) && (flags & pe_action_optional) == 0) { processed = TRUE; crm_trace("%s implies %s printed", then->uuid, first->uuid); update_action_flags(first, pe_action_print_always); /* dont care about changed */ } if(processed == FALSE) { crm_trace("Constraint 0x%.6x not applicable", type); } return changed; } gboolean update_action(action_t *then) { + GListPtr lpc = NULL; enum pe_graph_flags changed = pe_graph_none; crm_trace("Processing %s (%s %s %s)", then->uuid, is_set(then->flags, pe_action_optional)?"optional":"required", is_set(then->flags, pe_action_runnable)?"runnable":"unrunnable", is_set(then->flags, pe_action_pseudo)?"pseudo":then->node?then->node->details->uname:""); - slist_iter( - other, action_wrapper_t, then->actions_before, lpc, - + for(lpc = then->actions_before; lpc != NULL; lpc = lpc->next) { + action_wrapper_t *other = (action_wrapper_t*)lpc->data; action_t *first = other->action; enum pe_action_flags first_flags = get_action_flags(first, then->node); enum pe_action_flags then_flags = get_action_flags(then, first->node); crm_trace("Checking %s (%s %s %s) against %s (%s %s %s) 0x%.6x", then->uuid, is_set(then_flags, pe_action_optional)?"optional":"required", is_set(then_flags, pe_action_runnable)?"runnable":"unrunnable", is_set(then_flags, pe_action_pseudo)?"pseudo":then->node?then->node->details->uname:"", first->uuid, is_set(first_flags, pe_action_optional)?"optional":"required", is_set(first_flags, pe_action_runnable)?"runnable":"unrunnable", is_set(first_flags, pe_action_pseudo)?"pseudo":first->node?first->node->details->uname:"", other->type); clear_bit_inplace(changed, pe_graph_updated_first); if(first->rsc != then->rsc && (then->rsc == NULL || first->rsc != then->rsc->parent)) { first = rsc_expand_action(first); } if(first == other->action) { clear_bit_inplace(first_flags, pe_action_pseudo); changed |= graph_update_action(first, then, then->node, first_flags, other->type); } else if(order_actions(first, then, other->type)) { crm_trace("Ordering %s afer %s instead of %s", then->uuid, first->uuid, other->action->uuid); /* Start again to get the new actions_before list */ changed |= (pe_graph_updated_then|pe_graph_disable); } if(changed & pe_graph_disable) { crm_trace("Disabled constraint %s -> %s", then->uuid, first->uuid); clear_bit_inplace(changed, pe_graph_disable); other->type = pe_order_none; } if(changed & pe_graph_updated_first) { + GListPtr lpc2 = NULL; crm_trace("Updated %s (first %s %s %s), processing dependants ", first->uuid, is_set(first->flags, pe_action_optional)?"optional":"required", is_set(first->flags, pe_action_runnable)?"runnable":"unrunnable", is_set(first->flags, pe_action_pseudo)?"pseudo":first->node?first->node->details->uname:""); - slist_iter( - other, action_wrapper_t, first->actions_after, lpc, + for(lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) { + action_wrapper_t *other = (action_wrapper_t*)lpc2->data; update_action(other->action); - ); + } update_action(first); } - - ); + } if(changed & pe_graph_updated_then) { crm_trace("Updated %s (then %s %s %s), processing dependants ", then->uuid, is_set(then->flags, pe_action_optional)?"optional":"required", is_set(then->flags, pe_action_runnable)?"runnable":"unrunnable", is_set(then->flags, pe_action_pseudo)?"pseudo":then->node?then->node->details->uname:""); update_action(then); - slist_iter( - other, action_wrapper_t, then->actions_after, lpc, + for(lpc = then->actions_after; lpc != NULL; lpc = lpc->next) { + action_wrapper_t *other = (action_wrapper_t*)lpc->data; update_action(other->action); - ); + } } return FALSE; } gboolean shutdown_constraints( - node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) + node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { - /* add the stop to the before lists so it counts as a pre-req - * for the shutdown - */ - slist_iter( - rsc, resource_t, node->details->running_rsc, lpc, - - if(is_not_set(rsc->flags, pe_rsc_managed)) { - continue; - } + /* add the stop to the before lists so it counts as a pre-req + * for the shutdown + */ + GListPtr lpc = NULL; + for(lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) { + resource_t *rsc = (resource_t*)lpc->data; + + if(is_not_set(rsc->flags, pe_rsc_managed)) { + continue; + } - custom_action_order( - rsc, stop_key(rsc), NULL, - NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, - pe_order_optional, data_set); - - ); + custom_action_order( + rsc, stop_key(rsc), NULL, + NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, + pe_order_optional, data_set); + } - return TRUE; + return TRUE; } gboolean stonith_constraints( - node_t *node, action_t *stonith_op, pe_working_set_t *data_set) + node_t *node, action_t *stonith_op, pe_working_set_t *data_set) { - CRM_CHECK(stonith_op != NULL, return FALSE); + CRM_CHECK(stonith_op != NULL, return FALSE); - /* - * Make sure the stonith OP occurs before we start any shared resources - */ - if(stonith_op != NULL) { - slist_iter( - rsc, resource_t, data_set->resources, lpc, - rsc_stonith_ordering(rsc, stonith_op, data_set); - ); + /* + * Make sure the stonith OP occurs before we start any shared resources + */ + if(stonith_op != NULL) { + GListPtr lpc = NULL; + for(lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + resource_t *rsc = (resource_t*)lpc->data; + rsc_stonith_ordering(rsc, stonith_op, data_set); } + } - /* add the stonith OP as a stop pre-req and the mark the stop - * as a pseudo op - since its now redundant - */ + /* add the stonith OP as a stop pre-req and the mark the stop + * as a pseudo op - since its now redundant + */ - return TRUE; + return TRUE; } xmlNode * action2xml(action_t *action, gboolean as_input) { - gboolean needs_node_info = TRUE; - xmlNode * action_xml = NULL; - xmlNode * args_xml = NULL; - char *action_id_s = NULL; + gboolean needs_node_info = TRUE; + xmlNode * action_xml = NULL; + xmlNode * args_xml = NULL; + char *action_id_s = NULL; - if(action == NULL) { - return NULL; - } + if(action == NULL) { + return NULL; + } - crm_debug_4("Dumping action %d as XML", action->id); - if(safe_str_eq(action->task, CRM_OP_FENCE)) { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); + crm_debug_4("Dumping action %d as XML", action->id); + if(safe_str_eq(action->task, CRM_OP_FENCE)) { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* needs_node_info = FALSE; */ - } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); + } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); - } else if(safe_str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT)) { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); + } else if(safe_str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT)) { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); - } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); + } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* } else if(safe_str_eq(action->task, RSC_PROBED)) { */ /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */ - } else if(is_set(action->flags, pe_action_pseudo)) { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); - needs_node_info = FALSE; + } else if(is_set(action->flags, pe_action_pseudo)) { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); + needs_node_info = FALSE; - } else { - action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); - } + } else { + action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); + } - action_id_s = crm_itoa(action->id); - crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); - crm_free(action_id_s); + action_id_s = crm_itoa(action->id); + crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); + crm_free(action_id_s); - crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); - if(action->rsc != NULL && action->rsc->clone_name != NULL) { - char *clone_key = NULL; - const char *interval_s = g_hash_table_lookup(action->meta, "interval"); - int interval = crm_parse_int(interval_s, "0"); - - if(safe_str_eq(action->task, RSC_NOTIFY)) { - const char *n_type = g_hash_table_lookup(action->meta, "notify_type"); - const char *n_task = g_hash_table_lookup(action->meta, "notify_operation"); - CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid)); - CRM_CHECK(n_task != NULL, crm_err("No notify operation value found for %s", action->uuid)); - clone_key = generate_notify_key(action->rsc->clone_name, n_type, n_task); + crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); + if(action->rsc != NULL && action->rsc->clone_name != NULL) { + char *clone_key = NULL; + const char *interval_s = g_hash_table_lookup(action->meta, "interval"); + int interval = crm_parse_int(interval_s, "0"); + + if(safe_str_eq(action->task, RSC_NOTIFY)) { + const char *n_type = g_hash_table_lookup(action->meta, "notify_type"); + const char *n_task = g_hash_table_lookup(action->meta, "notify_operation"); + CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid)); + CRM_CHECK(n_task != NULL, crm_err("No notify operation value found for %s", action->uuid)); + clone_key = generate_notify_key(action->rsc->clone_name, n_type, n_task); - } else { - clone_key = generate_op_key(action->rsc->clone_name, action->task, interval); - } - - CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid)); - crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key); - crm_xml_add(action_xml, "internal_"XML_LRM_ATTR_TASK_KEY, action->uuid); - crm_free(clone_key); - } else { - crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); + clone_key = generate_op_key(action->rsc->clone_name, action->task, interval); } + + CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid)); + crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key); + crm_xml_add(action_xml, "internal_"XML_LRM_ATTR_TASK_KEY, action->uuid); + crm_free(clone_key); + + } else { + crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); + } - if(needs_node_info && action->node != NULL) { - crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, - action->node->details->uname); + if(needs_node_info && action->node != NULL) { + crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, + action->node->details->uname); - crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, - action->node->details->id); - } + crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, + action->node->details->id); + } - if(is_set(action->flags, pe_action_failure_is_fatal) == FALSE) { - add_hash_param(action->meta, - XML_ATTR_TE_ALLOWFAIL, XML_BOOLEAN_TRUE); - } + if(is_set(action->flags, pe_action_failure_is_fatal) == FALSE) { + add_hash_param(action->meta, + XML_ATTR_TE_ALLOWFAIL, XML_BOOLEAN_TRUE); + } - if(as_input) { - return action_xml; - } + if(as_input) { + return action_xml; + } - if(action->rsc) { - if(is_set(action->flags, pe_action_pseudo) == FALSE) { - int lpc = 0; + if(action->rsc) { + if(is_set(action->flags, pe_action_pseudo) == FALSE) { + int lpc = 0; - xmlNode *rsc_xml = create_xml_node( - action_xml, crm_element_name(action->rsc->xml)); - - const char *attr_list[] = { - XML_AGENT_ATTR_CLASS, - XML_AGENT_ATTR_PROVIDER, - XML_ATTR_TYPE - }; - - if(action->rsc->clone_name != NULL) { - crm_debug("Using clone name %s for %s", action->rsc->clone_name, action->rsc->id); - crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name); - crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id); - - } else { - crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id); - crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->long_name); - } + xmlNode *rsc_xml = create_xml_node( + action_xml, crm_element_name(action->rsc->xml)); + + const char *attr_list[] = { + XML_AGENT_ATTR_CLASS, + XML_AGENT_ATTR_PROVIDER, + XML_ATTR_TYPE + }; + + if(action->rsc->clone_name != NULL) { + crm_debug("Using clone name %s for %s", action->rsc->clone_name, action->rsc->id); + crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name); + crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id); + + } else { + crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id); + crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->long_name); + } - for(lpc = 0; lpc < DIMOF(attr_list); lpc++) { - crm_xml_add(rsc_xml, attr_list[lpc], - g_hash_table_lookup(action->rsc->meta, attr_list[lpc])); - } + for(lpc = 0; lpc < DIMOF(attr_list); lpc++) { + crm_xml_add(rsc_xml, attr_list[lpc], + g_hash_table_lookup(action->rsc->meta, attr_list[lpc])); } } + } - args_xml = create_xml_node(NULL, XML_TAG_ATTRS); - crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); + args_xml = create_xml_node(NULL, XML_TAG_ATTRS); + crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); - g_hash_table_foreach(action->extra, hash2field, args_xml); - if(action->rsc != NULL) { - g_hash_table_foreach(action->rsc->parameters, hash2smartfield, args_xml); - } + g_hash_table_foreach(action->extra, hash2field, args_xml); + if(action->rsc != NULL) { + g_hash_table_foreach(action->rsc->parameters, hash2smartfield, args_xml); + } - g_hash_table_foreach(action->meta, hash2metafield, args_xml); - if(action->rsc != NULL) { - resource_t *parent = action->rsc; - while(parent != NULL) { - parent->cmds->append_meta(parent, args_xml); - parent = parent->parent; - } + g_hash_table_foreach(action->meta, hash2metafield, args_xml); + if(action->rsc != NULL) { + resource_t *parent = action->rsc; + while(parent != NULL) { + parent->cmds->append_meta(parent, args_xml); + parent = parent->parent; + } - } else if(safe_str_eq(action->task, CRM_OP_FENCE)) { - g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml); - } + } else if(safe_str_eq(action->task, CRM_OP_FENCE)) { + g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml); + } - sorted_xml(args_xml, action_xml, FALSE); - crm_log_xml_debug_4(action_xml, "dumped action"); - free_xml(args_xml); + sorted_xml(args_xml, action_xml, FALSE); + crm_log_xml_debug_4(action_xml, "dumped action"); + free_xml(args_xml); - return action_xml; + return action_xml; } static gboolean should_dump_action(action_t *action) { - int log_filter = LOG_DEBUG_5; + int log_filter = LOG_DEBUG_5; - CRM_CHECK(action != NULL, return FALSE); + CRM_CHECK(action != NULL, return FALSE); - if(is_set(action->flags, pe_action_dumped)) { - do_crm_log_unlikely(log_filter, "action %d (%s) was already dumped", + if(is_set(action->flags, pe_action_dumped)) { + do_crm_log_unlikely(log_filter, "action %d (%s) was already dumped", action->id, action->uuid); - return FALSE; + return FALSE; - } else if(is_set(action->flags, pe_action_runnable) == FALSE) { - do_crm_log_unlikely(log_filter, "action %d (%s) was not runnable", + } else if(is_set(action->flags, pe_action_runnable) == FALSE) { + do_crm_log_unlikely(log_filter, "action %d (%s) was not runnable", action->id, action->uuid); - return FALSE; + return FALSE; - } else if(is_set(action->flags, pe_action_optional) && is_set(action->flags, pe_action_print_always) == FALSE) { - do_crm_log_unlikely(log_filter, "action %d (%s) was optional", + } else if(is_set(action->flags, pe_action_optional) && is_set(action->flags, pe_action_print_always) == FALSE) { + do_crm_log_unlikely(log_filter, "action %d (%s) was optional", action->id, action->uuid); - return FALSE; - - } else if(action->rsc != NULL - && is_not_set(action->rsc->flags, pe_rsc_managed)) { - const char * interval = NULL; - interval = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); - - /* make sure probes and recurring monitors go through */ - if(safe_str_neq(action->task, RSC_STATUS) && interval == NULL) { - do_crm_log_unlikely(log_filter, "action %d (%s) was for an unmanaged resource (%s)", - action->id, action->uuid, action->rsc->id); - return FALSE; - } + return FALSE; + + } else if(action->rsc != NULL + && is_not_set(action->rsc->flags, pe_rsc_managed)) { + const char * interval = NULL; + interval = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); + + /* make sure probes and recurring monitors go through */ + if(safe_str_neq(action->task, RSC_STATUS) && interval == NULL) { + do_crm_log_unlikely(log_filter, "action %d (%s) was for an unmanaged resource (%s)", + action->id, action->uuid, action->rsc->id); + return FALSE; } + } - if(is_set(action->flags, pe_action_pseudo) - || safe_str_eq(action->task, CRM_OP_FENCE) - || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { - /* skip the next checks */ - return TRUE; - } - - if(action->node == NULL) { - pe_err("action %d (%s) was not allocated", - action->id, action->uuid); - log_action(LOG_DEBUG, "Unallocated action", action, FALSE); - return FALSE; + if(is_set(action->flags, pe_action_pseudo) + || safe_str_eq(action->task, CRM_OP_FENCE) + || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { + /* skip the next checks */ + return TRUE; + } + + if(action->node == NULL) { + pe_err("action %d (%s) was not allocated", + action->id, action->uuid); + log_action(LOG_DEBUG, "Unallocated action", action, FALSE); + return FALSE; - } else if(action->node->details->online == FALSE) { - pe_err("action %d was (%s) scheduled for offline node", - action->id, action->uuid); - log_action(LOG_DEBUG, "Action for offline node", action, FALSE); - return FALSE; + } else if(action->node->details->online == FALSE) { + pe_err("action %d was (%s) scheduled for offline node", + action->id, action->uuid); + log_action(LOG_DEBUG, "Action for offline node", action, FALSE); + return FALSE; #if 0 - /* but this would also affect resources that can be safely - * migrated before a fencing op - */ - } else if(action->node->details->unclean == FALSE) { - pe_err("action %d was (%s) scheduled for unclean node", - action->id, action->uuid); - log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); - return FALSE; + /* but this would also affect resources that can be safely + * migrated before a fencing op + */ + } else if(action->node->details->unclean == FALSE) { + pe_err("action %d was (%s) scheduled for unclean node", + action->id, action->uuid); + log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); + return FALSE; #endif - } - return TRUE; + } + return TRUE; } /* lowest to highest */ static gint sort_action_id(gconstpointer a, gconstpointer b) { - const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; - const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; + const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; + const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } + if(a == NULL) { return 1; } + if(b == NULL) { return -1; } - if(action_wrapper1->action->id > action_wrapper2->action->id) { - return -1; - } + if(action_wrapper1->action->id > action_wrapper2->action->id) { + return -1; + } - if(action_wrapper1->action->id < action_wrapper2->action->id) { - return 1; - } - return 0; + if(action_wrapper1->action->id < action_wrapper2->action->id) { + return 1; + } + return 0; } static gboolean should_dump_input(int last_action, action_t *action, action_wrapper_t *wrapper) { int type = wrapper->type; int log_dump = LOG_DEBUG_3; int log_filter = LOG_DEBUG_3; type &= ~pe_order_implies_first_printed; type &= ~pe_order_implies_then_printed; type &= ~pe_order_optional; wrapper->state = pe_link_not_dumped; if(last_action == wrapper->action->id) { do_crm_log_unlikely(log_filter, "Input (%d) %s duplicated for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); + wrapper->action->id, wrapper->action->uuid, action->uuid); wrapper->state = pe_link_dup; return FALSE; } else if(wrapper->type == pe_order_none) { do_crm_log_unlikely(log_filter, "Input (%d) %s suppressed for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); + wrapper->action->id, wrapper->action->uuid, action->uuid); return FALSE; } else if(is_set(wrapper->action->flags, pe_action_runnable) == FALSE && type == pe_order_none && safe_str_neq(wrapper->action->uuid, CRM_OP_PROBED)) { do_crm_log_unlikely(log_filter, "Input (%d) %s optional (ordering) for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); + wrapper->action->id, wrapper->action->uuid, action->uuid); return FALSE; } else if(is_set(action->flags, pe_action_pseudo) && (wrapper->type & pe_order_stonith_stop)) { do_crm_log_unlikely(log_filter, "Input (%d) %s suppressed for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); + wrapper->action->id, wrapper->action->uuid, action->uuid); return FALSE; } else if(wrapper->action->rsc && wrapper->action->rsc != action->rsc && is_set(wrapper->action->rsc->flags, pe_rsc_failed) && is_not_set(wrapper->action->rsc->flags, pe_rsc_managed) && strstr(wrapper->action->uuid, "_stop_0") && action->rsc->variant >= pe_clone) { crm_warn("Ignoring requirement that %s comeplete before %s:" " unmanaged failed resources cannot prevent clone shutdown", wrapper->action->uuid, action->uuid); return FALSE; } else if(is_set(wrapper->action->flags, pe_action_dumped) || should_dump_action(wrapper->action)) { do_crm_log_unlikely(log_dump, "Input (%d) %s should be dumped for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); + wrapper->action->id, wrapper->action->uuid, action->uuid); goto dump; #if 0 } else if(is_set(wrapper->action->flags, pe_action_runnable) && is_set(wrapper->action->flags, pe_action_pseudo) && wrapper->action->rsc->variant != pe_native) { do_crm_log(LOG_CRIT, "Input (%d) %s should be dumped for %s", wrapper->action->id, wrapper->action->uuid, action->uuid); goto dump; #endif } else if(is_set(wrapper->action->flags, pe_action_optional) == TRUE && is_set(wrapper->action->flags, pe_action_print_always) == FALSE) { do_crm_log_unlikely(log_filter, "Input (%d) %s optional for %s", - wrapper->action->id, wrapper->action->uuid, action->uuid); - do_crm_log_unlikely(log_filter, "Input (%d) %s n=%p p=%d r=%d o=%d a=%d f=0x%.6x", - wrapper->action->id, - wrapper->action->uuid, - wrapper->action->node, - is_set(wrapper->action->flags, pe_action_pseudo), - is_set(wrapper->action->flags, pe_action_runnable), - is_set(wrapper->action->flags, pe_action_optional), - is_set(wrapper->action->flags, pe_action_print_always), - wrapper->type); + wrapper->action->id, wrapper->action->uuid, action->uuid); + do_crm_log_unlikely(log_filter, "Input (%d) %s n=%p p=%d r=%d o=%d a=%d f=0x%.6x", + wrapper->action->id, + wrapper->action->uuid, + wrapper->action->node, + is_set(wrapper->action->flags, pe_action_pseudo), + is_set(wrapper->action->flags, pe_action_runnable), + is_set(wrapper->action->flags, pe_action_optional), + is_set(wrapper->action->flags, pe_action_print_always), + wrapper->type); return FALSE; } dump: do_crm_log_unlikely(log_dump, "Input (%d) %s n=%p p=%d r=%d o=%d a=%d f=0x%.6x dumped for %s", wrapper->action->id, wrapper->action->uuid, wrapper->action->node, is_set(wrapper->action->flags, pe_action_pseudo), is_set(wrapper->action->flags, pe_action_runnable), is_set(wrapper->action->flags, pe_action_optional), is_set(wrapper->action->flags, pe_action_print_always), wrapper->type, action->uuid); return TRUE; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { - int last_action = -1; - int synapse_priority = 0; - xmlNode * syn = NULL; - xmlNode * set = NULL; - xmlNode * in = NULL; - xmlNode * input = NULL; - xmlNode * xml_action = NULL; - - if(should_dump_action(action) == FALSE) { - return; - } + GListPtr lpc = NULL; + int last_action = -1; + int synapse_priority = 0; + xmlNode * syn = NULL; + xmlNode * set = NULL; + xmlNode * in = NULL; + xmlNode * input = NULL; + xmlNode * xml_action = NULL; + + if(should_dump_action(action) == FALSE) { + return; + } - set_bit_inplace(action->flags, pe_action_dumped); + set_bit_inplace(action->flags, pe_action_dumped); - syn = create_xml_node(data_set->graph, "synapse"); - set = create_xml_node(syn, "action_set"); - in = create_xml_node(syn, "inputs"); + syn = create_xml_node(data_set->graph, "synapse"); + set = create_xml_node(syn, "action_set"); + in = create_xml_node(syn, "inputs"); - crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); - data_set->num_synapse++; + crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); + data_set->num_synapse++; - if(action->rsc != NULL) { - synapse_priority = action->rsc->priority; - } - if(action->priority > synapse_priority) { - synapse_priority = action->priority; - } - if(synapse_priority > 0) { - crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); - } + if(action->rsc != NULL) { + synapse_priority = action->rsc->priority; + } + if(action->priority > synapse_priority) { + synapse_priority = action->priority; + } + if(synapse_priority > 0) { + crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); + } - xml_action = action2xml(action, FALSE); - add_node_nocopy(set, crm_element_name(xml_action), xml_action); + xml_action = action2xml(action, FALSE); + add_node_nocopy(set, crm_element_name(xml_action), xml_action); - action->actions_before = g_list_sort( - action->actions_before, sort_action_id); + action->actions_before = g_list_sort( + action->actions_before, sort_action_id); - slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, - - if(should_dump_input(last_action, action, wrapper) == FALSE) { - continue; - } + for(lpc = action->actions_before; lpc != NULL; lpc = lpc->next) { + action_wrapper_t *wrapper = (action_wrapper_t*)lpc->data; + if(should_dump_input(last_action, action, wrapper) == FALSE) { + continue; + } - wrapper->state = pe_link_dumped; - CRM_CHECK(last_action < wrapper->action->id, ;); - last_action = wrapper->action->id; - input = create_xml_node(in, "trigger"); + wrapper->state = pe_link_dumped; + CRM_CHECK(last_action < wrapper->action->id, ;); + last_action = wrapper->action->id; + input = create_xml_node(in, "trigger"); - xml_action = action2xml(wrapper->action, TRUE); - add_node_nocopy(input, crm_element_name(xml_action), xml_action); - ); + xml_action = action2xml(wrapper->action, TRUE); + add_node_nocopy(input, crm_element_name(xml_action), xml_action); + } } diff --git a/pengine/group.c b/pengine/group.c index 4dd376f390..0521b55068 100644 --- a/pengine/group.c +++ b/pengine/group.c @@ -1,481 +1,486 @@ /* * 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 #define VARIANT_GROUP 1 #include node_t * group_color(resource_t *rsc, pe_working_set_t *data_set) { - node_t *node = NULL; - node_t *group_node = NULL; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); + node_t *node = NULL; + node_t *group_node = NULL; + GListPtr gIter = rsc->children; + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, rsc); - if(is_not_set(rsc->flags, pe_rsc_provisional)) { - return rsc->allocated_to; - } - crm_debug_2("Processing %s", rsc->id); - if(is_set(rsc->flags, pe_rsc_allocating)) { - crm_debug("Dependency loop detected involving %s", rsc->id); - return NULL; - } + if(is_not_set(rsc->flags, pe_rsc_provisional)) { + return rsc->allocated_to; + } + crm_debug_2("Processing %s", rsc->id); + if(is_set(rsc->flags, pe_rsc_allocating)) { + crm_debug("Dependency loop detected involving %s", rsc->id); + return NULL; + } - if(group_data->first_child == NULL) { - /* nothign to allocate */ - clear_bit(rsc->flags, pe_rsc_provisional); - return NULL; - } + if(group_data->first_child == NULL) { + /* nothign to allocate */ + clear_bit(rsc->flags, pe_rsc_provisional); + return NULL; + } - set_bit(rsc->flags, pe_rsc_allocating); - rsc->role = group_data->first_child->role; + set_bit(rsc->flags, pe_rsc_allocating); + rsc->role = group_data->first_child->role; - group_data->first_child->rsc_cons = g_list_concat( - group_data->first_child->rsc_cons, rsc->rsc_cons); - rsc->rsc_cons = NULL; + group_data->first_child->rsc_cons = g_list_concat( + group_data->first_child->rsc_cons, rsc->rsc_cons); + rsc->rsc_cons = NULL; - group_data->first_child->rsc_cons_lhs = g_list_concat( - group_data->first_child->rsc_cons_lhs, rsc->rsc_cons_lhs); - rsc->rsc_cons_lhs = NULL; + group_data->first_child->rsc_cons_lhs = g_list_concat( + group_data->first_child->rsc_cons_lhs, rsc->rsc_cons_lhs); + rsc->rsc_cons_lhs = NULL; - dump_node_scores(show_scores?0:scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); + dump_node_scores(show_scores?0:scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + node = child_rsc->cmds->allocate(child_rsc, data_set); + if(group_node == NULL) { + group_node = node; + } + } - node = child_rsc->cmds->allocate(child_rsc, data_set); - if(group_node == NULL) { - group_node = node; - } - ); + rsc->next_role = group_data->first_child->next_role; + clear_bit(rsc->flags, pe_rsc_allocating); + clear_bit(rsc->flags, pe_rsc_provisional); - rsc->next_role = group_data->first_child->next_role; - clear_bit(rsc->flags, pe_rsc_allocating); - clear_bit(rsc->flags, pe_rsc_provisional); - - if(group_data->colocated) { - return group_node; - } - return NULL; + if(group_data->colocated) { + return group_node; + } + return NULL; } void group_update_pseudo_status(resource_t *parent, resource_t *child); void group_create_actions(resource_t *rsc, pe_working_set_t *data_set) { - action_t *op = NULL; - const char *value = NULL; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); + action_t *op = NULL; + const char *value = NULL; + GListPtr gIter = rsc->children; - crm_debug_2("Creating actions for %s", rsc->id); + crm_debug_2("Creating actions for %s", rsc->id); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - child_rsc->cmds->create_actions(child_rsc, data_set); - group_update_pseudo_status(rsc, child_rsc); - ); - - op = start_action(rsc, NULL, TRUE/* !group_data->child_starting */); - set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); - - op = custom_action(rsc, started_key(rsc), - RSC_STARTED, NULL, - TRUE/* !group_data->child_starting */, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); - - op = stop_action(rsc, NULL, TRUE/* !group_data->child_stopping */); - set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + + child_rsc->cmds->create_actions(child_rsc, data_set); + group_update_pseudo_status(rsc, child_rsc); + } + + op = start_action(rsc, NULL, TRUE/* !group_data->child_starting */); + set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); + + op = custom_action(rsc, started_key(rsc), + RSC_STARTED, NULL, + TRUE/* !group_data->child_starting */, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); + + op = stop_action(rsc, NULL, TRUE/* !group_data->child_stopping */); + set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); - op = custom_action(rsc, stopped_key(rsc), - RSC_STOPPED, NULL, - TRUE/* !group_data->child_stopping */, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); - - value = g_hash_table_lookup(rsc->meta, "stateful"); - if(crm_is_true(value)) { - op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); - op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); - - op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); - op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set); - set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); - } + op = custom_action(rsc, stopped_key(rsc), + RSC_STOPPED, NULL, + TRUE/* !group_data->child_stopping */, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo|pe_action_runnable); + + value = g_hash_table_lookup(rsc->meta, "stateful"); + if(crm_is_true(value)) { + op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); + op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); + + op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); + op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set); + set_bit_inplace(op->flags, pe_action_pseudo); set_bit_inplace(op->flags, pe_action_runnable); + } } void group_update_pseudo_status(resource_t *parent, resource_t *child) { - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, parent); + GListPtr gIter = child->actions; + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, parent); - if(group_data->ordered == FALSE) { - /* If this group is not ordered, then leave the meta-actions as optional */ - return; - } + if(group_data->ordered == FALSE) { + /* If this group is not ordered, then leave the meta-actions as optional */ + return; + } - if(group_data->child_stopping && group_data->child_starting) { - return; + if(group_data->child_stopping && group_data->child_starting) { + return; + } + + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + if(is_set(action->flags, pe_action_optional)) { + continue; } - slist_iter( - action, action_t, child->actions, lpc, - - if(is_set(action->flags, pe_action_optional)) { - continue; - } - if(safe_str_eq(RSC_STOP, action->task) && is_set(action->flags, pe_action_runnable)) { - group_data->child_stopping = TRUE; - crm_debug_3("Based on %s the group is stopping", action->uuid); - - } else if(safe_str_eq(RSC_START, action->task) && is_set(action->flags, pe_action_runnable)) { - group_data->child_starting = TRUE; - crm_debug_3("Based on %s the group is starting", action->uuid); - } - - ); + if(safe_str_eq(RSC_STOP, action->task) && is_set(action->flags, pe_action_runnable)) { + group_data->child_stopping = TRUE; + crm_debug_3("Based on %s the group is stopping", action->uuid); + + } else if(safe_str_eq(RSC_START, action->task) && is_set(action->flags, pe_action_runnable)) { + group_data->child_starting = TRUE; + crm_debug_3("Based on %s the group is starting", action->uuid); + } + } } void group_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { - resource_t *last_rsc = NULL; - resource_t *top = uber_parent(rsc); - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - - new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); - new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); - new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); - - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - int stop = pe_order_none; - int stopped = pe_order_implies_then_printed; - int start = pe_order_implies_then|pe_order_runnable_left; - int started = pe_order_runnable_left|pe_order_implies_then|pe_order_implies_then_printed; + GListPtr gIter = rsc->children; + resource_t *last_rsc = NULL; + resource_t *top = uber_parent(rsc); + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, rsc); + + new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); + new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); + new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + int stop = pe_order_none; + int stopped = pe_order_implies_then_printed; + int start = pe_order_implies_then|pe_order_runnable_left; + int started = pe_order_runnable_left|pe_order_implies_then|pe_order_implies_then_printed; - child_rsc->cmds->internal_constraints(child_rsc, data_set); + child_rsc->cmds->internal_constraints(child_rsc, data_set); - if(last_rsc == NULL) { - if(group_data->ordered) { - stop |= pe_order_optional; - stopped = pe_order_implies_then; - } + if(last_rsc == NULL) { + if(group_data->ordered) { + stop |= pe_order_optional; + stopped = pe_order_implies_then; + } - } else if(group_data->colocated) { - rsc_colocation_new( - "group:internal_colocation", NULL, INFINITY, - child_rsc, last_rsc, NULL, NULL, data_set); - } + } else if(group_data->colocated) { + rsc_colocation_new( + "group:internal_colocation", NULL, INFINITY, + child_rsc, last_rsc, NULL, NULL, data_set); + } - if(top->variant == pe_master) { - new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE, - stop|pe_order_implies_first_printed, data_set); + if(top->variant == pe_master) { + new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE, + stop|pe_order_implies_first_printed, data_set); - new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set); + new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set); - new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set); + new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set); - new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, - pe_order_implies_first_printed, data_set); + new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, + pe_order_implies_first_printed, data_set); - } + } - order_start_start(rsc, child_rsc, pe_order_implies_first_printed); - order_stop_stop(rsc, child_rsc, stop|pe_order_implies_first_printed); + order_start_start(rsc, child_rsc, pe_order_implies_first_printed); + order_stop_stop(rsc, child_rsc, stop|pe_order_implies_first_printed); - new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set); + new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set); - new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set); + new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set); - if(group_data->ordered == FALSE) { - order_start_start(rsc, child_rsc, start|pe_order_implies_first_printed); - if(top->variant == pe_master) { - new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, - start|pe_order_implies_first_printed, data_set); - } - - } else if(last_rsc != NULL) { - child_rsc->restart_type = pe_restart_restart; - - order_start_start(last_rsc, child_rsc, start); - order_stop_stop(child_rsc, last_rsc, pe_order_optional); - - if(top->variant == pe_master) { - new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set); - new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_optional, data_set); - } - - } else { - /* If anyone in the group is starting, then - * pe_order_implies_then will cause _everyone_ in the group - * to be sent a start action - * But this is safe since starting something that is already - * started is required to be "safe" - */ - int flags = pe_order_none; + if(group_data->ordered == FALSE) { + order_start_start(rsc, child_rsc, start|pe_order_implies_first_printed); + if(top->variant == pe_master) { + new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, + start|pe_order_implies_first_printed, data_set); + } + + } else if(last_rsc != NULL) { + child_rsc->restart_type = pe_restart_restart; + + order_start_start(last_rsc, child_rsc, start); + order_stop_stop(child_rsc, last_rsc, pe_order_optional); + + if(top->variant == pe_master) { + new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set); + new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_optional, data_set); + } + + } else { + /* If anyone in the group is starting, then + * pe_order_implies_then will cause _everyone_ in the group + * to be sent a start action + * But this is safe since starting something that is already + * started is required to be "safe" + */ + int flags = pe_order_none; - order_start_start(rsc, child_rsc, flags); - if(top->variant == pe_master) { - new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, flags, data_set); - } + order_start_start(rsc, child_rsc, flags); + if(top->variant == pe_master) { + new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, flags, data_set); + } - } + } - last_rsc = child_rsc; - ); + last_rsc = child_rsc; + } - if(group_data->ordered && last_rsc != NULL) { - int stop_stop_flags = pe_order_implies_then; - int stop_stopped_flags = pe_order_optional; + if(group_data->ordered && last_rsc != NULL) { + int stop_stop_flags = pe_order_implies_then; + int stop_stopped_flags = pe_order_optional; - order_stop_stop(rsc, last_rsc, stop_stop_flags); - new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set); + order_stop_stop(rsc, last_rsc, stop_stop_flags); + new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set); - if(top->variant == pe_master) { - new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set); - new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set); - } + if(top->variant == pe_master) { + new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set); + new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set); } + } } void group_rsc_colocation_lh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - group_variant_data_t *group_data = NULL; + GListPtr gIter = rsc_lh->children; + group_variant_data_t *group_data = NULL; - if(rsc_lh == NULL) { - pe_err("rsc_lh was NULL for %s", constraint->id); - return; + if(rsc_lh == NULL) { + pe_err("rsc_lh was NULL for %s", constraint->id); + return; - } else if(rsc_rh == NULL) { - pe_err("rsc_rh was NULL for %s", constraint->id); - return; - } + } else if(rsc_rh == NULL) { + pe_err("rsc_rh was NULL for %s", constraint->id); + return; + } - crm_debug_4("Processing constraints from %s", rsc_lh->id); - - get_group_variant_data(group_data, rsc_lh); - - if(group_data->colocated) { - group_data->first_child->cmds->rsc_colocation_lh( - group_data->first_child, rsc_rh, constraint); - return; - - } else if(constraint->score >= INFINITY) { - crm_config_err("%s: Cannot perform manditory colocation" - " between non-colocated group and %s", - rsc_lh->id, rsc_rh->id); - return; - } - - slist_iter( - child_rsc, resource_t, rsc_lh->children, lpc, - child_rsc->cmds->rsc_colocation_lh( - child_rsc, rsc_rh, constraint); - ); + crm_debug_4("Processing constraints from %s", rsc_lh->id); + + get_group_variant_data(group_data, rsc_lh); + + if(group_data->colocated) { + group_data->first_child->cmds->rsc_colocation_lh( + group_data->first_child, rsc_rh, constraint); + return; + + } else if(constraint->score >= INFINITY) { + crm_config_err("%s: Cannot perform manditory colocation" + " between non-colocated group and %s", + rsc_lh->id, rsc_rh->id); + return; + } + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint); + } } void group_rsc_colocation_rh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc_rh); - CRM_CHECK(rsc_lh->variant == pe_native, return); + GListPtr gIter = rsc_rh->children; + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, rsc_rh); + CRM_CHECK(rsc_lh->variant == pe_native, return); - crm_debug_3("Processing RH of constraint %s", constraint->id); - print_resource(LOG_DEBUG_3, "LHS", rsc_lh, TRUE); + crm_debug_3("Processing RH of constraint %s", constraint->id); + print_resource(LOG_DEBUG_3, "LHS", rsc_lh, TRUE); - if(is_set(rsc_rh->flags, pe_rsc_provisional)) { - return; + if(is_set(rsc_rh->flags, pe_rsc_provisional)) { + return; - } else if(group_data->colocated && group_data->first_child) { - if(constraint->score >= INFINITY) { - /* Ensure RHS is _fully_ up before can start LHS */ - group_data->last_child->cmds->rsc_colocation_rh( - rsc_lh, group_data->last_child, constraint); - } else { - /* A partially active RHS is fine */ - group_data->first_child->cmds->rsc_colocation_rh( - rsc_lh, group_data->first_child, constraint); - } + } else if(group_data->colocated && group_data->first_child) { + if(constraint->score >= INFINITY) { + /* Ensure RHS is _fully_ up before can start LHS */ + group_data->last_child->cmds->rsc_colocation_rh( + rsc_lh, group_data->last_child, constraint); + } else { + /* A partially active RHS is fine */ + group_data->first_child->cmds->rsc_colocation_rh( + rsc_lh, group_data->first_child, constraint); + } - return; - - } else if(constraint->score >= INFINITY) { - crm_config_err("%s: Cannot perform manditory colocation with" - " non-colocated group: %s", rsc_lh->id, rsc_rh->id); - return; - } - - slist_iter( - child_rsc, resource_t, rsc_rh->children, lpc, - child_rsc->cmds->rsc_colocation_rh( - rsc_lh, child_rsc, constraint); - ); + return; + + } else if(constraint->score >= INFINITY) { + crm_config_err("%s: Cannot perform manditory colocation with" + " non-colocated group: %s", rsc_lh->id, rsc_rh->id); + return; + } + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); + } } enum pe_action_flags group_action_flags(action_t *action, node_t *node) { gboolean check_runnable = FALSE; const char *task_s = action->task; + GListPtr gIter = action->rsc->children; enum action_tasks task = text2task(task_s); enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo); switch(task) { case stopped_rsc: case started_rsc: case action_demoted: case action_promoted: task_s = task2text(task-1); check_runnable = TRUE; break; default: break; } - slist_iter( - child, resource_t, action->rsc->children, lpc, - + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; action_t *child_action = find_first_action(child->actions, NULL, task_s, node); + if(child_action) { enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node); if(is_set(flags, pe_action_optional) && is_set(child_flags, pe_action_optional) == FALSE) { crm_trace("%s is manditory because of %s", action->uuid, child_action->uuid); clear_bit_inplace(flags, pe_action_optional); clear_bit_inplace(action->flags, pe_action_optional); } if(check_runnable && is_set(flags, pe_action_runnable) && is_set(child_flags, pe_action_runnable) == FALSE) { crm_trace("%s is not runnable because of %s", action->uuid, child_action->uuid); clear_bit_inplace(flags, pe_action_runnable); clear_bit_inplace(action->flags, pe_action_runnable); } } - ); + } return flags; } enum pe_graph_flags group_update_actions( action_t *first, action_t *then, node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type) { + GListPtr gIter = then->rsc->children; enum pe_graph_flags changed = pe_graph_none; CRM_ASSERT(then->rsc != NULL); changed |= native_update_actions(first, then, node, flags, filter, type); - slist_iter( - child, resource_t, then->rsc->children, lpc, - + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; action_t *child_action = find_first_action(child->actions, NULL, then->task, node); if(child_action) { changed |= child->cmds->update_actions(first, child_action, node, flags, filter, type); } - ); + } return changed; } void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { - GListPtr saved = constraint->node_list_rh; - GListPtr zero = node_list_dup(constraint->node_list_rh, TRUE, FALSE); - gboolean reset_scores = TRUE; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - - crm_debug("Processing rsc_location %s for %s", - constraint->id, rsc->id); - - native_rsc_location(rsc, constraint); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - child_rsc->cmds->rsc_location(child_rsc, constraint); - if(group_data->colocated && reset_scores) { - reset_scores = FALSE; - constraint->node_list_rh = zero; - } - ); - - constraint->node_list_rh = saved; - pe_free_shallow_adv(zero, TRUE); + GListPtr gIter = rsc->children; + GListPtr saved = constraint->node_list_rh; + GListPtr zero = node_list_dup(constraint->node_list_rh, TRUE, FALSE); + gboolean reset_scores = TRUE; + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, rsc); + + crm_debug("Processing rsc_location %s for %s", + constraint->id, rsc->id); + + native_rsc_location(rsc, constraint); + + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + + child_rsc->cmds->rsc_location(child_rsc, constraint); + if(group_data->colocated && reset_scores) { + reset_scores = FALSE; + constraint->node_list_rh = zero; + } + } + + constraint->node_list_rh = saved; + pe_free_shallow_adv(zero, TRUE); } void group_expand(resource_t *rsc, pe_working_set_t *data_set) { - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); + GListPtr gIter = rsc->children; + group_variant_data_t *group_data = NULL; + get_group_variant_data(group_data, rsc); - crm_debug_3("Processing actions from %s", rsc->id); + crm_debug_3("Processing actions from %s", rsc->id); - CRM_CHECK(rsc != NULL, return); - native_expand(rsc, data_set); + CRM_CHECK(rsc != NULL, return); + native_expand(rsc, data_set); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - - child_rsc->cmds->expand(child_rsc, data_set); - ); - + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->expand(child_rsc, data_set); + } } GHashTable * group_merge_weights( resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, int factor, gboolean allow_rollback, gboolean only_positive) { + GListPtr gIter = rsc->rsc_cons_lhs; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(is_set(rsc->flags, pe_rsc_merging)) { crm_info("Breaking dependency loop with %s at %s", rsc->id, rhs); return nodes; } set_bit(rsc->flags, pe_rsc_merging); nodes = group_data->first_child->cmds->merge_weights( group_data->first_child, rhs, nodes, attr, factor, allow_rollback, only_positive); - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, - + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; nodes = rsc_merge_weights( constraint->rsc_lh, rsc->id, nodes, constraint->node_attribute, constraint->score/INFINITY, allow_rollback, only_positive); - ); + } clear_bit(rsc->flags, pe_rsc_merging); return nodes; } void group_append_meta(resource_t *rsc, xmlNode *xml) { } diff --git a/pengine/master.c b/pengine/master.c index 40eec57dfe..7dbb5f710f 100644 --- a/pengine/master.c +++ b/pengine/master.c @@ -1,905 +1,941 @@ /* * 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 #define VARIANT_CLONE 1 #include extern gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set); extern int master_score(resource_t *rsc, node_t *node, int not_set_value); static void child_promoting_constraints( - clone_variant_data_t *clone_data, enum pe_ordering type, - resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) + clone_variant_data_t *clone_data, enum pe_ordering type, + resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) { - if(child == NULL) { - if(clone_data->ordered && last != NULL) { - crm_debug_4("Ordered version (last node)"); - /* last child promote before promoted started */ - new_rsc_order(last, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set); - } - return; + if(child == NULL) { + if(clone_data->ordered && last != NULL) { + crm_debug_4("Ordered version (last node)"); + /* last child promote before promoted started */ + new_rsc_order(last, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set); } + return; + } - /* child promote before global promoted */ - new_rsc_order(child, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set); + /* child promote before global promoted */ + new_rsc_order(child, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set); - /* global promote before child promote */ - new_rsc_order(rsc, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set); + /* global promote before child promote */ + new_rsc_order(rsc, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set); - if(clone_data->ordered) { - crm_debug_4("Ordered version"); - if(last == NULL) { - /* global promote before first child promote */ - last = rsc; + if(clone_data->ordered) { + crm_debug_4("Ordered version"); + if(last == NULL) { + /* global promote before first child promote */ + last = rsc; - } /* else: child/child relative promote */ + } /* else: child/child relative promote */ - order_start_start(last, child, type); - new_rsc_order(last, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set); + order_start_start(last, child, type); + new_rsc_order(last, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set); - } else { - crm_debug_4("Un-ordered version"); - } + } else { + crm_debug_4("Un-ordered version"); + } } static void child_demoting_constraints( - clone_variant_data_t *clone_data, enum pe_ordering type, - resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) + clone_variant_data_t *clone_data, enum pe_ordering type, + resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) { - if(child == NULL) { - if(clone_data->ordered && last != NULL) { - crm_debug_4("Ordered version (last node)"); - /* global demote before first child demote */ - new_rsc_order(rsc, RSC_DEMOTE, last, RSC_DEMOTE, - pe_order_optional, data_set); - } - return; + if(child == NULL) { + if(clone_data->ordered && last != NULL) { + crm_debug_4("Ordered version (last node)"); + /* global demote before first child demote */ + new_rsc_order(rsc, RSC_DEMOTE, last, RSC_DEMOTE, + pe_order_optional, data_set); } + return; + } - /* child demote before global demoted */ - new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, - pe_order_implies_then_printed, data_set); + /* child demote before global demoted */ + new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, + pe_order_implies_then_printed, data_set); - /* global demote before child demote */ - new_rsc_order(rsc, RSC_DEMOTE, child, RSC_DEMOTE, - pe_order_implies_first_printed, data_set); + /* global demote before child demote */ + new_rsc_order(rsc, RSC_DEMOTE, child, RSC_DEMOTE, + pe_order_implies_first_printed, data_set); - if(clone_data->ordered && last != NULL) { - crm_debug_4("Ordered version"); + if(clone_data->ordered && last != NULL) { + crm_debug_4("Ordered version"); - /* child/child relative demote */ - new_rsc_order(child, RSC_DEMOTE, last, RSC_DEMOTE, type, data_set); + /* child/child relative demote */ + new_rsc_order(child, RSC_DEMOTE, last, RSC_DEMOTE, type, data_set); - } else if(clone_data->ordered) { - crm_debug_4("Ordered version (1st node)"); - /* first child stop before global stopped */ - new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, type, data_set); + } else if(clone_data->ordered) { + crm_debug_4("Ordered version (1st node)"); + /* first child stop before global stopped */ + new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, type, data_set); - } else { - crm_debug_4("Un-ordered version"); - } + } else { + crm_debug_4("Un-ordered version"); + } } static void master_update_pseudo_status( - resource_t *rsc, gboolean *demoting, gboolean *promoting) + resource_t *rsc, gboolean *demoting, gboolean *promoting) { - if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - master_update_pseudo_status(child, demoting, promoting) - ); - return; + GListPtr gIter = NULL; + if(rsc->children) { + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + master_update_pseudo_status(child, demoting, promoting); } + return; + } - CRM_ASSERT(demoting != NULL); - CRM_ASSERT(promoting != NULL); - - slist_iter( - action, action_t, rsc->actions, lpc, + CRM_ASSERT(demoting != NULL); + CRM_ASSERT(promoting != NULL); - if(*promoting && *demoting) { - return; - - } else if(is_set(action->flags, pe_action_optional)) { - continue; + gIter = rsc->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + if(*promoting && *demoting) { + return; - } else if(safe_str_eq(RSC_DEMOTE, action->task)) { - *demoting = TRUE; + } else if(is_set(action->flags, pe_action_optional)) { + continue; - } else if(safe_str_eq(RSC_PROMOTE, action->task)) { - *promoting = TRUE; - } - ); + } else if(safe_str_eq(RSC_DEMOTE, action->task)) { + *demoting = TRUE; + } else if(safe_str_eq(RSC_PROMOTE, action->task)) { + *promoting = TRUE; + } + } } -#define apply_master_location(list) \ - slist_iter( \ - cons, rsc_to_node_t, list, lpc2, \ - cons_node = NULL; \ - if(cons->role_filter == RSC_ROLE_MASTER) { \ - crm_debug_2("Applying %s to %s", \ - cons->id, child_rsc->id); \ - cons_node = pe_find_node_id( \ - cons->node_list_rh, chosen->details->id); \ - } \ - if(cons_node != NULL) { \ - int new_priority = merge_weights( \ - child_rsc->priority, cons_node->weight); \ - crm_debug_2("\t%s: %d->%d (%d)", child_rsc->id, \ - child_rsc->priority, new_priority, cons_node->weight); \ - child_rsc->priority = new_priority; \ - } \ - ); +#define apply_master_location(list) do { \ + gIter2 = list; \ + for(; gIter2 != NULL; gIter2 = gIter2->next) { \ + rsc_to_node_t *cons = (rsc_to_node_t*)gIter2->data; \ + \ + cons_node = NULL; \ + if(cons->role_filter == RSC_ROLE_MASTER) { \ + crm_debug_2("Applying %s to %s", \ + cons->id, child_rsc->id); \ + cons_node = pe_find_node_id( \ + cons->node_list_rh, chosen->details->id); \ + } \ + if(cons_node != NULL) { \ + int new_priority = merge_weights( \ + child_rsc->priority, cons_node->weight); \ + crm_debug_2("\t%s: %d->%d (%d)", child_rsc->id, \ + child_rsc->priority, new_priority, cons_node->weight); \ + child_rsc->priority = new_priority; \ + } \ + } \ + } while(0) static node_t * can_be_master(resource_t *rsc) { - node_t *node = NULL; - node_t *local_node = NULL; - resource_t *parent = uber_parent(rsc); - clone_variant_data_t *clone_data = NULL; - int level = LOG_DEBUG_2; + node_t *node = NULL; + node_t *local_node = NULL; + resource_t *parent = uber_parent(rsc); + clone_variant_data_t *clone_data = NULL; + int level = LOG_DEBUG_2; #if 0 - enum rsc_role_e role = RSC_ROLE_UNKNOWN; - role = rsc->fns->state(rsc, FALSE); - crm_info("%s role: %s", rsc->id, role2text(role)); + enum rsc_role_e role = RSC_ROLE_UNKNOWN; + role = rsc->fns->state(rsc, FALSE); + crm_info("%s role: %s", rsc->id, role2text(role)); #endif - if(rsc->children) { - slist_iter( - child, resource_t, rsc->children, lpc, - if(can_be_master(child) == NULL) { - do_crm_log_unlikely(level, "Child %s of %s can't be promoted", child->id, rsc->id); - return NULL; - } - ); - } + if(rsc->children) { + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; - node = rsc->fns->location(rsc, NULL, FALSE); - if(node == NULL) { - do_crm_log_unlikely(level, "%s cannot be master: not allocated", rsc->id); + if(can_be_master(child) == NULL) { + do_crm_log_unlikely(level, "Child %s of %s can't be promoted", child->id, rsc->id); return NULL; + } + } + } + + node = rsc->fns->location(rsc, NULL, FALSE); + if(node == NULL) { + do_crm_log_unlikely(level, "%s cannot be master: not allocated", rsc->id); + return NULL; - } else if(is_not_set(rsc->flags, pe_rsc_managed)) { - if(rsc->fns->state(rsc, TRUE) == RSC_ROLE_MASTER) { - crm_notice("Forcing unmanaged master %s to remain promoted on %s", - rsc->id, node->details->uname); + } else if(is_not_set(rsc->flags, pe_rsc_managed)) { + if(rsc->fns->state(rsc, TRUE) == RSC_ROLE_MASTER) { + crm_notice("Forcing unmanaged master %s to remain promoted on %s", + rsc->id, node->details->uname); - } else { - return NULL; - } + } else { + return NULL; + } - } else if(rsc->priority < 0) { - do_crm_log_unlikely(level, "%s cannot be master: preference: %d", - rsc->id, rsc->priority); - return NULL; + } else if(rsc->priority < 0) { + do_crm_log_unlikely(level, "%s cannot be master: preference: %d", + rsc->id, rsc->priority); + return NULL; - } else if(can_run_resources(node) == FALSE) { - do_crm_log_unlikely(level, "Node cant run any resources: %s", + } else if(can_run_resources(node) == FALSE) { + do_crm_log_unlikely(level, "Node cant run any resources: %s", node->details->uname); - return NULL; - } + return NULL; + } - get_clone_variant_data(clone_data, parent); - local_node = pe_hash_table_lookup( - parent->allowed_nodes, node->details->id); + get_clone_variant_data(clone_data, parent); + local_node = pe_hash_table_lookup( + parent->allowed_nodes, node->details->id); - if(local_node == NULL) { - crm_err("%s cannot run on %s: node not allowed", - rsc->id, node->details->uname); - return NULL; + if(local_node == NULL) { + crm_err("%s cannot run on %s: node not allowed", + rsc->id, node->details->uname); + return NULL; - } else if(local_node->count < clone_data->master_node_max - || is_not_set(rsc->flags, pe_rsc_managed)) { - return local_node; + } else if(local_node->count < clone_data->master_node_max + || is_not_set(rsc->flags, pe_rsc_managed)) { + return local_node; - } else { - do_crm_log_unlikely(level, "%s cannot be master on %s: node full", + } else { + do_crm_log_unlikely(level, "%s cannot be master on %s: node full", rsc->id, node->details->uname); - } + } - return NULL; + return NULL; } static gint sort_master_instance(gconstpointer a, gconstpointer b, gpointer data_set) { - int rc; - enum rsc_role_e role1 = RSC_ROLE_UNKNOWN; - enum rsc_role_e role2 = RSC_ROLE_UNKNOWN; + int rc; + enum rsc_role_e role1 = RSC_ROLE_UNKNOWN; + enum rsc_role_e role2 = RSC_ROLE_UNKNOWN; - const resource_t *resource1 = (const resource_t*)a; - const resource_t *resource2 = (const resource_t*)b; + const resource_t *resource1 = (const resource_t*)a; + const resource_t *resource2 = (const resource_t*)b; - CRM_ASSERT(resource1 != NULL); - CRM_ASSERT(resource2 != NULL); + CRM_ASSERT(resource1 != NULL); + CRM_ASSERT(resource2 != NULL); - role1 = resource1->fns->state(resource1, TRUE); - role2 = resource2->fns->state(resource2, TRUE); + role1 = resource1->fns->state(resource1, TRUE); + role2 = resource2->fns->state(resource2, TRUE); - rc = sort_rsc_index(a, b); - if( rc != 0 ) { - return rc; - } + rc = sort_rsc_index(a, b); + if( rc != 0 ) { + return rc; + } - if(role1 > role2) { - return -1; + if(role1 > role2) { + return -1; - } else if(role1 < role2) { - return 1; - } + } else if(role1 < role2) { + return 1; + } - return sort_clone_instance(a, b, data_set); + return sort_clone_instance(a, b, data_set); } static void master_promotion_order(resource_t *rsc, pe_working_set_t *data_set) { + GListPtr gIter = NULL; node_t *node = NULL; node_t *chosen = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->merged_master_weights) { return; } clone_data->merged_master_weights = TRUE; crm_debug_2("Merging weights for %s", rsc->id); - slist_iter( - child, resource_t, rsc->children, lpc, + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + crm_debug_2("%s: %d", child->id, child->sort_index); - ); + } dump_node_scores(LOG_DEBUG_3, rsc, "Before", rsc->allowed_nodes); - slist_iter( - child, resource_t, rsc->children, lpc, + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; chosen = child->fns->location(child, NULL, FALSE); if(chosen == NULL || child->sort_index < 0) { crm_debug_3("Skipping %s", child->id); continue; } node = (node_t*)pe_hash_table_lookup( rsc->allowed_nodes, chosen->details->id); CRM_ASSERT(node != NULL); /* adds in master preferences and rsc_location.role=Master */ node->weight = merge_weights(child->sort_index, node->weight); - ); + } dump_node_scores(LOG_DEBUG_3, rsc, "Middle", rsc->allowed_nodes); - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons, lpc, + gIter = rsc->rsc_cons; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + /* (re-)adds location preferences of resources that the * master instance should/must be colocated with */ if(constraint->role_lh == RSC_ROLE_MASTER) { crm_debug_2("RHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id, constraint->score); rsc->allowed_nodes = constraint->rsc_rh->cmds->merge_weights( constraint->rsc_rh, rsc->id, rsc->allowed_nodes, constraint->node_attribute, constraint->score/INFINITY, constraint->score==INFINITY?FALSE:TRUE, FALSE); } - ); + } - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, + gIter = rsc->rsc_cons_lhs; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + /* (re-)adds location preferences of resource that wish to be * colocated with the master instance */ if(constraint->role_rh == RSC_ROLE_MASTER) { crm_debug_2("LHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id, constraint->score); rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rsc->id, rsc->allowed_nodes, constraint->node_attribute, constraint->score/INFINITY, TRUE, TRUE); } - ); + } dump_node_scores(LOG_DEBUG_3, rsc, "After", rsc->allowed_nodes); /* write them back and sort */ - slist_iter( - child, resource_t, rsc->children, lpc, + + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; chosen = child->fns->location(child, NULL, FALSE); if(chosen == NULL || child->sort_index < 0) { crm_debug_2("%s: %d", child->id, child->sort_index); continue; } node = (node_t*)pe_hash_table_lookup( rsc->allowed_nodes, chosen->details->id); CRM_ASSERT(node != NULL); child->sort_index = node->weight; crm_debug_2("%s: %d", child->id, child->sort_index); - ); + } rsc->children = g_list_sort_with_data(rsc->children, sort_master_instance, data_set); } int master_score(resource_t *rsc, node_t *node, int not_set_value) { - char *attr_name; - char *name = rsc->id; - const char *attr_value; - int score = not_set_value, len = 0; - - if(rsc->children) { - slist_iter( - child, resource_t, rsc->children, lpc, - int c_score = master_score(child, node, not_set_value); - if(score == not_set_value) { - score = c_score; - } else { - score += c_score; - } - ); - return score; + char *attr_name; + char *name = rsc->id; + const char *attr_value; + int score = not_set_value, len = 0; + + if(rsc->children) { + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; + int c_score = master_score(child, node, not_set_value); + + if(score == not_set_value) { + score = c_score; + } else { + score += c_score; + } } + return score; + } - if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED) { - return score; - } + if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED) { + return score; + } - if(rsc->running_on) { - node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id); - if(match && match->weight < 0) { - crm_debug_2("%s on %s has score: %d - ignoring master pref", - rsc->id, match->details->uname, match->weight); - return score; - } + if(rsc->running_on) { + node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id); + if(match && match->weight < 0) { + crm_debug_2("%s on %s has score: %d - ignoring master pref", + rsc->id, match->details->uname, match->weight); + return score; } + } - if(rsc->clone_name) { - /* Use the name the lrm knows this resource as, - * since that's what crm_master would have used too - */ - name = rsc->clone_name; - } + if(rsc->clone_name) { + /* Use the name the lrm knows this resource as, + * since that's what crm_master would have used too + */ + name = rsc->clone_name; + } - len = 8 + strlen(name); - crm_malloc0(attr_name, len); - sprintf(attr_name, "master-%s", name); + len = 8 + strlen(name); + crm_malloc0(attr_name, len); + sprintf(attr_name, "master-%s", name); + + crm_debug_3("looking for %s on %s", attr_name, + node->details->uname); + attr_value = g_hash_table_lookup( + node->details->attrs, attr_name); + if(attr_value == NULL) { + crm_free(attr_name); + len = 8 + strlen(rsc->long_name); + crm_malloc0(attr_name, len); + sprintf(attr_name, "master-%s", rsc->long_name); crm_debug_3("looking for %s on %s", attr_name, - node->details->uname); + node->details->uname); attr_value = g_hash_table_lookup( - node->details->attrs, attr_name); - - if(attr_value == NULL) { - crm_free(attr_name); - len = 8 + strlen(rsc->long_name); - crm_malloc0(attr_name, len); - sprintf(attr_name, "master-%s", rsc->long_name); - crm_debug_3("looking for %s on %s", attr_name, - node->details->uname); - attr_value = g_hash_table_lookup( - node->details->attrs, attr_name); - } + node->details->attrs, attr_name); + } - if(attr_value != NULL) { - crm_debug_2("%s[%s] = %s", attr_name, - node->details->uname, crm_str(attr_value)); - score = char2score(attr_value); - } + if(attr_value != NULL) { + crm_debug_2("%s[%s] = %s", attr_name, + node->details->uname, crm_str(attr_value)); + score = char2score(attr_value); + } - crm_free(attr_name); - return score; + crm_free(attr_name); + return score; } #define max(a, b) achildren; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->applied_master_prefs) { /* Make sure we only do this once */ return; } clone_data->applied_master_prefs = TRUE; - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - + for(; gIter != NULL; gIter = gIter->next) { GHashTableIter iter; node_t *node = NULL; + resource_t *child_rsc = (resource_t*)gIter->data; + g_hash_table_iter_init (&iter, child_rsc->allowed_nodes); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { if(can_run_resources(node) == FALSE) { /* This node will never be promoted to master, * so don't apply the master score as that may * lead to clone shuffling */ continue; } score = master_score(child_rsc, node, 0); if(score > 0) { new_score = merge_weights(node->weight, score); if(new_score != node->weight) { crm_debug_2("\t%s: Updating preference for %s (%d->%d)", child_rsc->id, node->details->uname, node->weight, new_score); node->weight = new_score; } } new_score = max(child_rsc->priority, score); if(new_score != child_rsc->priority) { crm_debug_2("\t%s: Updating priority (%d->%d)", - child_rsc->id, child_rsc->priority, new_score); + child_rsc->id, child_rsc->priority, new_score); child_rsc->priority = new_score; } } - ); + } } static void set_role_slave(resource_t *rsc, gboolean current) { + GListPtr gIter = rsc->children; if(current) { if(rsc->role == RSC_ROLE_STARTED) { rsc->role = RSC_ROLE_SLAVE; } } else { GListPtr allocated = NULL; rsc->fns->location(rsc, &allocated, FALSE); if(allocated) { rsc->next_role = RSC_ROLE_SLAVE; } else { rsc->next_role = RSC_ROLE_STOPPED; } g_list_free(allocated); } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; set_role_slave(child_rsc, current); - ); + } } static void set_role_master(resource_t *rsc) { + GListPtr gIter = rsc->children; if(rsc->next_role == RSC_ROLE_UNKNOWN) { rsc->next_role = RSC_ROLE_MASTER; } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; set_role_master(child_rsc); - ); + } } node_t * master_color(resource_t *rsc, pe_working_set_t *data_set) { - int promoted = 0; - GHashTableIter iter; - node_t *node = NULL; - node_t *chosen = NULL; - node_t *cons_node = NULL; - enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; + int promoted = 0; + GListPtr gIter = NULL; + GListPtr gIter2 = NULL; + + GHashTableIter iter; + node_t *node = NULL; + node_t *chosen = NULL; + node_t *cons_node = NULL; + enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - apply_master_prefs(rsc); + apply_master_prefs(rsc); - clone_color(rsc, data_set); + clone_color(rsc, data_set); - /* count now tracks the number of masters allocated */ - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - node->count = 0; - } - - /* - * assign priority - */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + /* count now tracks the number of masters allocated */ + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + node->count = 0; + } - GListPtr list = NULL; - crm_debug_2("Assigning priority for %s: %s", child_rsc->id, role2text(child_rsc->next_role)); + /* + * assign priority + */ + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + GListPtr list = NULL; + resource_t *child_rsc = (resource_t*)gIter->data; - if(child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) { - set_role_slave(child_rsc, TRUE); - } + crm_debug_2("Assigning priority for %s: %s", child_rsc->id, role2text(child_rsc->next_role)); - chosen = child_rsc->fns->location(child_rsc, &list, FALSE); - if(g_list_length(list) > 1) { - crm_config_err("Cannot promote non-colocated child %s", child_rsc->id); - } + if(child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) { + set_role_slave(child_rsc, TRUE); + } - g_list_free(list); - if(chosen == NULL) { - continue; - } - - next_role = child_rsc->fns->state(child_rsc, FALSE); - switch(next_role) { - case RSC_ROLE_STARTED: - case RSC_ROLE_UNKNOWN: - CRM_CHECK(chosen != NULL, break); - /* - * Default to -1 if no value is set - * - * This allows master locations to be specified - * based solely on rsc_location constraints, - * but prevents anyone from being promoted if - * neither a constraint nor a master-score is present - */ - child_rsc->priority = master_score(child_rsc, chosen, -1); - break; - - case RSC_ROLE_SLAVE: - case RSC_ROLE_STOPPED: - child_rsc->priority = -INFINITY; - break; - case RSC_ROLE_MASTER: - /* We will arrive here if we're re-creating actions after a stonith - * OR target-role is set - */ - break; - default: - CRM_CHECK(FALSE/* unhandled */, - crm_err("Unknown resource role: %d for %s", - next_role, child_rsc->id)); - } + chosen = child_rsc->fns->location(child_rsc, &list, FALSE); + if(g_list_length(list) > 1) { + crm_config_err("Cannot promote non-colocated child %s", child_rsc->id); + } - apply_master_location(child_rsc->rsc_location); - apply_master_location(rsc->rsc_location); - slist_iter( - cons, rsc_colocation_t, child_rsc->rsc_cons, lpc2, - child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons); - ); + g_list_free(list); + if(chosen == NULL) { + continue; + } - child_rsc->sort_index = child_rsc->priority; - crm_debug_2("Assigning priority for %s: %d", child_rsc->id, child_rsc->priority); + next_role = child_rsc->fns->state(child_rsc, FALSE); + switch(next_role) { + case RSC_ROLE_STARTED: + case RSC_ROLE_UNKNOWN: + CRM_CHECK(chosen != NULL, break); + /* + * Default to -1 if no value is set + * + * This allows master locations to be specified + * based solely on rsc_location constraints, + * but prevents anyone from being promoted if + * neither a constraint nor a master-score is present + */ + child_rsc->priority = master_score(child_rsc, chosen, -1); + break; + + case RSC_ROLE_SLAVE: + case RSC_ROLE_STOPPED: + child_rsc->priority = -INFINITY; + break; + case RSC_ROLE_MASTER: + /* We will arrive here if we're re-creating actions after a stonith + * OR target-role is set + */ + break; + default: + CRM_CHECK(FALSE/* unhandled */, + crm_err("Unknown resource role: %d for %s", + next_role, child_rsc->id)); + } - if(next_role == RSC_ROLE_MASTER) { - child_rsc->sort_index = INFINITY; - } + apply_master_location(child_rsc->rsc_location); + apply_master_location(rsc->rsc_location); - ); + gIter2 = child_rsc->rsc_cons; + for(; gIter2 != NULL; gIter2 = gIter2->next) { + rsc_colocation_t *cons = (rsc_colocation_t*)gIter2->data; + child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons); + } + + child_rsc->sort_index = child_rsc->priority; + crm_debug_2("Assigning priority for %s: %d", child_rsc->id, child_rsc->priority); - dump_node_scores(LOG_DEBUG_3, rsc, "Pre merge", rsc->allowed_nodes); - master_promotion_order(rsc, data_set); + if(next_role == RSC_ROLE_MASTER) { + child_rsc->sort_index = INFINITY; + } + } + + dump_node_scores(LOG_DEBUG_3, rsc, "Pre merge", rsc->allowed_nodes); + master_promotion_order(rsc, data_set); - /* mark the first N as masters */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + /* mark the first N as masters */ - char *score = score2char(child_rsc->sort_index); - chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); - if(show_scores) { - fprintf(stdout, "%s promotion score on %s: %s\n", - child_rsc->id, chosen?chosen->details->uname:"none", score); + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + char *score = score2char(child_rsc->sort_index); + + chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); + if(show_scores) { + fprintf(stdout, "%s promotion score on %s: %s\n", + child_rsc->id, chosen?chosen->details->uname:"none", score); - } else { - do_crm_log_unlikely(scores_log_level, "%s promotion score on %s: %s", - child_rsc->id, chosen?chosen->details->uname:"none", score); - } - crm_free(score); + } else { + do_crm_log_unlikely(scores_log_level, "%s promotion score on %s: %s", + child_rsc->id, chosen?chosen->details->uname:"none", score); + } + crm_free(score); - chosen = NULL; /* nuke 'chosen' so that we don't promote more than the - * required number of instances - */ + chosen = NULL; /* nuke 'chosen' so that we don't promote more than the + * required number of instances + */ - if(child_rsc->sort_index < 0) { - crm_debug_2("Not supposed to promote child: %s", child_rsc->id); + if(child_rsc->sort_index < 0) { + crm_debug_2("Not supposed to promote child: %s", child_rsc->id); - } else if(promoted < clone_data->master_max || is_not_set(rsc->flags, pe_rsc_managed)) { - chosen = can_be_master(child_rsc); - } + } else if(promoted < clone_data->master_max || is_not_set(rsc->flags, pe_rsc_managed)) { + chosen = can_be_master(child_rsc); + } - crm_debug("%s master score: %d", child_rsc->id, child_rsc->priority); + crm_debug("%s master score: %d", child_rsc->id, child_rsc->priority); - if(chosen == NULL) { - set_role_slave(child_rsc, FALSE); - continue; - } + if(chosen == NULL) { + set_role_slave(child_rsc, FALSE); + continue; + } - chosen->count++; - crm_info("Promoting %s (%s %s)", - child_rsc->id, role2text(child_rsc->role), chosen->details->uname); - set_role_master(child_rsc); - promoted++; - ); + chosen->count++; + crm_info("Promoting %s (%s %s)", + child_rsc->id, role2text(child_rsc->role), chosen->details->uname); + set_role_master(child_rsc); + promoted++; + } - clone_data->masters_allocated = promoted; - crm_info("%s: Promoted %d instances of a possible %d to master", - rsc->id, promoted, clone_data->master_max); - return NULL; + clone_data->masters_allocated = promoted; + crm_info("%s: Promoted %d instances of a possible %d to master", + rsc->id, promoted, clone_data->master_max); + return NULL; } void master_create_actions(resource_t *rsc, pe_working_set_t *data_set) { - action_t *action = NULL; - action_t *action_complete = NULL; - gboolean any_promoting = FALSE; - gboolean any_demoting = FALSE; - resource_t *last_promote_rsc = NULL; - resource_t *last_demote_rsc = NULL; - - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + action_t *action = NULL; + GListPtr gIter = rsc->children; + action_t *action_complete = NULL; + gboolean any_promoting = FALSE; + gboolean any_demoting = FALSE; + resource_t *last_promote_rsc = NULL; + resource_t *last_demote_rsc = NULL; + + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - crm_debug("Creating actions for %s", rsc->id); + crm_debug("Creating actions for %s", rsc->id); - /* create actions as normal */ - clone_create_actions(rsc, data_set); + /* create actions as normal */ + clone_create_actions(rsc, data_set); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - gboolean child_promoting = FALSE; - gboolean child_demoting = FALSE; + for(; gIter != NULL; gIter = gIter->next) { + gboolean child_promoting = FALSE; + gboolean child_demoting = FALSE; + resource_t *child_rsc = (resource_t*)gIter->data; - crm_debug_2("Creating actions for %s", child_rsc->id); - child_rsc->cmds->create_actions(child_rsc, data_set); - master_update_pseudo_status( - child_rsc, &child_demoting, &child_promoting); + crm_debug_2("Creating actions for %s", child_rsc->id); + child_rsc->cmds->create_actions(child_rsc, data_set); + master_update_pseudo_status( + child_rsc, &child_demoting, &child_promoting); - any_demoting = any_demoting || child_demoting; - any_promoting = any_promoting || child_promoting; - crm_debug_2("Created actions for %s: %d %d", child_rsc->id, child_promoting, child_demoting); - ); + any_demoting = any_demoting || child_demoting; + any_promoting = any_promoting || child_promoting; + crm_debug_2("Created actions for %s: %d %d", child_rsc->id, child_promoting, child_demoting); + } - /* promote */ - action = promote_action(rsc, NULL, !any_promoting); - action_complete = custom_action( - rsc, promoted_key(rsc), - RSC_PROMOTED, NULL, !any_promoting, TRUE, data_set); - - action_complete->priority = INFINITY; - update_action_flags(action, pe_action_pseudo); + /* promote */ + action = promote_action(rsc, NULL, !any_promoting); + action_complete = custom_action( + rsc, promoted_key(rsc), + RSC_PROMOTED, NULL, !any_promoting, TRUE, data_set); + + action_complete->priority = INFINITY; + update_action_flags(action, pe_action_pseudo); + update_action_flags(action, pe_action_runnable); + update_action_flags(action_complete, pe_action_pseudo); + update_action_flags(action_complete, pe_action_runnable); + + if(clone_data->masters_allocated > 0) { update_action_flags(action, pe_action_runnable); - update_action_flags(action_complete, pe_action_pseudo); update_action_flags(action_complete, pe_action_runnable); - - if(clone_data->masters_allocated > 0) { - update_action_flags(action, pe_action_runnable); - update_action_flags(action_complete, pe_action_runnable); - } + } - child_promoting_constraints(clone_data, pe_order_optional, - rsc, NULL, last_promote_rsc, data_set); + child_promoting_constraints(clone_data, pe_order_optional, + rsc, NULL, last_promote_rsc, data_set); - if(clone_data->promote_notify == NULL) { - clone_data->promote_notify = create_notification_boundaries( - rsc, RSC_PROMOTE, action, action_complete, data_set); - } + if(clone_data->promote_notify == NULL) { + clone_data->promote_notify = create_notification_boundaries( + rsc, RSC_PROMOTE, action, action_complete, data_set); + } - /* demote */ - action = demote_action(rsc, NULL, !any_demoting); - action_complete = custom_action( - rsc, demoted_key(rsc), - RSC_DEMOTED, NULL, !any_demoting, TRUE, data_set); - action_complete->priority = INFINITY; - - update_action_flags(action, pe_action_pseudo); - update_action_flags(action, pe_action_runnable); - update_action_flags(action_complete, pe_action_pseudo); - update_action_flags(action_complete, pe_action_runnable); + /* demote */ + action = demote_action(rsc, NULL, !any_demoting); + action_complete = custom_action( + rsc, demoted_key(rsc), + RSC_DEMOTED, NULL, !any_demoting, TRUE, data_set); + action_complete->priority = INFINITY; + + update_action_flags(action, pe_action_pseudo); + update_action_flags(action, pe_action_runnable); + update_action_flags(action_complete, pe_action_pseudo); + update_action_flags(action_complete, pe_action_runnable); - child_demoting_constraints(clone_data, pe_order_optional, - rsc, NULL, last_demote_rsc, data_set); + child_demoting_constraints(clone_data, pe_order_optional, + rsc, NULL, last_demote_rsc, data_set); - if(clone_data->demote_notify == NULL) { - clone_data->demote_notify = create_notification_boundaries( - rsc, RSC_DEMOTE, action, action_complete, data_set); + if(clone_data->demote_notify == NULL) { + clone_data->demote_notify = create_notification_boundaries( + rsc, RSC_DEMOTE, action, action_complete, data_set); - if(clone_data->promote_notify) { - /* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day - * Requires exposing *_notify - */ - order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); - order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); - order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); - order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre, pe_order_optional); - order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre, pe_order_optional); - } + if(clone_data->promote_notify) { + /* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day + * Requires exposing *_notify + */ + order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); + order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); + order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre, pe_order_optional); + order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre, pe_order_optional); + order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre, pe_order_optional); } + } + + /* restore the correct priority */ - /* restore the correct priority */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - child_rsc->priority = rsc->priority; - ); + gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->priority = rsc->priority; + } } void master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { - resource_t *last_rsc = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); + GListPtr gIter = rsc->children; + resource_t *last_rsc = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc); - clone_internal_constraints(rsc, data_set); + clone_internal_constraints(rsc, data_set); - /* global stopped before start */ - new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); + /* global stopped before start */ + new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); - /* global stopped before promote */ - new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_PROMOTE, pe_order_optional, data_set); + /* global stopped before promote */ + new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_PROMOTE, pe_order_optional, data_set); - /* global demoted before start */ - new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_START, pe_order_optional, data_set); + /* global demoted before start */ + new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_START, pe_order_optional, data_set); - /* global started before promote */ - new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_optional, data_set); + /* global started before promote */ + new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_optional, data_set); - /* global demoted before stop */ - new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set); + /* global demoted before stop */ + new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set); - /* global demote before demoted */ - new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_optional, data_set); + /* global demote before demoted */ + new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_optional, data_set); - /* global demoted before promote */ - new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_PROMOTE, pe_order_optional, data_set); + /* global demoted before promote */ + new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_PROMOTE, pe_order_optional, data_set); - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - /* child demote before promote */ - new_rsc_order(child_rsc, RSC_DEMOTE, child_rsc, RSC_PROMOTE, pe_order_optional, data_set); + /* child demote before promote */ + new_rsc_order(child_rsc, RSC_DEMOTE, child_rsc, RSC_PROMOTE, pe_order_optional, data_set); - child_promoting_constraints(clone_data, pe_order_optional, - rsc, child_rsc, last_rsc, data_set); + child_promoting_constraints(clone_data, pe_order_optional, + rsc, child_rsc, last_rsc, data_set); - child_demoting_constraints(clone_data, pe_order_optional, - rsc, child_rsc, last_rsc, data_set); + child_demoting_constraints(clone_data, pe_order_optional, + rsc, child_rsc, last_rsc, data_set); - last_rsc = child_rsc; - - ); - + last_rsc = child_rsc; + } } static void node_hash_update_one(GHashTable *hash, node_t *other, const char *attr, int score) { GHashTableIter iter; node_t *node = NULL; const char *value = NULL; if(other == NULL) { return; } else if(attr == NULL) { attr = "#"XML_ATTR_UNAME; } value = g_hash_table_lookup(other->details->attrs, attr); g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - const char *tmp = g_hash_table_lookup(node->details->attrs, attr); - if(safe_str_eq(value, tmp)) { - crm_debug_2("%s: %d + %d", node->details->uname, node->weight, other->weight); - node->weight = merge_weights(node->weight, score); - } + const char *tmp = g_hash_table_lookup(node->details->attrs, attr); + if(safe_str_eq(value, tmp)) { + crm_debug_2("%s: %d + %d", node->details->uname, node->weight, other->weight); + node->weight = merge_weights(node->weight, score); + } } } void master_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc_rh); + GListPtr gIter = NULL; + clone_variant_data_t *clone_data = NULL; + get_clone_variant_data(clone_data, rsc_rh); + + CRM_CHECK(rsc_rh != NULL, return); + if(is_set(rsc_rh->flags, pe_rsc_provisional)) { + return; + } else if(constraint->role_rh == RSC_ROLE_UNKNOWN) { + crm_debug_3("Handling %s as a clone colocation", constraint->id); + clone_rsc_colocation_rh(rsc_lh, rsc_rh, constraint); + return; + } - CRM_CHECK(rsc_rh != NULL, return); - if(is_set(rsc_rh->flags, pe_rsc_provisional)) { - return; - - } else if(constraint->role_rh == RSC_ROLE_UNKNOWN) { - crm_debug_3("Handling %s as a clone colocation", constraint->id); - clone_rsc_colocation_rh(rsc_lh, rsc_rh, constraint); - return; + CRM_CHECK(rsc_lh != NULL, return); + CRM_CHECK(rsc_lh->variant == pe_native, return); + crm_debug_2("Processing constraint %s: %d", constraint->id, constraint->score); + + if(constraint->role_rh == RSC_ROLE_UNKNOWN) { + + gIter = rsc_rh->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); } - - CRM_CHECK(rsc_lh != NULL, return); - CRM_CHECK(rsc_lh->variant == pe_native, return); - crm_debug_2("Processing constraint %s: %d", constraint->id, constraint->score); - - if(constraint->role_rh == RSC_ROLE_UNKNOWN) { - slist_iter( - child_rsc, resource_t, rsc_rh->children, lpc, - - child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); - ); - - } else if(is_set(rsc_lh->flags, pe_rsc_provisional)) { - GListPtr rhs = NULL; - slist_iter( - child_rsc, resource_t, rsc_rh->children, lpc, - node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); - enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE); - crm_debug_3("Processing: %s", child_rsc->id); - if(chosen != NULL && next_role == constraint->role_rh) { - crm_debug_3("Applying: %s %s %s %d", child_rsc->id, - role2text(next_role), chosen->details->uname, constraint->score); - if(constraint->score < INFINITY) { - node_hash_update_one(rsc_lh->allowed_nodes, chosen, - constraint->node_attribute, constraint->score); - } - rhs = g_list_prepend(rhs, chosen); - } - ); - - /* Only do this if its not a master-master colocation - * Doing this unconditionally would prevent the slaves from being started - */ - if(constraint->role_lh != RSC_ROLE_MASTER - || constraint->role_rh != RSC_ROLE_MASTER) { - if(constraint->score > 0) { - node_list_exclude(rsc_lh->allowed_nodes, rhs, TRUE); - } + + } else if(is_set(rsc_lh->flags, pe_rsc_provisional)) { + GListPtr rhs = NULL; + + gIter = rsc_rh->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); + enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE); + crm_debug_3("Processing: %s", child_rsc->id); + if(chosen != NULL && next_role == constraint->role_rh) { + crm_debug_3("Applying: %s %s %s %d", child_rsc->id, + role2text(next_role), chosen->details->uname, constraint->score); + if(constraint->score < INFINITY) { + node_hash_update_one(rsc_lh->allowed_nodes, chosen, + constraint->node_attribute, constraint->score); } - g_list_free(rhs); + rhs = g_list_prepend(rhs, chosen); + } + } - } else if(constraint->role_lh == RSC_ROLE_MASTER) { - resource_t *rh_child = find_compatible_child(rsc_lh, rsc_rh, constraint->role_rh, FALSE); - if(rh_child == NULL && constraint->score >= INFINITY) { - crm_debug_2("%s can't be promoted %s", rsc_lh->id, constraint->id); - rsc_lh->priority = -INFINITY; - - } else if(rh_child != NULL) { - int new_priority = merge_weights(rsc_lh->priority, constraint->score); - crm_debug("Applying %s to %s", constraint->id, rsc_lh->id); - crm_debug("\t%s: %d->%d", rsc_lh->id, rsc_lh->priority, new_priority); - rsc_lh->priority = new_priority; + /* Only do this if its not a master-master colocation + * Doing this unconditionally would prevent the slaves from being started + */ + if(constraint->role_lh != RSC_ROLE_MASTER + || constraint->role_rh != RSC_ROLE_MASTER) { + if(constraint->score > 0) { + node_list_exclude(rsc_lh->allowed_nodes, rhs, TRUE); } } + g_list_free(rhs); - return; + } else if(constraint->role_lh == RSC_ROLE_MASTER) { + resource_t *rh_child = find_compatible_child(rsc_lh, rsc_rh, constraint->role_rh, FALSE); + if(rh_child == NULL && constraint->score >= INFINITY) { + crm_debug_2("%s can't be promoted %s", rsc_lh->id, constraint->id); + rsc_lh->priority = -INFINITY; + + } else if(rh_child != NULL) { + int new_priority = merge_weights(rsc_lh->priority, constraint->score); + crm_debug("Applying %s to %s", constraint->id, rsc_lh->id); + crm_debug("\t%s: %d->%d", rsc_lh->id, rsc_lh->priority, new_priority); + rsc_lh->priority = new_priority; + } + } + + return; } void master_append_meta(resource_t *rsc, xmlNode *xml) { char *name = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_append_meta(rsc, xml); name = crm_meta_name(XML_RSC_ATTR_MASTER_MAX); crm_xml_add_int(xml, name, clone_data->master_max); crm_free(name); name = crm_meta_name(XML_RSC_ATTR_MASTER_NODEMAX); crm_xml_add_int(xml, name, clone_data->master_node_max); crm_free(name); } diff --git a/pengine/native.c b/pengine/native.c index 96f38c7b78..656f6676f7 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -1,2416 +1,2449 @@ /* * 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 #define DELETE_THEN_REFRESH 1 /* The crmd will remove the resource from the CIB itself, making this redundant */ #define VARIANT_NATIVE 1 #include 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 Recurring(resource_t *rsc, action_t *start, node_t *node, - pe_working_set_t *data_set); + pe_working_set_t *data_set); void RecurringOp(resource_t *rsc, action_t *start, node_t *node, xmlNode *operation, 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); + resource_t *rsc, node_t *node, action_t *op, + notify_data_t *n_data, pe_working_set_t *data_set); void NoRoleChange (resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set); gboolean DeleteRsc (resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set); gboolean StopRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean StartRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean DemoteRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean RoleError (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean NullOp (resource_t *rsc, node_t *next, gboolean optional, 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, }, + /* 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*,gboolean,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, }, + /* 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, }, }; struct capacity_data { node_t *node; resource_t *rsc; gboolean is_enough; }; static void check_capacity(gpointer key, gpointer value, gpointer user_data) { - int required = 0; - int remaining = 0; - struct capacity_data *data = user_data; + int required = 0; + int remaining = 0; + struct capacity_data *data = user_data; - required = crm_parse_int(value, "0"); - remaining = crm_parse_int(g_hash_table_lookup(data->node->details->utilization, key), "0"); + required = crm_parse_int(value, "0"); + remaining = crm_parse_int(g_hash_table_lookup(data->node->details->utilization, key), "0"); - if (required > remaining) { - crm_debug("Node %s has no enough %s for resource %s: required=%d remaining=%d", - data->node->details->uname, (char *)key, data->rsc->id, required, remaining); - data->is_enough = FALSE; - } + if (required > remaining) { + crm_debug("Node %s has no enough %s for resource %s: required=%d remaining=%d", + data->node->details->uname, (char *)key, data->rsc->id, required, remaining); + data->is_enough = FALSE; + } } static gboolean have_enough_capacity(node_t *node, resource_t *rsc) { - struct capacity_data data; + struct capacity_data data; - data.node = node; - data.rsc = rsc; - data.is_enough = TRUE; + data.node = node; + data.rsc = rsc; + data.is_enough = TRUE; - g_hash_table_foreach(rsc->utilization, check_capacity, &data); + g_hash_table_foreach(rsc->utilization, check_capacity, &data); - return data.is_enough; + return data.is_enough; } static gboolean native_choose_node(resource_t *rsc, pe_working_set_t *data_set) { - /* - 1. Sort by weight - 2. color.chosen_node = the node (of those with the highest wieght) - with the fewest resources - 3. remove color.chosen_node from all other colors - */ - int alloc_details = scores_log_level+1; - - GListPtr nodes = NULL; - node_t *chosen = NULL; - - int lpc = 0; - int multiple = 0; - int length = 0; - gboolean result = FALSE; - - if (safe_str_neq(data_set->placement_strategy, "default")) { - slist_iter( - node, node_t, data_set->nodes, lpc, - if (have_enough_capacity(node, rsc) == FALSE) { - crm_debug("Resource %s cannot be allocated to node %s: none of enough capacity", - rsc->id, node->details->uname); - resource_location(rsc, node, -INFINITY, "__limit_utilization_", data_set); - } - ); - dump_node_scores(alloc_details, rsc, "Post-utilization", rsc->allowed_nodes); + /* + 1. Sort by weight + 2. color.chosen_node = the node (of those with the highest wieght) + with the fewest resources + 3. remove color.chosen_node from all other colors + */ + int alloc_details = scores_log_level+1; + + GListPtr nodes = NULL; + node_t *chosen = NULL; + + int lpc = 0; + int multiple = 0; + int length = 0; + gboolean result = FALSE; + + if (safe_str_neq(data_set->placement_strategy, "default")) { + GListPtr gIter = NULL; + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + + if (have_enough_capacity(node, rsc) == FALSE) { + crm_debug("Resource %s cannot be allocated to node %s: none of enough capacity", + rsc->id, node->details->uname); + resource_location(rsc, node, -INFINITY, "__limit_utilization_", data_set); + } } + dump_node_scores(alloc_details, rsc, "Post-utilization", rsc->allowed_nodes); + } - length = g_hash_table_size(rsc->allowed_nodes); + length = g_hash_table_size(rsc->allowed_nodes); - if(is_not_set(rsc->flags, pe_rsc_provisional)) { - return rsc->allocated_to?TRUE:FALSE; - } + if(is_not_set(rsc->flags, pe_rsc_provisional)) { + return rsc->allocated_to?TRUE:FALSE; + } - crm_debug_3("Choosing node for %s from %d candidates", rsc->id, length); - - if(rsc->allowed_nodes) { - nodes = g_hash_table_get_values(rsc->allowed_nodes); - nodes = g_list_sort_with_data(nodes, sort_node_weight, g_list_nth_data(rsc->running_on, 0)); - chosen = g_list_nth_data(nodes, 0); - - if(chosen - && chosen->weight > 0 - && can_run_resources(chosen)) { - node_t *running = g_list_nth_data(rsc->running_on, 0); - if(running && can_run_resources(running) == FALSE) { - crm_trace("Current node for %s (%s) can't run resources", - rsc->id, running->details->uname); - running = NULL; - } + crm_debug_3("Choosing node for %s from %d candidates", rsc->id, length); + + if(rsc->allowed_nodes) { + nodes = g_hash_table_get_values(rsc->allowed_nodes); + nodes = g_list_sort_with_data(nodes, sort_node_weight, g_list_nth_data(rsc->running_on, 0)); + chosen = g_list_nth_data(nodes, 0); + + if(chosen + && chosen->weight > 0 + && can_run_resources(chosen)) { + node_t *running = g_list_nth_data(rsc->running_on, 0); + if(running && can_run_resources(running) == FALSE) { + crm_trace("Current node for %s (%s) can't run resources", + rsc->id, running->details->uname); + running = NULL; + } - for(lpc = 1; lpc < length; lpc++) { - node_t *tmp = g_list_nth_data(nodes, lpc); - if(tmp->weight == chosen->weight) { - multiple++; - if(running && tmp->details == running->details) { - /* prefer the existing node if scores are equal */ - chosen = tmp; - } + for(lpc = 1; lpc < length; lpc++) { + node_t *tmp = g_list_nth_data(nodes, lpc); + if(tmp->weight == chosen->weight) { + multiple++; + if(running && tmp->details == running->details) { + /* prefer the existing node if scores are equal */ + chosen = tmp; } } } } + } - if(multiple > 1) { - int log_level = LOG_INFO; - char *score = score2char(chosen->weight); - if(chosen->weight >= INFINITY) { - log_level = LOG_WARNING; - } - - do_crm_log(log_level, "%d nodes with equal score (%s) for" - " running %s resources. Chose %s.", - multiple, score, rsc->id, chosen->details->uname); - crm_free(score); + if(multiple > 1) { + int log_level = LOG_INFO; + char *score = score2char(chosen->weight); + if(chosen->weight >= INFINITY) { + log_level = LOG_WARNING; } + + do_crm_log(log_level, "%d nodes with equal score (%s) for" + " running %s resources. Chose %s.", + multiple, score, rsc->id, chosen->details->uname); + crm_free(score); + } - result = native_assign_node(rsc, nodes, chosen, FALSE); - g_list_free(nodes); - return result; + result = native_assign_node(rsc, nodes, chosen, FALSE); + g_list_free(nodes); + return result; } static int node_list_attr_score(GHashTable *list, const char *attr, const char *value) { GHashTableIter iter; node_t *node = NULL; int best_score = -INFINITY; const char *best_node = NULL; if(attr == NULL) { attr = "#"XML_ATTR_UNAME; } g_hash_table_iter_init (&iter, list); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - int weight = node->weight; - if(can_run_resources(node) == FALSE) { - weight = -INFINITY; - } - if(weight > best_score || best_node == NULL) { - const char *tmp = g_hash_table_lookup(node->details->attrs, attr); - if(safe_str_eq(value, tmp)) { - best_score = weight; - best_node = node->details->uname; - } - } + int weight = node->weight; + if(can_run_resources(node) == FALSE) { + weight = -INFINITY; + } + if(weight > best_score || best_node == NULL) { + const char *tmp = g_hash_table_lookup(node->details->attrs, attr); + if(safe_str_eq(value, tmp)) { + best_score = weight; + best_node = node->details->uname; + } + } } if(safe_str_neq(attr, "#"XML_ATTR_UNAME)) { crm_info("Best score for %s=%s was %s with %d", - attr, value, best_node?best_node:"", best_score); + attr, value, best_node?best_node:"", best_score); } return best_score; } static void node_hash_update(GHashTable *list1, GHashTable *list2, const char *attr, int factor, gboolean only_positive) { int score = 0; int new_score = 0; GHashTableIter iter; node_t *node = NULL; if(attr == NULL) { attr = "#"XML_ATTR_UNAME; } g_hash_table_iter_init (&iter, list1); while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { CRM_CHECK(node != NULL, continue); score = node_list_attr_score(list2, attr, g_hash_table_lookup(node->details->attrs, attr)); new_score = merge_weights(factor*score, node->weight); if(factor < 0 && score < 0) { /* Negative preference for a node with a negative score * should not become a positive preference * * TODO: Decide if we want to filter only if weight == -INFINITY * */ crm_trace("%s: Filtering %d + %d*%d (factor * score)", node->details->uname, node->weight, factor, score); } else if(only_positive && new_score < 0 && node->weight > 0) { node->weight = 1; crm_trace("%s: Filtering %d + %d*%d (score > 0)", node->details->uname, node->weight, factor, score); } else if(only_positive && new_score < 0 && node->weight == 0) { crm_trace("%s: Filtering %d + %d*%d (score == 0)", node->details->uname, node->weight, factor, score); } else { crm_trace("%s: %d + %d*%d", node->details->uname, node->weight, factor, score); node->weight = new_score; } } } static GHashTable * node_hash_dup(GHashTable *hash) { /* Hack! */ GListPtr list = g_hash_table_get_values(hash); GHashTable *result = node_hash_from_list(list); g_list_free(list); return result; } GHashTable * rsc_merge_weights(resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, int factor, gboolean allow_rollback, gboolean only_positive) { GHashTable *work = NULL; int multiplier = 1; if(factor < 0) { multiplier = -1; } if(is_set(rsc->flags, pe_rsc_merging)) { crm_info("%s: Breaking dependency loop at %s", rhs, rsc->id); return nodes; } set_bit(rsc->flags, pe_rsc_merging); crm_debug_2("%s: Combining scores from %s", rhs, rsc->id); work = node_hash_dup(nodes); node_hash_update(work, rsc->allowed_nodes, attr, factor, only_positive); if(allow_rollback && can_run_any(work) == FALSE) { crm_info("%s: Rolling back scores from %s", rhs, rsc->id); g_hash_table_destroy(work); /* TODO: Free memory */ clear_bit(rsc->flags, pe_rsc_merging); return nodes; } if(can_run_any(work)) { - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, - + GListPtr gIter = NULL; + for(gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; crm_debug_2("Applying %s", constraint->id); work = rsc_merge_weights(constraint->rsc_lh, rhs, work, constraint->node_attribute, - multiplier*constraint->score/INFINITY, allow_rollback, only_positive); - ); + multiplier*constraint->score/INFINITY, allow_rollback, only_positive); + } } g_hash_table_destroy(nodes); /* TODO: Free memory */ clear_bit(rsc->flags, pe_rsc_merging); return work; } node_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { - int alloc_details = scores_log_level+1; - const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - if(rsc->parent && is_not_set(rsc->parent->flags, pe_rsc_allocating)) { - /* never allocate children on their own */ - crm_debug("Escalating allocation of %s to its parent: %s", - rsc->id, rsc->parent->id); - rsc->parent->cmds->allocate(rsc->parent, data_set); - } + GListPtr gIter = NULL; + int alloc_details = scores_log_level+1; + const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + if(rsc->parent && is_not_set(rsc->parent->flags, pe_rsc_allocating)) { + /* never allocate children on their own */ + crm_debug("Escalating allocation of %s to its parent: %s", + rsc->id, rsc->parent->id); + rsc->parent->cmds->allocate(rsc->parent, data_set); + } - if(is_not_set(rsc->flags, pe_rsc_provisional)) { - return rsc->allocated_to; - } - - if(is_set(rsc->flags, pe_rsc_allocating)) { - crm_debug("Dependency loop detected involving %s", rsc->id); - return NULL; - } - - set_bit(rsc->flags, pe_rsc_allocating); - print_resource(alloc_details, "Allocating: ", rsc, FALSE); - dump_node_scores(alloc_details, rsc, "Pre-allloc", rsc->allowed_nodes); + if(is_not_set(rsc->flags, pe_rsc_provisional)) { + return rsc->allocated_to; + } - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons, lpc, + if(is_set(rsc->flags, pe_rsc_allocating)) { + crm_debug("Dependency loop detected involving %s", rsc->id); + return NULL; + } - GHashTable *archive = NULL; - resource_t *rsc_rh = constraint->rsc_rh; - crm_debug_2("%s: Pre-Processing %s (%s, %d, %s)", - rsc->id, constraint->id, rsc_rh->id, - constraint->score, role2text(constraint->role_lh)); - if(constraint->role_lh >= RSC_ROLE_MASTER - || (constraint->score < 0 && constraint->score > -INFINITY)) { - archive = node_hash_dup(rsc->allowed_nodes); - } - rsc_rh->cmds->allocate(rsc_rh, data_set); - rsc->cmds->rsc_colocation_lh(rsc, rsc_rh, constraint); - if(archive && can_run_any(rsc->allowed_nodes) == FALSE) { - crm_info("%s: Rolling back scores from %s", rsc->id, rsc_rh->id); - g_hash_table_destroy(rsc->allowed_nodes); - rsc->allowed_nodes = archive; - archive = NULL; - } - if(archive) { - g_hash_table_destroy(archive); - } - ); + set_bit(rsc->flags, pe_rsc_allocating); + print_resource(alloc_details, "Allocating: ", rsc, FALSE); + dump_node_scores(alloc_details, rsc, "Pre-allloc", rsc->allowed_nodes); + + for(gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + + GHashTable *archive = NULL; + resource_t *rsc_rh = constraint->rsc_rh; + crm_debug_2("%s: Pre-Processing %s (%s, %d, %s)", + rsc->id, constraint->id, rsc_rh->id, + constraint->score, role2text(constraint->role_lh)); + if(constraint->role_lh >= RSC_ROLE_MASTER + || (constraint->score < 0 && constraint->score > -INFINITY)) { + archive = node_hash_dup(rsc->allowed_nodes); + } + rsc_rh->cmds->allocate(rsc_rh, data_set); + rsc->cmds->rsc_colocation_lh(rsc, rsc_rh, constraint); + if(archive && can_run_any(rsc->allowed_nodes) == FALSE) { + crm_info("%s: Rolling back scores from %s", rsc->id, rsc_rh->id); + g_hash_table_destroy(rsc->allowed_nodes); + rsc->allowed_nodes = archive; + archive = NULL; + } + if(archive) { + g_hash_table_destroy(archive); + } + } - dump_node_scores(alloc_details, rsc, "Post-coloc", rsc->allowed_nodes); + dump_node_scores(alloc_details, rsc, "Post-coloc", rsc->allowed_nodes); - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, + for(gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; - rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( - constraint->rsc_lh, rsc->id, rsc->allowed_nodes, - constraint->node_attribute, constraint->score/INFINITY, TRUE, FALSE); - ); + rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( + constraint->rsc_lh, rsc->id, rsc->allowed_nodes, + constraint->node_attribute, constraint->score/INFINITY, TRUE, FALSE); + } - print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE); - if(rsc->next_role == RSC_ROLE_STOPPED) { - crm_debug_2("Making sure %s doesn't get allocated", rsc->id); - /* make sure it doesnt come up again */ - resource_location( - rsc, NULL, -INFINITY, XML_RSC_ATTR_TARGET_ROLE, data_set); - } - - dump_node_scores(show_scores?0:scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); - if(is_set(data_set->flags, pe_flag_stonith_enabled) - && is_set(data_set->flags, pe_flag_have_stonith_resource) == FALSE) { - clear_bit(rsc->flags, pe_rsc_managed); - } - - if(is_not_set(rsc->flags, pe_rsc_managed)) { - const char *reason = NULL; - node_t *assign_to = NULL; - if(rsc->running_on == NULL) { - reason = "inactive"; - } else if(rsc->role == RSC_ROLE_MASTER) { - assign_to = rsc->running_on->data; - reason = "master"; - } else if(is_set(rsc->flags, pe_rsc_failed)) { - reason = "failed"; - } else { - assign_to = rsc->running_on->data; - reason = "active"; - } - crm_info("Unmanaged resource %s allocated to %s: %s", rsc->id, - assign_to?assign_to->details->uname:"'nowhere'", reason); - native_assign_node(rsc, NULL, assign_to, TRUE); - - } else if(is_set(data_set->flags, pe_flag_stop_everything) - && safe_str_neq(class, "stonith")) { - crm_debug("Forcing %s to stop", rsc->id); - native_assign_node(rsc, NULL, NULL, TRUE); - - } else if(is_set(rsc->flags, pe_rsc_provisional) - && native_choose_node(rsc, data_set) ) { - crm_debug_3("Allocated resource %s to %s", - rsc->id, rsc->allocated_to->details->uname); - - } else if(rsc->allocated_to == NULL) { - if(is_not_set(rsc->flags, pe_rsc_orphan)) { - crm_info("Resource %s cannot run anywhere", rsc->id); - } else if(rsc->running_on != NULL) { - crm_info("Stopping orphan resource %s", rsc->id); - } - + print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE); + if(rsc->next_role == RSC_ROLE_STOPPED) { + crm_debug_2("Making sure %s doesn't get allocated", rsc->id); + /* make sure it doesnt come up again */ + resource_location( + rsc, NULL, -INFINITY, XML_RSC_ATTR_TARGET_ROLE, data_set); + } + + dump_node_scores(show_scores?0:scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); + if(is_set(data_set->flags, pe_flag_stonith_enabled) + && is_set(data_set->flags, pe_flag_have_stonith_resource) == FALSE) { + clear_bit(rsc->flags, pe_rsc_managed); + } + + if(is_not_set(rsc->flags, pe_rsc_managed)) { + const char *reason = NULL; + node_t *assign_to = NULL; + if(rsc->running_on == NULL) { + reason = "inactive"; + } else if(rsc->role == RSC_ROLE_MASTER) { + assign_to = rsc->running_on->data; + reason = "master"; + } else if(is_set(rsc->flags, pe_rsc_failed)) { + reason = "failed"; } else { - crm_debug("Pre-Allocated resource %s to %s", - rsc->id, rsc->allocated_to->details->uname); + assign_to = rsc->running_on->data; + reason = "active"; + } + crm_info("Unmanaged resource %s allocated to %s: %s", rsc->id, + assign_to?assign_to->details->uname:"'nowhere'", reason); + native_assign_node(rsc, NULL, assign_to, TRUE); + + } else if(is_set(data_set->flags, pe_flag_stop_everything) + && safe_str_neq(class, "stonith")) { + crm_debug("Forcing %s to stop", rsc->id); + native_assign_node(rsc, NULL, NULL, TRUE); + + } else if(is_set(rsc->flags, pe_rsc_provisional) + && native_choose_node(rsc, data_set) ) { + crm_debug_3("Allocated resource %s to %s", + rsc->id, rsc->allocated_to->details->uname); + + } else if(rsc->allocated_to == NULL) { + if(is_not_set(rsc->flags, pe_rsc_orphan)) { + crm_info("Resource %s cannot run anywhere", rsc->id); + } else if(rsc->running_on != NULL) { + crm_info("Stopping orphan resource %s", rsc->id); } + + } else { + crm_debug("Pre-Allocated resource %s to %s", + rsc->id, rsc->allocated_to->details->uname); + } - clear_bit(rsc->flags, pe_rsc_allocating); - print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE); + clear_bit(rsc->flags, pe_rsc_allocating); + print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE); - return rsc->allocated_to; + return rsc->allocated_to; } static gboolean is_op_dup( resource_t *rsc, const char *name, const char *interval) { gboolean dup = FALSE; const char *id = NULL; const char *value = NULL; xml_child_iter_filter( rsc->ops_xml, operation, "op", value = crm_element_value(operation, "name"); if(safe_str_neq(value, name)) { continue; } value = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); if(value == NULL) { value = "0"; } if(safe_str_neq(value, interval)) { continue; } if(id == NULL) { id = ID(operation); } else { crm_config_err("Operation %s is a duplicate of %s", ID(operation), id); crm_config_err("Do not use the same (name, interval) combination more than once per resource"); dup = TRUE; } ); return dup; } void RecurringOp(resource_t *rsc, action_t *start, node_t *node, xmlNode *operation, 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; + char *key = NULL; + const char *name = NULL; + const char *value = NULL; + const char *interval = NULL; + const char *node_uname = NULL; - unsigned long long interval_ms = 0; - action_t *mon = NULL; - gboolean is_optional = TRUE; - GListPtr possible_matches = NULL; + unsigned long long interval_ms = 0; + action_t *mon = NULL; + gboolean is_optional = TRUE; + GListPtr possible_matches = NULL; - crm_debug_2("Creating recurring action %s for %s in role %s", - ID(operation), rsc->id, role2text(rsc->next_role)); + crm_debug_2("Creating recurring action %s for %s in role %s", + ID(operation), rsc->id, role2text(rsc->next_role)); - if(node != NULL) { - node_uname = node->details->uname; - } + if(node != NULL) { + node_uname = node->details->uname; + } - interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); - interval_ms = crm_get_interval(interval); + interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); + interval_ms = crm_get_interval(interval); - if(interval_ms == 0) { - return; - } + if(interval_ms == 0) { + return; + } - name = crm_element_value(operation, "name"); - if(is_op_dup(rsc, name, interval)) { - return; - } + name = crm_element_value(operation, "name"); + if(is_op_dup(rsc, name, interval)) { + return; + } - if(safe_str_eq(name, RSC_STOP) - || safe_str_eq(name, RSC_START) - || safe_str_eq(name, RSC_DEMOTE) - || safe_str_eq(name, RSC_PROMOTE) - ) { - crm_config_err("Invalid recurring action %s wth name: '%s'", - ID(operation), name); - return; - } + if(safe_str_eq(name, RSC_STOP) + || safe_str_eq(name, RSC_START) + || safe_str_eq(name, RSC_DEMOTE) + || safe_str_eq(name, RSC_PROMOTE) + ) { + crm_config_err("Invalid recurring action %s wth name: '%s'", + ID(operation), name); + return; + } - key = generate_op_key(rsc->id, name, interval_ms); - if(find_rsc_op_entry(rsc, key) == NULL) { - /* disabled */ - crm_free(key); - return; - } + key = generate_op_key(rsc->id, name, interval_ms); + if(find_rsc_op_entry(rsc, key) == NULL) { + /* disabled */ + crm_free(key); + return; + } - if(start != NULL) { - crm_debug_3("Marking %s %s due to %s", - key, is_set(start->flags, pe_action_optional)?"optional":"manditory", - start->uuid); - is_optional = (get_action_flags(start, NULL) & pe_action_optional); - } else { - crm_debug_2("Marking %s optional", key); - is_optional = TRUE; - } + if(start != NULL) { + crm_debug_3("Marking %s %s due to %s", + key, is_set(start->flags, pe_action_optional)?"optional":"manditory", + start->uuid); + is_optional = (get_action_flags(start, NULL) & pe_action_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); - } else { - g_list_free(possible_matches); - } - - 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 *result = "Ignoring"; - if(is_optional) { - char *local_key = crm_strdup(key); - log_level = LOG_INFO; - result = "Cancelling"; - /* its running : cancel it */ + /* 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); + } else { + g_list_free(possible_matches); + } + + 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 *result = "Ignoring"; + if(is_optional) { + char *local_key = crm_strdup(key); + log_level = LOG_INFO; + result = "Cancelling"; + /* its running : cancel it */ - mon = custom_action( - rsc, local_key, RSC_CANCEL, node, - FALSE, TRUE, data_set); - - crm_free(mon->task); - mon->task = crm_strdup(RSC_CANCEL); - add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval); - add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name); - - local_key = NULL; - - switch(rsc->role) { - case RSC_ROLE_SLAVE: - case RSC_ROLE_STARTED: - if(rsc->next_role == RSC_ROLE_MASTER) { - local_key = promote_key(rsc); - - } else if(rsc->next_role == RSC_ROLE_STOPPED) { - local_key = stop_key(rsc); - } + mon = custom_action( + rsc, local_key, RSC_CANCEL, node, + FALSE, TRUE, data_set); + + crm_free(mon->task); + mon->task = crm_strdup(RSC_CANCEL); + add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval); + add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name); + + local_key = NULL; + + switch(rsc->role) { + case RSC_ROLE_SLAVE: + case RSC_ROLE_STARTED: + if(rsc->next_role == RSC_ROLE_MASTER) { + local_key = promote_key(rsc); + + } else if(rsc->next_role == RSC_ROLE_STOPPED) { + local_key = stop_key(rsc); + } - break; - case RSC_ROLE_MASTER: - local_key = demote_key(rsc); - break; - default: - break; - } + break; + case RSC_ROLE_MASTER: + local_key = demote_key(rsc); + break; + default: + break; + } - if(local_key) { - custom_action_order(rsc, NULL, mon, rsc, local_key, NULL, - pe_order_runnable_left, data_set); - } + if(local_key) { + custom_action_order(rsc, NULL, mon, rsc, local_key, NULL, + pe_order_runnable_left, data_set); + } - mon = NULL; - } + mon = NULL; + } - do_crm_log(log_level, "%s action %s (%s vs. %s)", - result , key, value?value:role2text(RSC_ROLE_SLAVE), - role2text(rsc->next_role)); - - crm_free(key); - key = NULL; - return; - } + do_crm_log(log_level, "%s action %s (%s vs. %s)", + result , key, value?value:role2text(RSC_ROLE_SLAVE), + role2text(rsc->next_role)); + + crm_free(key); + key = NULL; + return; + } - mon = custom_action(rsc, key, name, node, - is_optional, TRUE, data_set); - key = mon->uuid; - if(is_optional) { - crm_debug_2("%s\t %s (optional)", - crm_str(node_uname), mon->uuid); - } + mon = custom_action(rsc, key, name, node, + is_optional, TRUE, data_set); + key = mon->uuid; + if(is_optional) { + crm_debug_2("%s\t %s (optional)", + crm_str(node_uname), mon->uuid); + } - if(start == NULL || is_set(start->flags, pe_action_runnable) == FALSE) { - crm_debug("%s\t %s (cancelled : start un-runnable)", - crm_str(node_uname), mon->uuid); - update_action_flags(mon, pe_action_runnable|pe_action_clear); + if(start == NULL || is_set(start->flags, pe_action_runnable) == FALSE) { + crm_debug("%s\t %s (cancelled : start un-runnable)", + crm_str(node_uname), mon->uuid); + update_action_flags(mon, pe_action_runnable|pe_action_clear); - } 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); - update_action_flags(mon, pe_action_runnable|pe_action_clear); + } 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); + update_action_flags(mon, pe_action_runnable|pe_action_clear); - } else if(is_set(mon->flags, pe_action_optional) == FALSE) { - crm_notice(" Start recurring %s (%llus) for %s on %s", mon->task, interval_ms/1000, rsc->id, crm_str(node_uname)); - } + } else if(is_set(mon->flags, pe_action_optional) == FALSE) { + crm_notice(" Start recurring %s (%llus) for %s on %s", mon->task, interval_ms/1000, rsc->id, crm_str(node_uname)); + } - if(rsc->next_role == RSC_ROLE_MASTER) { - char *running_master = crm_itoa(EXECRA_RUNNING_MASTER); - add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master); - crm_free(running_master); - } + if(rsc->next_role == RSC_ROLE_MASTER) { + char *running_master = crm_itoa(EXECRA_RUNNING_MASTER); + add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master); + crm_free(running_master); + } - if(node == NULL || is_set(rsc->flags, pe_rsc_managed)) { - custom_action_order(rsc, start_key(rsc), NULL, + if(node == NULL || is_set(rsc->flags, pe_rsc_managed)) { + custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_order_implies_then|pe_order_runnable_left, data_set); - if(rsc->next_role == RSC_ROLE_MASTER) { - custom_action_order( - rsc, promote_key(rsc), NULL, - rsc, NULL, mon, - pe_order_optional|pe_order_runnable_left, data_set); - - } else if(rsc->role == RSC_ROLE_MASTER) { - custom_action_order( - rsc, demote_key(rsc), NULL, - rsc, NULL, mon, - pe_order_optional|pe_order_runnable_left, data_set); - } + if(rsc->next_role == RSC_ROLE_MASTER) { + custom_action_order( + rsc, promote_key(rsc), NULL, + rsc, NULL, mon, + pe_order_optional|pe_order_runnable_left, data_set); + + } else if(rsc->role == RSC_ROLE_MASTER) { + custom_action_order( + rsc, demote_key(rsc), NULL, + rsc, NULL, mon, + pe_order_optional|pe_order_runnable_left, data_set); } + } } void Recurring(resource_t *rsc, action_t *start, node_t *node, - pe_working_set_t *data_set) + pe_working_set_t *data_set) { if(is_not_set(data_set->flags, pe_flag_maintenance_mode)) { xml_child_iter_filter( - rsc->ops_xml, operation, "op", - RecurringOp(rsc, start, node, operation, data_set); - ); + rsc->ops_xml, operation, "op", + RecurringOp(rsc, start, node, operation, data_set); + ); } } 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; + action_t *start = NULL; + node_t *chosen = NULL; + GListPtr gIter = NULL; + enum rsc_role_e role = RSC_ROLE_UNKNOWN; + enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; - crm_debug_2("Createing actions for %s: %s->%s", rsc->id, - role2text(rsc->role), role2text(rsc->next_role)); + crm_debug_2("Createing actions for %s: %s->%s", rsc->id, + role2text(rsc->role), role2text(rsc->next_role)); - chosen = rsc->allocated_to; - if(chosen != NULL && rsc->next_role == RSC_ROLE_UNKNOWN) { - rsc->next_role = RSC_ROLE_STARTED; + chosen = rsc->allocated_to; + if(chosen != NULL && rsc->next_role == RSC_ROLE_UNKNOWN) { + rsc->next_role = RSC_ROLE_STARTED; - } else if(rsc->next_role == RSC_ROLE_UNKNOWN) { - rsc->next_role = RSC_ROLE_STOPPED; - } + } else if(rsc->next_role == RSC_ROLE_UNKNOWN) { + rsc->next_role = RSC_ROLE_STOPPED; + } - get_rsc_attributes(rsc->parameters, rsc, chosen, data_set); + get_rsc_attributes(rsc->parameters, rsc, chosen, data_set); - slist_iter( - current, node_t, rsc->dangling_migrations, lpc, + for(gIter = rsc->dangling_migrations; gIter != NULL; gIter = gIter->next) { + node_t *current = (node_t*)gIter->data; - action_t *stop = stop_action(rsc, current, FALSE); - set_bit_inplace(stop->flags, pe_action_dangle); - crm_trace("Forcing a cleanup of %s on %s", rsc->id, current->details->uname); + action_t *stop = stop_action(rsc, current, FALSE); + set_bit_inplace(stop->flags, pe_action_dangle); + crm_trace("Forcing a cleanup of %s on %s", rsc->id, current->details->uname); - if(is_set(data_set->flags, pe_flag_remove_after_stop)) { - DeleteRsc(rsc, current, FALSE, data_set); - } - ); + if(is_set(data_set->flags, pe_flag_remove_after_stop)) { + DeleteRsc(rsc, current, FALSE, data_set); + } + } - if(g_list_length(rsc->running_on) > 1) { - if(rsc->recovery_type == recovery_stop_start) { - pe_proc_warn("Attempting recovery of resource %s", rsc->id); - if(rsc->role == RSC_ROLE_MASTER) { - DemoteRsc(rsc, NULL, FALSE, data_set); - } - StopRsc(rsc, NULL, FALSE, data_set); - rsc->role = RSC_ROLE_STOPPED; - } + if(g_list_length(rsc->running_on) > 1) { + if(rsc->recovery_type == recovery_stop_start) { + pe_proc_warn("Attempting recovery of resource %s", rsc->id); + if(rsc->role == RSC_ROLE_MASTER) { + DemoteRsc(rsc, NULL, FALSE, data_set); + } + StopRsc(rsc, NULL, FALSE, 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, - update_action_flags(action, pe_action_optional); -/* action->pseudo = TRUE; */ - ); - g_list_free(possible_matches); - crm_debug_2("Stopping a stopped resource"); - crm_free(key); - goto do_recurring; + } 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); + GListPtr gIter = NULL; + for(gIter = possible_matches; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; - } else if(rsc->role != RSC_ROLE_STOPPED) { - /* A cheap trick to account for the fact that Master/Slave groups may not be - * completely running when we set their role to Slave - */ - crm_debug_2("Resetting %s.role = %s (was %s)", - rsc->id, role2text(RSC_ROLE_STOPPED), role2text(rsc->role)); - rsc->role = RSC_ROLE_STOPPED; + update_action_flags(action, pe_action_optional); +/* action->pseudo = TRUE; */ } + + g_list_free(possible_matches); + crm_debug_2("Stopping a stopped resource"); + crm_free(key); + goto do_recurring; + + } else if(rsc->role != RSC_ROLE_STOPPED) { + /* A cheap trick to account for the fact that Master/Slave groups may not be + * completely running when we set their role to Slave + */ + crm_debug_2("Resetting %s.role = %s (was %s)", + rsc->id, role2text(RSC_ROLE_STOPPED), role2text(rsc->role)); + rsc->role = RSC_ROLE_STOPPED; + } - role = rsc->role; + 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, FALSE, data_set) == FALSE) { - break; - } - role = next_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, FALSE, data_set) == FALSE) { + break; } + role = next_role; + } do_recurring: - if(rsc->next_role != RSC_ROLE_STOPPED || is_set(rsc->flags, pe_rsc_managed) == FALSE) { - start = start_action(rsc, chosen, TRUE); - Recurring(rsc, start, chosen, data_set); - } + if(rsc->next_role != RSC_ROLE_STOPPED || is_set(rsc->flags, pe_rsc_managed) == FALSE) { + 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) { - /* This function is on the critical path and worth optimizing as much as possible */ + /* This function is on the critical path and worth optimizing as much as possible */ - resource_t *top = uber_parent(rsc); - int type = pe_order_optional|pe_order_implies_then|pe_order_restart; - const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + resource_t *top = uber_parent(rsc); + int type = pe_order_optional|pe_order_implies_then|pe_order_restart; + const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - custom_action_order(rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL, - rsc, generate_op_key(rsc->id, RSC_START, 0), NULL, - type, data_set); + custom_action_order(rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL, + rsc, generate_op_key(rsc->id, RSC_START, 0), NULL, + type, data_set); - if(top->variant == pe_master) { - custom_action_order(rsc, generate_op_key(rsc->id, RSC_DEMOTE, 0), NULL, - rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL, - pe_order_optional, data_set); + if(top->variant == pe_master) { + custom_action_order(rsc, generate_op_key(rsc->id, RSC_DEMOTE, 0), NULL, + rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL, + pe_order_optional, data_set); - custom_action_order(rsc, generate_op_key(rsc->id, RSC_START, 0), NULL, - rsc, generate_op_key(rsc->id, RSC_PROMOTE, 0), NULL, - pe_order_runnable_left, data_set); - } + custom_action_order(rsc, generate_op_key(rsc->id, RSC_START, 0), NULL, + rsc, generate_op_key(rsc->id, RSC_PROMOTE, 0), NULL, + pe_order_runnable_left, data_set); + } - if(is_not_set(rsc->flags, pe_rsc_managed)) { - crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); - return; - } - - if(safe_str_neq(class, "stonith")) { - action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); - custom_action_order( - rsc, stop_key(rsc), NULL, - NULL, crm_strdup(all_stopped->task), all_stopped, - pe_order_implies_then|pe_order_runnable_left, data_set); - } + if(is_not_set(rsc->flags, pe_rsc_managed)) { + crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); + return; + } + + if(safe_str_neq(class, "stonith")) { + action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); + custom_action_order( + rsc, stop_key(rsc), NULL, + NULL, crm_strdup(all_stopped->task), all_stopped, + pe_order_implies_then|pe_order_runnable_left, data_set); + } - if (g_hash_table_size(rsc->utilization) > 0 - && safe_str_neq(data_set->placement_strategy, "default")) { - GHashTableIter iter; - node_t *next = NULL; + if (g_hash_table_size(rsc->utilization) > 0 + && safe_str_neq(data_set->placement_strategy, "default")) { + GHashTableIter iter; + node_t *next = NULL; + GListPtr gIter = NULL; - crm_trace("Creating utilization constraints for %s - strategy: %s", - rsc->id, data_set->placement_strategy); + crm_trace("Creating utilization constraints for %s - strategy: %s", + rsc->id, data_set->placement_strategy); - slist_iter( - current, node_t, rsc->running_on, lpc, + for(gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) { + node_t *current = (node_t*)gIter->data; - char *load_stopped_task = crm_concat(LOAD_STOPPED, current->details->uname, '_'); - action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set); - if(load_stopped->node == NULL) { - load_stopped->node = node_copy(current); - update_action_flags(load_stopped, pe_action_optional|pe_action_clear); - } + char *load_stopped_task = crm_concat(LOAD_STOPPED, current->details->uname, '_'); + action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set); + if(load_stopped->node == NULL) { + load_stopped->node = node_copy(current); + update_action_flags(load_stopped, pe_action_optional|pe_action_clear); + } - custom_action_order( - rsc, stop_key(rsc), NULL, - NULL, load_stopped_task, load_stopped, - pe_order_optional, data_set); - ); - - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&next)) { - char *load_stopped_task = crm_concat(LOAD_STOPPED, next->details->uname, '_'); - action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set); - if(load_stopped->node == NULL) { - load_stopped->node = node_copy(next); - update_action_flags(load_stopped, pe_action_optional|pe_action_clear); - } + custom_action_order( + rsc, stop_key(rsc), NULL, + NULL, load_stopped_task, load_stopped, + pe_order_optional, data_set); + } - custom_action_order( - NULL, load_stopped_task, load_stopped, - rsc, start_key(rsc), NULL, - pe_order_optional, data_set); - } + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&next)) { + char *load_stopped_task = crm_concat(LOAD_STOPPED, next->details->uname, '_'); + action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set); + if(load_stopped->node == NULL) { + load_stopped->node = node_copy(next); + update_action_flags(load_stopped, pe_action_optional|pe_action_clear); + } + + custom_action_order( + NULL, load_stopped_task, load_stopped, + rsc, start_key(rsc), NULL, + pe_order_optional, data_set); } + } } void native_rsc_colocation_lh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + 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; + 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; - } + } 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); + crm_debug_2("Processing colocation constraint between %s and %s", + rsc_lh->id, rsc_rh->id); - rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); + rsc_rh->cmds->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) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - int level = LOG_DEBUG_4; - if(constraint->score == 0){ - return FALSE; - } + int level = LOG_DEBUG_4; + if(constraint->score == 0){ + return FALSE; + } - if(constraint->score > 0 - && constraint->role_lh != RSC_ROLE_UNKNOWN - && constraint->role_lh != rsc_lh->next_role) { - do_crm_log_unlikely(level, "LH: Skipping constraint: \"%s\" state filter", + if(constraint->score > 0 + && constraint->role_lh != RSC_ROLE_UNKNOWN + && constraint->role_lh != rsc_lh->next_role) { + do_crm_log_unlikely(level, "LH: Skipping constraint: \"%s\" state filter", role2text(constraint->role_rh)); - return FALSE; - } + return FALSE; + } - if(constraint->score > 0 - && constraint->role_rh != RSC_ROLE_UNKNOWN - && constraint->role_rh != rsc_rh->next_role) { - do_crm_log_unlikely(level, "RH: Skipping constraint: \"%s\" state filter", + if(constraint->score > 0 + && constraint->role_rh != RSC_ROLE_UNKNOWN + && constraint->role_rh != rsc_rh->next_role) { + do_crm_log_unlikely(level, "RH: Skipping constraint: \"%s\" state filter", role2text(constraint->role_rh)); - return FALSE; - } + return FALSE; + } - if(constraint->score < 0 - && constraint->role_lh != RSC_ROLE_UNKNOWN - && constraint->role_lh == rsc_lh->next_role) { - do_crm_log_unlikely(level, "LH: Skipping -ve constraint: \"%s\" state filter", + if(constraint->score < 0 + && constraint->role_lh != RSC_ROLE_UNKNOWN + && constraint->role_lh == rsc_lh->next_role) { + do_crm_log_unlikely(level, "LH: Skipping -ve constraint: \"%s\" state filter", role2text(constraint->role_rh)); - return FALSE; - } + return FALSE; + } - if(constraint->score < 0 - && constraint->role_rh != RSC_ROLE_UNKNOWN - && constraint->role_rh == rsc_rh->next_role) { - do_crm_log_unlikely(level, "RH: Skipping -ve constraint: \"%s\" state filter", + if(constraint->score < 0 + && constraint->role_rh != RSC_ROLE_UNKNOWN + && constraint->role_rh == rsc_rh->next_role) { + do_crm_log_unlikely(level, "RH: Skipping -ve constraint: \"%s\" state filter", role2text(constraint->role_rh)); - return FALSE; - } + return FALSE; + } - return TRUE; + return TRUE; } static void colocation_match( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - const char *tmp = NULL; - const char *value = NULL; - const char *attribute = "#id"; + const char *tmp = NULL; + const char *value = NULL; + const char *attribute = "#id"; - GHashTable *work = NULL; - gboolean do_check = FALSE; + GHashTable *work = NULL; + gboolean do_check = FALSE; - GHashTableIter iter; - node_t *node = NULL; + GHashTableIter iter; + node_t *node = NULL; - if(constraint->node_attribute != NULL) { - attribute = constraint->node_attribute; - } + if(constraint->node_attribute != NULL) { + attribute = constraint->node_attribute; + } - if(rsc_rh->allocated_to) { - value = g_hash_table_lookup( - rsc_rh->allocated_to->details->attrs, attribute); - do_check = TRUE; + if(rsc_rh->allocated_to) { + value = g_hash_table_lookup( + rsc_rh->allocated_to->details->attrs, attribute); + do_check = TRUE; - } else if(constraint->score < 0) { - /* nothing to do: - * anti-colocation with something thats not running - */ - return; - } + } else if(constraint->score < 0) { + /* nothing to do: + * anti-colocation with something thats not running + */ + return; + } - work = node_hash_dup(rsc_lh->allowed_nodes); + work = node_hash_dup(rsc_lh->allowed_nodes); - g_hash_table_iter_init (&iter, work); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - tmp = g_hash_table_lookup(node->details->attrs, attribute); - if(do_check && safe_str_eq(tmp, value)) { - if(constraint->score < INFINITY) { - crm_debug_2("%s: %s.%s += %d", constraint->id, rsc_lh->id, - node->details->uname, constraint->score); - node->weight = merge_weights( - constraint->score, node->weight); - } + g_hash_table_iter_init (&iter, work); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + tmp = g_hash_table_lookup(node->details->attrs, attribute); + if(do_check && safe_str_eq(tmp, value)) { + if(constraint->score < INFINITY) { + crm_debug_2("%s: %s.%s += %d", constraint->id, rsc_lh->id, + node->details->uname, constraint->score); + node->weight = merge_weights( + constraint->score, node->weight); + } - } else if(do_check == FALSE || constraint->score >= INFINITY) { - crm_debug_2("%s: %s.%s -= %d (%s)", constraint->id, rsc_lh->id, - node->details->uname, constraint->score, do_check?"failed":"unallocated"); - node->weight = merge_weights(-constraint->score, node->weight); - } + } else if(do_check == FALSE || constraint->score >= INFINITY) { + crm_debug_2("%s: %s.%s -= %d (%s)", constraint->id, rsc_lh->id, + node->details->uname, constraint->score, do_check?"failed":"unallocated"); + node->weight = merge_weights(-constraint->score, node->weight); } + } - if(can_run_any(work) - || constraint->score <= -INFINITY - || constraint->score >= INFINITY) { - g_hash_table_destroy(rsc_lh->allowed_nodes); - rsc_lh->allowed_nodes = work; - work = NULL; - - } else { - char *score = score2char(constraint->score); - crm_info("%s: Rolling back scores from %s (%d, %s)", - rsc_lh->id, rsc_rh->id, do_check, score); - crm_free(score); - } + if(can_run_any(work) + || constraint->score <= -INFINITY + || constraint->score >= INFINITY) { + g_hash_table_destroy(rsc_lh->allowed_nodes); + rsc_lh->allowed_nodes = work; + work = NULL; + + } else { + char *score = score2char(constraint->score); + crm_info("%s: Rolling back scores from %s (%d, %s)", + rsc_lh->id, rsc_rh->id, do_check, score); + crm_free(score); + } - if(work) { - g_hash_table_destroy(work); - } + if(work) { + g_hash_table_destroy(work); + } } void native_rsc_colocation_rh( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) + resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { - crm_debug_2("%sColocating %s with %s (%s, weight=%d)", - constraint->score >= 0?"":"Anti-", - rsc_lh->id, rsc_rh->id, constraint->id, constraint->score); + crm_debug_2("%sColocating %s with %s (%s, weight=%d)", + constraint->score >= 0?"":"Anti-", + rsc_lh->id, rsc_rh->id, constraint->id, constraint->score); - if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { - return; - } + if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { + return; + } - if(is_set(rsc_rh->flags, pe_rsc_provisional)) { - return; + if(is_set(rsc_rh->flags, pe_rsc_provisional)) { + return; - } else if(is_not_set(rsc_lh->flags, pe_rsc_provisional)) { - /* error check */ - struct node_shared_s *details_lh; - struct node_shared_s *details_rh; - if((constraint->score > -INFINITY) && (constraint->score < INFINITY)) { - return; - } + } else if(is_not_set(rsc_lh->flags, pe_rsc_provisional)) { + /* error check */ + struct node_shared_s *details_lh; + struct node_shared_s *details_rh; + if((constraint->score > -INFINITY) && (constraint->score < INFINITY)) { + return; + } - details_rh = rsc_rh->allocated_to?rsc_rh->allocated_to->details:NULL; - details_lh = rsc_lh->allocated_to?rsc_lh->allocated_to->details:NULL; + details_rh = rsc_rh->allocated_to?rsc_rh->allocated_to->details:NULL; + details_lh = rsc_lh->allocated_to?rsc_lh->allocated_to->details:NULL; - if(constraint->score == INFINITY && details_lh != details_rh) { - crm_err("%s and %s are both allocated" - " but to different nodes: %s vs. %s", - rsc_lh->id, rsc_rh->id, - details_lh?details_lh->uname:"n/a", - details_rh?details_rh->uname:"n/a"); - - } else if(constraint->score == -INFINITY && details_lh == details_rh) { - crm_err("%s and %s are both allocated" - " but to the SAME node: %s", - rsc_lh->id, rsc_rh->id, - details_rh?details_rh->uname:"n/a"); - } + if(constraint->score == INFINITY && details_lh != details_rh) { + crm_err("%s and %s are both allocated" + " but to different nodes: %s vs. %s", + rsc_lh->id, rsc_rh->id, + details_lh?details_lh->uname:"n/a", + details_rh?details_rh->uname:"n/a"); + + } else if(constraint->score == -INFINITY && details_lh == details_rh) { + crm_err("%s and %s are both allocated" + " but to the SAME node: %s", + rsc_lh->id, rsc_rh->id, + details_rh?details_rh->uname:"n/a"); + } - return; + return; - } else { - colocation_match(rsc_lh, rsc_rh, constraint); - } + } else { + colocation_match(rsc_lh, rsc_rh, constraint); + } } const char *convert_non_atomic_task(char *raw_task, resource_t *rsc, gboolean allow_notify); const char * convert_non_atomic_task(char *raw_task, resource_t *rsc, gboolean allow_notify) { int task = no_action; const char *atomic_task = raw_task; crm_trace("Processing %s for %s", crm_str(raw_task), rsc->id); if(raw_task == NULL) { return NULL; } else if(strstr(raw_task, "notify") != NULL) { goto done; /* no conversion */ } else if(rsc->variant < pe_group) { goto done; /* no conversion */ } task = text2task(raw_task); switch(task) { case stop_rsc: case start_rsc: case action_notify: case action_promote: case action_demote: break; case stopped_rsc: case started_rsc: case action_notified: case action_promoted: case action_demoted: task--; break; case monitor_rsc: case shutdown_crm: case stonith_node: goto done; break; default: crm_trace("Unknown action: %s", raw_task); goto done; break; } if(task != no_action) { if(is_set(rsc->flags, pe_rsc_notify) && allow_notify) { /* atomic_task = generate_notify_key(rid, "confirmed-post", task2text(task+1)); */ crm_err("Not handled"); } else { atomic_task = task2text(task+1); } crm_trace("Converted %s -> %s", raw_task, atomic_task); } done: return atomic_task; } enum pe_action_flags native_action_flags(action_t *action, node_t *node) { return action->flags; } enum pe_graph_flags native_update_actions( action_t *first, action_t *then, node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type) { enum pe_graph_flags changed = pe_graph_none; enum pe_action_flags then_flags = then->flags; enum pe_action_flags first_flags = first->flags; if(type & pe_order_implies_first) { if((filter & pe_action_optional) && (flags & pe_action_optional) == 0) { clear_bit_inplace(first->flags, pe_action_optional); } } if(is_set(type, pe_order_runnable_left) && is_set(filter, pe_action_runnable) && is_set(flags, pe_action_runnable) == FALSE) { clear_bit_inplace(then->flags, pe_action_runnable); } if(is_set(type, pe_order_implies_then) && is_set(filter, pe_action_optional) && is_set(flags, pe_action_optional) == FALSE) { clear_bit_inplace(then->flags, pe_action_optional); } if(is_set(type, pe_order_restart)) { gboolean unset = FALSE; crm_trace("Handle restart 0x%.6x 0x%.6x", filter, then->flags); CRM_ASSERT(then->rsc == first->rsc); CRM_ASSERT(then->rsc->variant == pe_native); if((filter & pe_action_runnable) && (then->flags & pe_action_runnable) == 0) { crm_trace("Handling shutdown: %s -> %s %d", first->uuid, then->uuid, is_set(first->flags, pe_action_runnable)); unset = TRUE; } if((filter & pe_action_optional) && (then->flags & pe_action_optional) == 0) { crm_trace("Handling recover: %s -> %s %d", first->uuid, then->uuid, is_set(first->flags, pe_action_runnable)); unset = TRUE; } if(unset && is_set(first->flags, pe_action_runnable)) { clear_bit_inplace(first->flags, pe_action_optional); } } if(then_flags != then->flags) { changed |= pe_graph_updated_then; crm_trace("Flags for %s on %s are now 0x%.6x (were 0x%.6x)", then->uuid, then->node?then->node->details->uname:"[none]", then->flags, then_flags); } if(first_flags != first->flags) { changed |= pe_graph_updated_first; crm_trace("Flags for %s on %s are now 0x%.6x (were 0x%.6x)", first->uuid, first->node?first->node->details->uname:"[none]", first->flags, first_flags); } return changed; } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { - GHashTableIter iter; - node_t *node = NULL; + GListPtr gIter = NULL; + GHashTableIter iter; + node_t *node = NULL; - crm_debug_2("Applying %s (%s) to %s", constraint->id, - role2text(constraint->role_filter), rsc->id); + 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; + /* 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(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(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; - } + } 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; - } - + if(constraint->node_list_rh == NULL) { + crm_debug_2("RHS of constraint %s is NULL", constraint->id); + return; + } - slist_iter( - node, node_t, constraint->node_list_rh, lpc, - node_t *other_node = NULL; + for(gIter = constraint->node_list_rh; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + node_t *other_node = NULL; - other_node = (node_t*)pe_hash_table_lookup( - rsc->allowed_nodes, node->details->id); + other_node = (node_t*)pe_hash_table_lookup( + rsc->allowed_nodes, node->details->id); - if(other_node != NULL) { - crm_debug_4("%s + %s: %d + %d", - node->details->uname, - other_node->details->uname, - node->weight, other_node->weight); - other_node->weight = merge_weights( - other_node->weight, node->weight); + if(other_node != NULL) { + crm_debug_4("%s + %s: %d + %d", + node->details->uname, + other_node->details->uname, + node->weight, other_node->weight); + other_node->weight = merge_weights( + other_node->weight, node->weight); - } else { - node_t *new_node = node_copy(node); - g_hash_table_insert(rsc->allowed_nodes, (gpointer)new_node->details->id, new_node); - } - ); - - g_hash_table_iter_init (&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight); + } else { + node_t *new_node = node_copy(node); + g_hash_table_insert(rsc->allowed_nodes, (gpointer)new_node->details->id, new_node); } + } + + g_hash_table_iter_init (&iter, rsc->allowed_nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight); + } } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { - crm_debug_3("Processing actions from %s", rsc->id); + GListPtr gIter = NULL; + crm_debug_3("Processing actions from %s", rsc->id); - 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); - ); + for(gIter = rsc->actions; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + crm_debug_4("processing action %d for rsc=%s", + action->id, rsc->id); + graph_element_from_action(action, data_set); + } - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; - child_rsc->cmds->expand(child_rsc, data_set); - ); + child_rsc->cmds->expand(child_rsc, data_set); + } } void LogActions(resource_t *rsc, pe_working_set_t *data_set) { node_t *next = NULL; node_t *current = NULL; gboolean moving = FALSE; if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, + GListPtr gIter = NULL; + for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + LogActions(child_rsc, data_set); - ); + } return; } next = rsc->allocated_to; if(rsc->running_on) { current = rsc->running_on->data; if(rsc->role == RSC_ROLE_STOPPED) { /* * This can occur when resources are being recovered * We fiddle with the current role in native_create_actions() */ rsc->role = RSC_ROLE_STARTED; } } if(current == NULL && is_set(rsc->flags, pe_rsc_orphan)) { /* Don't log stopped orphans */ return; } if(is_not_set(rsc->flags, pe_rsc_managed) || (current == NULL && next == NULL)) { crm_notice("Leave resource %s\t(%s%s)", rsc->id, role2text(rsc->role), is_not_set(rsc->flags, pe_rsc_managed)?" unmanaged":""); return; } if(current != NULL && next != NULL && safe_str_neq(current->details->id, next->details->id)) { moving = TRUE; } if(rsc->role == rsc->next_role) { action_t *start = NULL; char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, next); crm_free(key); if(possible_matches) { start = possible_matches->data; g_list_free(possible_matches); } key = generate_op_key(rsc->id, CRMD_ACTION_MIGRATED, 0); possible_matches = find_actions(rsc->actions, key, next); crm_free(key); CRM_CHECK(next != NULL,); if(next == NULL) { } else if(possible_matches && current) { crm_notice("Migrate resource %s\t(%s %s -> %s)", rsc->id, role2text(rsc->role), current->details->uname, next->details->uname); g_list_free(possible_matches); } else if(start == NULL || is_set(start->flags, pe_action_optional)) { crm_notice("Leave resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else if(moving && current) { crm_notice("Move resource %s\t(%s %s -> %s)", rsc->id, role2text(rsc->role), current->details->uname, next->details->uname); } else if(is_set(rsc->flags, pe_rsc_failed)) { crm_notice("Recover resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else if(start && is_set(start->flags, pe_action_runnable) == FALSE) { crm_notice("Stop resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else { crm_notice("Restart resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } return; } if(rsc->role > RSC_ROLE_SLAVE && rsc->role > rsc->next_role) { CRM_CHECK(current != NULL,); if(current != NULL) { crm_notice("Demote %s\t(%s -> %s %s)", rsc->id, role2text(rsc->role), role2text(rsc->next_role), current->details->uname); } } if(rsc->next_role == RSC_ROLE_STOPPED || moving) { + GListPtr gIter = NULL; CRM_CHECK(current != NULL,); - slist_iter(node, node_t, rsc->running_on, lpc, - crm_notice("Stop resource %s\t(%s)", rsc->id, node->details->uname)); + for(gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + crm_notice("Stop resource %s\t(%s)", rsc->id, node->details->uname); + } } if(rsc->role == RSC_ROLE_STOPPED || moving) { CRM_CHECK(next != NULL,); if(next != NULL) { crm_notice("Start %s\t(%s)", rsc->id, next->details->uname); } } if(rsc->next_role > RSC_ROLE_SLAVE && rsc->role < rsc->next_role) { CRM_CHECK(next != NULL,); crm_notice("Promote %s\t(%s -> %s %s)", rsc->id, role2text(rsc->role), role2text(rsc->next_role), next->details->uname); } } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { - action_t *stop = NULL; - action_t *start = NULL; - GListPtr possible_matches = NULL; + GListPtr gIter = NULL; + action_t *stop = NULL; + action_t *start = NULL; + GListPtr possible_matches = NULL; - crm_debug_2("Executing: %s (role=%s)", rsc->id, role2text(rsc->next_role)); + crm_debug_2("Executing: %s (role=%s)", rsc->id, role2text(rsc->next_role)); - if(current == NULL || next == NULL) { - return; - } + if(current == NULL || next == NULL) { + return; + } - if(is_set(rsc->flags, pe_rsc_failed) - || safe_str_neq(current->details->id, next->details->id)) { + if(is_set(rsc->flags, pe_rsc_failed) + || safe_str_neq(current->details->id, next->details->id)) { - if(rsc->next_role > RSC_ROLE_STARTED) { - gboolean optional = TRUE; - if(rsc->role == RSC_ROLE_MASTER) { - optional = FALSE; - } - DemoteRsc(rsc, current, optional, data_set); - } - if(rsc->role == RSC_ROLE_MASTER) { - DemoteRsc(rsc, current, FALSE, data_set); - } - StopRsc(rsc, current, FALSE, data_set); - StartRsc(rsc, next, FALSE, data_set); - if(rsc->next_role == RSC_ROLE_MASTER) { - PromoteRsc(rsc, next, FALSE, data_set); - } + if(rsc->next_role > RSC_ROLE_STARTED) { + gboolean optional = TRUE; + if(rsc->role == RSC_ROLE_MASTER) { + optional = FALSE; + } + DemoteRsc(rsc, current, optional, data_set); + } + if(rsc->role == RSC_ROLE_MASTER) { + DemoteRsc(rsc, current, FALSE, data_set); + } + StopRsc(rsc, current, FALSE, data_set); + StartRsc(rsc, next, FALSE, data_set); + if(rsc->next_role == RSC_ROLE_MASTER) { + PromoteRsc(rsc, next, FALSE, data_set); + } - possible_matches = find_recurring_actions(rsc->actions, next); - slist_iter(match, action_t, possible_matches, lpc, - if(is_set(match->flags, pe_action_optional) == FALSE) { - crm_debug("Fixing recurring action: %s", - match->uuid); - update_action_flags(match, pe_action_optional); - } - ); - g_list_free(possible_matches); - - } else if(is_set(rsc->flags, pe_rsc_start_pending)) { - start = start_action(rsc, next, TRUE); - if(is_set(start->flags, pe_action_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; - } + possible_matches = find_recurring_actions(rsc->actions, next); + for(gIter = possible_matches; gIter != NULL; gIter = gIter->next) { + action_t *match = (action_t*)gIter->data; + if(is_set(match->flags, pe_action_optional) == FALSE) { + crm_debug("Fixing recurring action: %s", + match->uuid); + update_action_flags(match, pe_action_optional); + } + } + g_list_free(possible_matches); + } else if(is_set(rsc->flags, pe_rsc_start_pending)) { + start = start_action(rsc, next, TRUE); + if(is_set(start->flags, pe_action_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); - if(is_set(start->flags, pe_action_optional)) { - update_action_flags(stop, pe_action_optional); - } else { - update_action_flags(stop, pe_action_optional|pe_action_clear); - } - if(rsc->next_role > RSC_ROLE_STARTED) { - DemoteRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); - } - StopRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); - StartRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); - if(rsc->next_role == RSC_ROLE_MASTER) { - PromoteRsc(rsc, next, is_set(start->flags, pe_action_optional), data_set); - } + stop = stop_action(rsc, current, TRUE); + start = start_action(rsc, next, TRUE); + if(is_set(start->flags, pe_action_optional)) { + update_action_flags(stop, pe_action_optional); + } else { + update_action_flags(stop, pe_action_optional|pe_action_clear); + } + if(rsc->next_role > RSC_ROLE_STARTED) { + DemoteRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); + } + StopRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); + StartRsc(rsc, current, is_set(start->flags, pe_action_optional), data_set); + if(rsc->next_role == RSC_ROLE_MASTER) { + PromoteRsc(rsc, next, is_set(start->flags, pe_action_optional), data_set); + } - if(is_set(start->flags, pe_action_runnable) == FALSE) { - rsc->next_role = RSC_ROLE_STOPPED; - } + if(is_set(start->flags, pe_action_runnable) == FALSE) { + rsc->next_role = RSC_ROLE_STOPPED; } + } } gboolean StopRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - - crm_debug_2("Executing: %s", rsc->id); - - if(rsc->next_role == RSC_ROLE_STOPPED - && rsc->variant == pe_native - && safe_str_eq(class, "stonith")) { - action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); - custom_action_order( - NULL, crm_strdup(all_stopped->task), all_stopped, - rsc, stop_key(rsc), NULL, - pe_order_optional|pe_order_stonith_stop, data_set); - } + GListPtr gIter = NULL; + const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + + crm_debug_2("Executing: %s", rsc->id); + + if(rsc->next_role == RSC_ROLE_STOPPED + && rsc->variant == pe_native + && safe_str_eq(class, "stonith")) { + action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); + custom_action_order( + NULL, crm_strdup(all_stopped->task), all_stopped, + rsc, stop_key(rsc), NULL, + pe_order_optional|pe_order_stonith_stop, data_set); + } - slist_iter( - current, node_t, rsc->running_on, lpc, - stop_action(rsc, current, optional); + for(gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) { + node_t *current = (node_t*)gIter->data; + + stop_action(rsc, current, optional); - if(is_set(data_set->flags, pe_flag_remove_after_stop)) { - DeleteRsc(rsc, current, optional, data_set); - } - ); + if(is_set(data_set->flags, pe_flag_remove_after_stop)) { + DeleteRsc(rsc, current, optional, data_set); + } + } - return TRUE; + return TRUE; } gboolean StartRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - action_t *start = NULL; + action_t *start = NULL; - crm_debug_2("Executing: %s", rsc->id); - start = start_action(rsc, next, TRUE); - if(is_set(start->flags, pe_action_runnable) && optional == FALSE) { - update_action_flags(start, pe_action_optional|pe_action_clear); - } - return TRUE; + crm_debug_2("Executing: %s", rsc->id); + start = start_action(rsc, next, TRUE); + if(is_set(start->flags, pe_action_runnable) && optional == FALSE) { + update_action_flags(start, pe_action_optional|pe_action_clear); + } + return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - char *key = NULL; - gboolean runnable = TRUE; - GListPtr action_list = NULL; - crm_debug_2("Executing: %s", rsc->id); - - CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, - crm_err("Next role: %s", role2text(rsc->next_role)); - return FALSE); + char *key = NULL; + GListPtr gIter = NULL; + gboolean runnable = TRUE; + GListPtr action_list = NULL; + crm_debug_2("Executing: %s", rsc->id); - CRM_CHECK(next != NULL, return FALSE); + CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, + crm_err("Next role: %s", role2text(rsc->next_role)); + return FALSE); - key = start_key(rsc); - action_list = find_actions_exact(rsc->actions, key, next); - crm_free(key); + CRM_CHECK(next != NULL, return FALSE); - slist_iter(start, action_t, action_list, lpc, - if(is_set(start->flags, pe_action_runnable) == FALSE) { - runnable = FALSE; - } - ); + key = start_key(rsc); + action_list = find_actions_exact(rsc->actions, key, next); + crm_free(key); - g_list_free(action_list); + for(gIter = action_list; gIter != NULL; gIter = gIter->next) { + action_t *start = (action_t*)gIter->data; + + if(is_set(start->flags, pe_action_runnable) == FALSE) { + runnable = FALSE; + } + } + g_list_free(action_list); - if(runnable) { - promote_action(rsc, next, optional); - return TRUE; - } + if(runnable) { + promote_action(rsc, next, optional); + return TRUE; + } - crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id); + crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id); - key = promote_key(rsc); - action_list = find_actions_exact(rsc->actions, key, next); - crm_free(key); + key = promote_key(rsc); + action_list = find_actions_exact(rsc->actions, key, next); + crm_free(key); - slist_iter(promote, action_t, action_list, lpc, - update_action_flags(promote, pe_action_runnable|pe_action_clear); - ); + for(gIter = action_list; gIter != NULL; gIter = gIter->next) { + action_t *promote = (action_t*)gIter->data; + update_action_flags(promote, pe_action_runnable|pe_action_clear); + } - g_list_free(action_list); - return TRUE; + g_list_free(action_list); + return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - crm_debug_2("Executing: %s", rsc->id); + GListPtr gIter = NULL; + 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, - demote_action(rsc, current, optional); - ); - return TRUE; + for(gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) { + node_t *current = (node_t*)gIter->data; + + demote_action(rsc, current, optional); + } + return TRUE; } gboolean RoleError(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - crm_debug("Executing: %s", rsc->id); - CRM_CHECK(FALSE, return FALSE); - return FALSE; + crm_debug("Executing: %s", rsc->id); + CRM_CHECK(FALSE, return FALSE); + return FALSE; } gboolean NullOp(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { - crm_debug_2("Executing: %s", rsc->id); - return FALSE; + crm_debug_2("Executing: %s", rsc->id); + return FALSE; } gboolean DeleteRsc(resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set) { - action_t *delete = NULL; + action_t *delete = NULL; #if DELETE_THEN_REFRESH - action_t *refresh = NULL; + action_t *refresh = NULL; #endif - if(is_set(rsc->flags, pe_rsc_failed)) { - crm_debug_2("Resource %s not deleted from %s: failed", - rsc->id, node->details->uname); - return FALSE; + if(is_set(rsc->flags, pe_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 == 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; - } + } 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; + } - crm_notice("Removing %s from %s", - rsc->id, node->details->uname); + crm_notice("Removing %s from %s", + rsc->id, node->details->uname); - delete = delete_action(rsc, node, optional); + delete = delete_action(rsc, node, optional); - new_rsc_order(rsc, RSC_STOP, rsc, RSC_DELETE, - optional?pe_order_implies_then:pe_order_optional, data_set); + new_rsc_order(rsc, RSC_STOP, rsc, RSC_DELETE, + optional?pe_order_implies_then:pe_order_optional, data_set); - new_rsc_order(rsc, RSC_DELETE, rsc, RSC_START, - optional?pe_order_implies_then:pe_order_optional, data_set); + new_rsc_order(rsc, RSC_DELETE, rsc, RSC_START, + optional?pe_order_implies_then:pe_order_optional, 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); + refresh = custom_action( + NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, + node, FALSE, TRUE, data_set); - add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); + add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - order_actions(delete, refresh, pe_order_optional); + order_actions(delete, refresh, pe_order_optional); #endif - return TRUE; + return TRUE; } #include <../lib/pengine/unpack.h> static node_t * probe_grouped_clone(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { node_t *running = NULL; resource_t *top = uber_parent(rsc); if(running == NULL && is_set(top->flags, pe_rsc_unique) == FALSE) { /* Annoyingly we also need to check any other clone instances * Clumsy, but it will work. * * An alternative would be to update known_on for every peer * during process_rsc_state() * * This code desperately needs optimization * ptest -x with 100 nodes, 100 clones and clone-max=10: * No probes O(25s) * Detection without clone loop O(3m) * Detection with clone loop O(8m) ptest[32211]: 2010/02/18_14:27:55 CRIT: stage5: Probing for unknown resources ptest[32211]: 2010/02/18_14:33:39 CRIT: stage5: Done ptest[32211]: 2010/02/18_14:35:05 CRIT: stage7: Updating action states ptest[32211]: 2010/02/18_14:35:05 CRIT: stage7: Done */ char *clone_id = clone_zero(rsc->id); resource_t *peer = pe_find_resource(top->children, clone_id); while(peer && running == NULL) { running = pe_hash_table_lookup(peer->known_on, node->details->id); if(running != NULL) { /* we already know the status of the resource on this node */ crm_debug_3("Skipping active clone: %s", rsc->id); crm_free(clone_id); return running; } clone_id = increment_clone(clone_id); peer = pe_find_resource(data_set->resources, clone_id); } crm_free(clone_id); } return running; } gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { - char *key = NULL; - action_t *probe = NULL; - node_t *running = NULL; - resource_t *top = uber_parent(rsc); + char *key = NULL; + action_t *probe = NULL; + node_t *running = NULL; + resource_t *top = uber_parent(rsc); - static const char *rc_master = NULL; - static const char *rc_inactive = NULL; + static const char *rc_master = NULL; + static const char *rc_inactive = NULL; - if(rc_inactive == NULL) { - rc_inactive = crm_itoa(EXECRA_NOT_RUNNING); - rc_master = crm_itoa(EXECRA_RUNNING_MASTER); - } + if(rc_inactive == NULL) { + rc_inactive = crm_itoa(EXECRA_NOT_RUNNING); + rc_master = crm_itoa(EXECRA_RUNNING_MASTER); + } - CRM_CHECK(node != NULL, return FALSE); - if(force == FALSE && is_not_set(data_set->flags, pe_flag_startup_probes)) { - crm_debug_2("Skipping active resource detection for %s", rsc->id); - return FALSE; - } + CRM_CHECK(node != NULL, return FALSE); + if(force == FALSE && is_not_set(data_set->flags, pe_flag_startup_probes)) { + crm_debug_2("Skipping active resource detection for %s", rsc->id); + return FALSE; + } - if(rsc->children) { - gboolean any_created = FALSE; + if(rsc->children) { + GListPtr gIter = NULL; + gboolean any_created = FALSE; - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - - any_created = child_rsc->cmds->create_probe( - child_rsc, node, complete, force, data_set) || any_created; - ); - - return any_created; + for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + any_created = child_rsc->cmds->create_probe( + child_rsc, node, complete, force, data_set) || any_created; } - if(is_set(rsc->flags, pe_rsc_orphan)) { - crm_debug_2("Skipping orphan: %s", rsc->id); - return FALSE; - } + return any_created; + } - running = g_hash_table_lookup(rsc->known_on, node->details->id); - if(running == NULL && is_set(rsc->flags, pe_rsc_unique) == FALSE) { - /* Anonymous clones */ - if(rsc->parent == top) { - running = g_hash_table_lookup(rsc->parent->known_on, node->details->id); + if(is_set(rsc->flags, pe_rsc_orphan)) { + crm_debug_2("Skipping orphan: %s", rsc->id); + return FALSE; + } + + running = g_hash_table_lookup(rsc->known_on, node->details->id); + if(running == NULL && is_set(rsc->flags, pe_rsc_unique) == FALSE) { + /* Anonymous clones */ + if(rsc->parent == top) { + running = g_hash_table_lookup(rsc->parent->known_on, node->details->id); - } else { - /* Grouped anonymous clones need extra special handling */ - running = probe_grouped_clone(rsc, node, data_set); - } + } else { + /* Grouped anonymous clones need extra special handling */ + running = probe_grouped_clone(rsc, node, data_set); } + } - if(force == FALSE && running != NULL) { - /* we already know the status of the resource on this node */ - crm_debug_3("Skipping active: %s", rsc->id); - return FALSE; - } + if(force == FALSE && running != NULL) { + /* we already know the status of the resource on this node */ + crm_debug_3("Skipping active: %s", rsc->id); + return FALSE; + } - key = generate_op_key(rsc->id, RSC_STATUS, 0); - probe = custom_action(rsc, key, RSC_STATUS, node, FALSE, TRUE, data_set); - update_action_flags(probe, pe_action_optional|pe_action_clear); + key = generate_op_key(rsc->id, RSC_STATUS, 0); + probe = custom_action(rsc, key, RSC_STATUS, node, FALSE, TRUE, data_set); + update_action_flags(probe, pe_action_optional|pe_action_clear); - if(running == NULL) { - add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_inactive); + if(running == NULL) { + add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_inactive); - } else if(rsc->role == RSC_ROLE_MASTER) { - add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_master); - } + } else if(rsc->role == RSC_ROLE_MASTER) { + add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_master); + } - crm_debug("Probing %s on %s (%s)", rsc->id, node->details->uname, role2text(rsc->role)); - order_actions(probe, complete, pe_order_implies_then); + crm_debug("Probing %s on %s (%s)", rsc->id, node->details->uname, role2text(rsc->role)); + order_actions(probe, complete, pe_order_implies_then); - return TRUE; + return TRUE; } static void native_start_constraints( - resource_t *rsc, action_t *stonith_op, gboolean is_stonith, - pe_working_set_t *data_set) + resource_t *rsc, action_t *stonith_op, gboolean is_stonith, + pe_working_set_t *data_set) { - node_t *target = stonith_op?stonith_op->node:NULL; + node_t *target = stonith_op?stonith_op->node:NULL; - if(is_stonith) { - char *key = start_key(rsc); - action_t *ready = get_pseudo_op(STONITH_UP, data_set); + if(is_stonith) { + char *key = start_key(rsc); + action_t *ready = get_pseudo_op(STONITH_UP, data_set); - crm_debug_2("Ordering %s action before stonith events", key); - custom_action_order( - rsc, key, NULL, - NULL, crm_strdup(ready->task), ready, - pe_order_optional|pe_order_implies_then, data_set); + crm_debug_2("Ordering %s action before stonith events", key); + custom_action_order( + rsc, key, NULL, + NULL, crm_strdup(ready->task), ready, + pe_order_optional|pe_order_implies_then, data_set); - } else { - action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); - action_t *stonith_done = get_pseudo_op(STONITH_DONE, data_set); - slist_iter(action, action_t, rsc->actions, lpc2, - if(action->needs == rsc_req_stonith) { - order_actions(stonith_done, action, pe_order_optional); - - } else if(target != NULL - && safe_str_eq(action->task, RSC_START) - && NULL == pe_hash_table_lookup(rsc->known_on, target->details->id)) { - /* if known == NULL, then we dont know if - * the resource is active on the node - * we're about to shoot - * - * in this case, regardless of action->needs, - * the only safe option is to wait until - * the node is shot before doing anything - * to with the resource - * - * its analogous to waiting for all the probes - * for rscX to complete before starting rscX - * - * the most likely explaination is that the - * DC died and took its status with it - */ + } else { + GListPtr gIter = NULL; + action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); + action_t *stonith_done = get_pseudo_op(STONITH_DONE, data_set); + for(gIter = rsc->actions; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + + if(action->needs == rsc_req_stonith) { + order_actions(stonith_done, action, pe_order_optional); + + } else if(target != NULL + && safe_str_eq(action->task, RSC_START) + && NULL == pe_hash_table_lookup(rsc->known_on, target->details->id)) { + /* if known == NULL, then we dont know if + * the resource is active on the node + * we're about to shoot + * + * in this case, regardless of action->needs, + * the only safe option is to wait until + * the node is shot before doing anything + * to with the resource + * + * its analogous to waiting for all the probes + * for rscX to complete before starting rscX + * + * the most likely explaination is that the + * DC died and took its status with it + */ - crm_debug("Ordering %s after %s recovery", - action->uuid, target->details->uname); - order_actions(all_stopped, action, - pe_order_optional|pe_order_runnable_left); - } - - ); + crm_debug("Ordering %s after %s recovery", + action->uuid, target->details->uname); + order_actions(all_stopped, action, + pe_order_optional|pe_order_runnable_left); + } } + } } static void native_stop_constraints( - resource_t *rsc, action_t *stonith_op, gboolean is_stonith, - pe_working_set_t *data_set) + resource_t *rsc, action_t *stonith_op, gboolean is_stonith, + pe_working_set_t *data_set) { - char *key = NULL; - GListPtr action_list = NULL; - resource_t *top = uber_parent(rsc); + char *key = NULL; + GListPtr gIter = NULL; + GListPtr action_list = NULL; + resource_t *top = uber_parent(rsc); - key = stop_key(rsc); - action_list = find_actions(rsc->actions, key, stonith_op->node); - crm_free(key); + key = stop_key(rsc); + action_list = find_actions(rsc->actions, key, stonith_op->node); + crm_free(key); - /* add the stonith OP as a stop pre-req and the mark the stop - * as a pseudo op - since its now redundant - */ + /* add the stonith OP as a stop pre-req and the mark the stop + * as a pseudo op - since its now redundant + */ - slist_iter( - action, action_t, action_list, lpc2, - - if(action->node->details->online - && action->node->details->unclean == FALSE - && is_set(rsc->flags, pe_rsc_failed)) { - continue; - } + for(gIter = action_list; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + if(action->node->details->online + && action->node->details->unclean == FALSE + && is_set(rsc->flags, pe_rsc_failed)) { + continue; + } - if(is_set(rsc->flags, pe_rsc_failed)) { - crm_warn("Stop of failed resource %s is" - " implicit after %s is fenced", - rsc->id, action->node->details->uname); - } else { - crm_info("%s is implicit after %s is fenced", - action->uuid, action->node->details->uname); - } + if(is_set(rsc->flags, pe_rsc_failed)) { + crm_warn("Stop of failed resource %s is" + " implicit after %s is fenced", + rsc->id, action->node->details->uname); + } else { + crm_info("%s is implicit after %s is fenced", + action->uuid, action->node->details->uname); + } - /* the stop would never complete and is - * now implied by the stonith operation - */ - update_action_flags(action, pe_action_pseudo); - update_action_flags(action, pe_action_runnable); - update_action_flags(action, pe_action_implied_by_stonith); + /* the stop would never complete and is + * now implied by the stonith operation + */ + update_action_flags(action, pe_action_pseudo); + update_action_flags(action, pe_action_runnable); + update_action_flags(action, pe_action_implied_by_stonith); - if(is_stonith == FALSE) { - action_t *parent_stop = find_first_action(top->actions, NULL, RSC_STOP, NULL); + if(is_stonith == FALSE) { + action_t *parent_stop = find_first_action(top->actions, NULL, RSC_STOP, NULL); - order_actions(stonith_op, action, pe_order_optional); - order_actions(stonith_op, parent_stop, pe_order_optional); - } + order_actions(stonith_op, action, pe_order_optional); + order_actions(stonith_op, parent_stop, pe_order_optional); + } - if(is_set(rsc->flags, pe_rsc_notify)) { - /* Create a second notification that will be delivered - * immediately after the node is fenced - * - * Basic problem: - * - C is a clone active on the node to be shot and stopping on another - * - R is a resource that depends on C - * - * + C.stop depends on R.stop - * + C.stopped depends on STONITH - * + C.notify depends on C.stopped - * + C.healthy depends on C.notify - * + R.stop depends on C.healthy - * - * The extra notification here changes - * + C.healthy depends on C.notify - * into: - * + C.healthy depends on C.notify' - * + C.notify' depends on STONITH' - * thus breaking the loop - */ - notify_data_t *n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op, data_set); - crm_info("Creating secondary notification for %s", action->uuid); - - collect_notification_data(rsc, TRUE, FALSE, n_data); - g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_resource"), crm_strdup(rsc->id)); - g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_uname"), crm_strdup(action->node->details->uname)); - create_notifications(uber_parent(rsc), n_data, data_set); - free_notification_data(n_data); - } + if(is_set(rsc->flags, pe_rsc_notify)) { + /* Create a second notification that will be delivered + * immediately after the node is fenced + * + * Basic problem: + * - C is a clone active on the node to be shot and stopping on another + * - R is a resource that depends on C + * + * + C.stop depends on R.stop + * + C.stopped depends on STONITH + * + C.notify depends on C.stopped + * + C.healthy depends on C.notify + * + R.stop depends on C.healthy + * + * The extra notification here changes + * + C.healthy depends on C.notify + * into: + * + C.healthy depends on C.notify' + * + C.notify' depends on STONITH' + * thus breaking the loop + */ + notify_data_t *n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op, data_set); + crm_info("Creating secondary notification for %s", action->uuid); + + collect_notification_data(rsc, TRUE, FALSE, n_data); + g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_resource"), crm_strdup(rsc->id)); + g_hash_table_insert(n_data->keys, crm_strdup("notify_stop_uname"), crm_strdup(action->node->details->uname)); + create_notifications(uber_parent(rsc), n_data, data_set); + free_notification_data(n_data); + } /* From Bug #1601, successful fencing must be an input to a failed resources stop action. However given group(rA, rB) running on nodeX and B.stop has failed, A := stop healthy resource (rA.stop) B := stop failed resource (pseudo operation B.stop) C := stonith nodeX A requires B, B requires C, C requires A This loop would prevent the cluster from making progress. This block creates the "C requires A" dependency and therefore must (at least for now) be disabled. Instead, run the block above and treat all resources on nodeX as B would be (marked as a pseudo op depending on the STONITH). TODO: Break the "A requires B" dependency in update_action() and re-enable this block - } else if(is_stonith == FALSE) { - crm_info("Moving healthy resource %s" - " off %s before fencing", - rsc->id, node->details->uname); + } else if(is_stonith == FALSE) { + crm_info("Moving healthy resource %s" + " off %s before fencing", + rsc->id, node->details->uname); - * stop healthy resources before the - * stonith op - * - custom_action_order( - rsc, stop_key(rsc), NULL, - NULL,crm_strdup(CRM_OP_FENCE),stonith_op, - pe_order_optional, data_set); + * stop healthy resources before the + * stonith op + * + custom_action_order( + rsc, stop_key(rsc), NULL, + NULL,crm_strdup(CRM_OP_FENCE),stonith_op, + pe_order_optional, data_set); */ - ); + } - g_list_free(action_list); + g_list_free(action_list); - key = demote_key(rsc); - action_list = find_actions(rsc->actions, key, stonith_op->node); - crm_free(key); + key = demote_key(rsc); + action_list = find_actions(rsc->actions, key, stonith_op->node); + crm_free(key); - slist_iter( - action, action_t, action_list, lpc2, - if(action->node->details->online == FALSE || is_set(rsc->flags, pe_rsc_failed)) { - crm_info("Demote of failed resource %s is" - " implict after %s is fenced", - rsc->id, action->node->details->uname); - /* the stop would never complete and is - * now implied by the stonith operation - */ - crm_trace("here - 1"); - update_action_flags(action, pe_action_pseudo); - update_action_flags(action, pe_action_runnable); - if(is_stonith == FALSE) { - order_actions(stonith_op, action, pe_order_optional); - } - } - ); + for(gIter = action_list; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + if(action->node->details->online == FALSE || is_set(rsc->flags, pe_rsc_failed)) { + crm_info("Demote of failed resource %s is" + " implict after %s is fenced", + rsc->id, action->node->details->uname); + /* the stop would never complete and is + * now implied by the stonith operation + */ + crm_trace("here - 1"); + update_action_flags(action, pe_action_pseudo); + update_action_flags(action, pe_action_runnable); + if(is_stonith == FALSE) { + order_actions(stonith_op, action, pe_order_optional); + } + } + } - g_list_free(action_list); + g_list_free(action_list); } void rsc_stonith_ordering( - resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) + resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) { - gboolean is_stonith = FALSE; - const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + gboolean is_stonith = FALSE; + const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - - rsc_stonith_ordering(child_rsc, stonith_op, data_set); - ); - return; + if(rsc->children) { + GListPtr gIter = NULL; + for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + rsc_stonith_ordering(child_rsc, stonith_op, data_set); } + return; + } - if(is_not_set(rsc->flags, pe_rsc_managed)) { - crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); - return; - } + if(is_not_set(rsc->flags, pe_rsc_managed)) { + crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); + return; + } - if(stonith_op != NULL && safe_str_eq(class, "stonith")) { - is_stonith = TRUE; - } + if(stonith_op != NULL && safe_str_eq(class, "stonith")) { + is_stonith = TRUE; + } - /* Start constraints */ - native_start_constraints(rsc, stonith_op, is_stonith, data_set); + /* Start constraints */ + native_start_constraints(rsc, stonith_op, is_stonith, data_set); - /* Stop constraints */ - native_stop_constraints(rsc, stonith_op, is_stonith, data_set); + /* Stop constraints */ + native_stop_constraints(rsc, stonith_op, is_stonith, data_set); } enum stack_activity { stack_stable = 0, stack_starting = 1, stack_stopping = 2, stack_middle = 4, }; static enum stack_activity find_clone_activity_on(resource_t *rsc, resource_t *target, node_t *node, const char *type) { int mode = stack_stable; action_t *active = NULL; if(target->children) { - slist_iter( - child, resource_t, target->children, lpc, + GListPtr gIter = NULL; + for(gIter = target->children; gIter != NULL; gIter = gIter->next) { + resource_t *child = (resource_t*)gIter->data; mode |= find_clone_activity_on(rsc, child, node, type); - ); + } return mode; } active = find_first_action(target->actions, NULL, CRMD_ACTION_START, NULL); if(active && is_set(active->flags, pe_action_optional) == FALSE && is_set(active->flags, pe_action_pseudo) == FALSE) { crm_debug("%s: found scheduled %s action (%s)", rsc->id, active->uuid, type); mode |= stack_starting; } active = find_first_action(target->actions, NULL, CRMD_ACTION_STOP, node); if(active && is_set(active->flags, pe_action_optional) == FALSE && is_set(active->flags, pe_action_pseudo) == FALSE) { crm_debug("%s: found scheduled %s action (%s)", rsc->id, active->uuid, type); mode |= stack_stopping; } return mode; } static enum stack_activity check_stack_element(resource_t *rsc, resource_t *other_rsc, const char *type) { resource_t *other_p = uber_parent(other_rsc); if(other_rsc == NULL || other_rsc == rsc) { return stack_stable; } else if(other_p->variant == pe_native) { crm_notice("Cannot migrate %s due to dependency on %s (%s)", rsc->id, other_rsc->id, type); return stack_middle; } else if(other_rsc == rsc->parent) { int mode = 0; - slist_iter(constraint, rsc_colocation_t, other_rsc->rsc_cons, lpc, - if(constraint->score > 0) { - mode |= check_stack_element(rsc, constraint->rsc_rh, type); - } - ); + GListPtr gIter = NULL; + for(gIter = other_rsc->rsc_cons; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + if(constraint->score > 0) { + mode |= check_stack_element(rsc, constraint->rsc_rh, type); + } + } return mode; } else if(other_p->variant == pe_group) { crm_notice("Cannot migrate %s due to dependency on group %s (%s)", rsc->id, other_rsc->id, type); return stack_middle; } /* else: >= clone */ /* -## Assumption -A depends on clone(B) + ## Assumption + A depends on clone(B) -## Resource Activity During Move + ## Resource Activity During Move - N1 N2 N3 - --- --- --- -t0 A.stop -t1 B.stop B.stop -t2 B.start B.start -t3 A.start + N1 N2 N3 + --- --- --- + t0 A.stop + t1 B.stop B.stop + t2 B.start B.start + t3 A.start -## Resource Activity During Migration + ## Resource Activity During Migration - N1 N2 N3 - --- --- --- -t0 B.start B.start -t1 A.stop (1) -t2 A.start (2) -t3 B.stop B.stop + N1 N2 N3 + --- --- --- + t0 B.start B.start + t1 A.stop (1) + t2 A.start (2) + t3 B.stop B.stop -Node 1: Rewritten to be a migrate-to operation -Node 2: Rewritten to be a migrate-from operation + Node 1: Rewritten to be a migrate-to operation + Node 2: Rewritten to be a migrate-from operation -# Constraints + # Constraints -The following constraints already exist in the system. -The 'ok' and 'fail' column refers to whether they still hold for migration. + The following constraints already exist in the system. + The 'ok' and 'fail' column refers to whether they still hold for migration. -a) A.stop -> A.start - ok -b) B.stop -> B.start - fail + a) A.stop -> A.start - ok + b) B.stop -> B.start - fail -c) A.stop -> B.stop - ok -d) B.start -> A.start - ok + c) A.stop -> B.stop - ok + d) B.start -> A.start - ok -e) B.stop -> A.start - fail -f) A.stop -> B.start - fail + e) B.stop -> A.start - fail + f) A.stop -> B.start - fail -## Scenarios -B unchanged - ok -B stopping only - fail - possible after fixing 'e' -B starting only - fail - possible after fixing 'f' -B stoping and starting - fail - constraint 'b' is unfixable -B restarting only on N2 - fail - as-per previous only rarer + ## Scenarios + B unchanged - ok + B stopping only - fail - possible after fixing 'e' + B starting only - fail - possible after fixing 'f' + B stoping and starting - fail - constraint 'b' is unfixable + B restarting only on N2 - fail - as-per previous only rarer - */ + */ /* Only allow migration when the clone is either stable, only starting or only stopping */ return find_clone_activity_on(rsc, other_rsc, NULL, type); } static gboolean at_stack_bottom(resource_t *rsc) { char *key = NULL; action_t *start = NULL; action_t *other = NULL; int mode = stack_stable; GListPtr action_list = NULL; + GListPtr gIter = NULL; key = start_key(rsc); action_list = find_actions(rsc->actions, key, NULL); crm_free(key); crm_debug_3("%s: processing", rsc->id); CRM_CHECK(action_list != NULL, return FALSE); start = action_list->data; g_list_free(action_list); - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons, lpc, - + for(gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; resource_t *target = constraint->rsc_rh; crm_debug_4("Checking %s: %s == %s (%d)", constraint->id, rsc->id, target->id, constraint->score); if(constraint->score > 0) { mode |= check_stack_element(rsc, target, "coloc"); if(mode & stack_middle) { return FALSE; } else if((mode & stack_stopping) && (mode & stack_starting)) { crm_notice("Cannot migrate %s due to colocation activity (last was %s)", rsc->id, target->id); return FALSE; } } - ); + } - slist_iter( - other_w, action_wrapper_t, start->actions_before, lpc, + for(gIter = start->actions_before; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other_w = (action_wrapper_t*)gIter->data; + other = other_w->action; if(other_w->type & pe_order_serialize_only) { crm_debug_3("%s: depends on %s (serialize ordering)", rsc->id, other->uuid); continue; } crm_debug_2("%s: Checking %s ordering", rsc->id, other->uuid); if(is_set(other->flags, pe_action_optional) == FALSE) { mode |= check_stack_element(rsc, other->rsc, "order"); if(mode & stack_middle) { return FALSE; } else if((mode & stack_stopping) && (mode & stack_starting)) { crm_notice("Cannot migrate %s due to ordering activity (last was %s)", rsc->id, other->rsc->id); return FALSE; } } - - ); - + } return TRUE; } void rsc_migrate_reload(resource_t *rsc, pe_working_set_t *data_set) { - char *key = NULL; - int level = LOG_DEBUG; - GListPtr action_list = NULL; + char *key = NULL; + GListPtr gIter = NULL; + int level = LOG_DEBUG; + GListPtr action_list = NULL; - action_t *stop = NULL; - action_t *start = NULL; - action_t *other = NULL; - action_t *action = NULL; - const char *value = NULL; + action_t *stop = NULL; + action_t *start = NULL; + action_t *other = NULL; + action_t *action = NULL; + const char *value = NULL; - if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - - rsc_migrate_reload(child_rsc, data_set); - ); - other = NULL; - return; - } else if(rsc->variant > pe_native) { - return; + if(rsc->children) { + for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + rsc_migrate_reload(child_rsc, data_set); } + other = NULL; + return; + } else if(rsc->variant > pe_native) { + return; + } - do_crm_log_unlikely(level+1, "Processing %s", rsc->id); + do_crm_log_unlikely(level+1, "Processing %s", rsc->id); - if(is_not_set(rsc->flags, pe_rsc_managed) - || is_set(rsc->flags, pe_rsc_failed) - || is_set(rsc->flags, pe_rsc_start_pending) - || rsc->next_role < RSC_ROLE_STARTED - || g_list_length(rsc->running_on) != 1) { - do_crm_log_unlikely( - level+1, "%s: general resource state: flags=0x%.16llx", - rsc->id, rsc->flags); - return; - } + if(is_not_set(rsc->flags, pe_rsc_managed) + || is_set(rsc->flags, pe_rsc_failed) + || is_set(rsc->flags, pe_rsc_start_pending) + || rsc->next_role < RSC_ROLE_STARTED + || g_list_length(rsc->running_on) != 1) { + do_crm_log_unlikely( + level+1, "%s: general resource state: flags=0x%.16llx", + rsc->id, rsc->flags); + return; + } - value = g_hash_table_lookup(rsc->meta, XML_OP_ATTR_ALLOW_MIGRATE); - if(crm_is_true(value)) { - set_bit(rsc->flags, pe_rsc_can_migrate); - } + value = g_hash_table_lookup(rsc->meta, XML_OP_ATTR_ALLOW_MIGRATE); + if(crm_is_true(value)) { + set_bit(rsc->flags, pe_rsc_can_migrate); + } - if(rsc->next_role > RSC_ROLE_SLAVE) { - clear_bit(rsc->flags, pe_rsc_can_migrate); - do_crm_log_unlikely( - level+1, "%s: resource role: role=%s", rsc->id, role2text(rsc->next_role)); - } + if(rsc->next_role > RSC_ROLE_SLAVE) { + clear_bit(rsc->flags, pe_rsc_can_migrate); + do_crm_log_unlikely( + level+1, "%s: resource role: role=%s", rsc->id, role2text(rsc->next_role)); + } - key = start_key(rsc); - action_list = find_actions(rsc->actions, key, NULL); - crm_free(key); + key = start_key(rsc); + action_list = find_actions(rsc->actions, key, NULL); + crm_free(key); - if(action_list == NULL) { - do_crm_log_unlikely(level, "%s: no start action", rsc->id); - return; - } + if(action_list == NULL) { + do_crm_log_unlikely(level, "%s: no start action", rsc->id); + return; + } - start = action_list->data; - g_list_free(action_list); + start = action_list->data; + g_list_free(action_list); - if(is_not_set(rsc->flags, pe_rsc_can_migrate) - && is_set(start->flags, pe_action_allow_reload_conversion) == FALSE) { - do_crm_log_unlikely(level+1, "%s: no need to continue", rsc->id); - return; - } + if(is_not_set(rsc->flags, pe_rsc_can_migrate) + && is_set(start->flags, pe_action_allow_reload_conversion) == FALSE) { + do_crm_log_unlikely(level+1, "%s: no need to continue", rsc->id); + return; + } - key = stop_key(rsc); - action_list = find_actions(rsc->actions, key, NULL); - crm_free(key); + key = stop_key(rsc); + action_list = find_actions(rsc->actions, key, NULL); + crm_free(key); - if(action_list == NULL) { - do_crm_log_unlikely(level, "%s: no stop action", rsc->id); - return; - } + if(action_list == NULL) { + do_crm_log_unlikely(level, "%s: no stop action", rsc->id); + return; + } - stop = action_list->data; - g_list_free(action_list); + stop = action_list->data; + g_list_free(action_list); - action = start; - if(action->node == NULL - || is_set(action->flags, pe_action_pseudo) - || is_set(action->flags, pe_action_optional) - || is_set(action->flags, pe_action_runnable) == FALSE) { - do_crm_log_unlikely(level, "%s: %s", rsc->id, action->task); - return; - } + action = start; + if(action->node == NULL + || is_set(action->flags, pe_action_pseudo) + || is_set(action->flags, pe_action_optional) + || is_set(action->flags, pe_action_runnable) == FALSE) { + do_crm_log_unlikely(level, "%s: %s", rsc->id, action->task); + return; + } - action = stop; - if(action->node == NULL - || is_set(action->flags, pe_action_pseudo) - || is_set(action->flags, pe_action_optional) - || is_set(action->flags, pe_action_runnable) == FALSE) { - do_crm_log_unlikely(level, "%s: %s", rsc->id, action->task); - return; - } + action = stop; + if(action->node == NULL + || is_set(action->flags, pe_action_pseudo) + || is_set(action->flags, pe_action_optional) + || is_set(action->flags, pe_action_runnable) == FALSE) { + do_crm_log_unlikely(level, "%s: %s", rsc->id, action->task); + return; + } - if(is_set(rsc->flags, pe_rsc_can_migrate)) { - if(start->node == NULL - || stop->node == NULL - || stop->node->details == start->node->details) { - clear_bit(rsc->flags, pe_rsc_can_migrate); + if(is_set(rsc->flags, pe_rsc_can_migrate)) { + if(start->node == NULL + || stop->node == NULL + || stop->node->details == start->node->details) { + clear_bit(rsc->flags, pe_rsc_can_migrate); - } else if(at_stack_bottom(rsc) == FALSE) { - clear_bit(rsc->flags, pe_rsc_can_migrate); - } + } else if(at_stack_bottom(rsc) == FALSE) { + clear_bit(rsc->flags, pe_rsc_can_migrate); } + } - if(is_set(rsc->flags, pe_rsc_can_migrate)) { - action_t *to = NULL; - action_t *from = NULL; - action_t *done = get_pseudo_op(STONITH_DONE, data_set); + if(is_set(rsc->flags, pe_rsc_can_migrate)) { + action_t *to = NULL; + action_t *from = NULL; + action_t *done = get_pseudo_op(STONITH_DONE, data_set); - crm_info("Migrating %s from %s to %s", rsc->id, - stop->node->details->uname, - start->node->details->uname); - - /* Preserve the stop to ensure the end state is sane on that node, - * Make the start a pseudo op - * Create migrate_to, have it depend on everything the stop did - * Create migrate_from - * *-> migrate_to -> migrate_from -> stop -> start - */ + crm_info("Migrating %s from %s to %s", rsc->id, + stop->node->details->uname, + start->node->details->uname); + + /* Preserve the stop to ensure the end state is sane on that node, + * Make the start a pseudo op + * Create migrate_to, have it depend on everything the stop did + * Create migrate_from + * *-> migrate_to -> migrate_from -> stop -> start + */ - update_action_flags(start, pe_action_pseudo); /* easier than trying to delete it from the graph - * but perhaps we should have it run anyway - */ + update_action_flags(start, pe_action_pseudo); /* easier than trying to delete it from the graph + * but perhaps we should have it run anyway + */ - to = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATE, 0), RSC_MIGRATE, stop->node, FALSE, TRUE, data_set); - from = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATED, 0), RSC_MIGRATED, start->node, FALSE, TRUE, data_set); + to = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATE, 0), RSC_MIGRATE, stop->node, FALSE, TRUE, data_set); + from = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATED, 0), RSC_MIGRATED, start->node, FALSE, TRUE, data_set); - /* This is slightly sub-optimal if 'to' fails, but always - * run both halves of the migration before terminating the - * transition. - * - * This can be removed if/when we update unpack_rsc_op() to - * 'correctly' handle partial migrations. - * - * Without this, we end up stopping both sides - */ - from->priority = INFINITY; + /* This is slightly sub-optimal if 'to' fails, but always + * run both halves of the migration before terminating the + * transition. + * + * This can be removed if/when we update unpack_rsc_op() to + * 'correctly' handle partial migrations. + * + * Without this, we end up stopping both sides + */ + from->priority = INFINITY; - order_actions(to, from, pe_order_optional); - order_actions(from, stop, pe_order_optional); - order_actions(done, to, pe_order_optional); + order_actions(to, from, pe_order_optional); + order_actions(from, stop, pe_order_optional); + order_actions(done, to, pe_order_optional); - add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->id); - add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->id); + add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->id); + add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->id); - add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->id); - add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->id); + add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->id); + add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->id); - /* Create the correct ordering ajustments based on find_clone_activity_on(); */ + /* Create the correct ordering ajustments based on find_clone_activity_on(); */ - slist_iter( - constraint, rsc_colocation_t, rsc->rsc_cons, lpc, - - resource_t *target = constraint->rsc_rh; - crm_info("Repairing %s: %s == %s (%d)", constraint->id, rsc->id, target->id, constraint->score); - - if(constraint->score > 0) { - int mode = check_stack_element(rsc, target, "coloc"); - action_t *clone_stop = find_first_action(target->actions, NULL, RSC_STOP, NULL); - action_t *clone_start = find_first_action(target->actions, NULL, RSC_STARTED, NULL); - - CRM_ASSERT(clone_stop != NULL); - CRM_ASSERT(clone_start != NULL); - CRM_ASSERT((mode & stack_middle) == 0); - CRM_ASSERT(((mode & stack_stopping) && (mode & stack_starting)) == 0); + for(gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + resource_t *target = constraint->rsc_rh; + crm_info("Repairing %s: %s == %s (%d)", constraint->id, rsc->id, target->id, constraint->score); + + if(constraint->score > 0) { + int mode = check_stack_element(rsc, target, "coloc"); + action_t *clone_stop = find_first_action(target->actions, NULL, RSC_STOP, NULL); + action_t *clone_start = find_first_action(target->actions, NULL, RSC_STARTED, NULL); + + CRM_ASSERT(clone_stop != NULL); + CRM_ASSERT(clone_start != NULL); + CRM_ASSERT((mode & stack_middle) == 0); + CRM_ASSERT(((mode & stack_stopping) && (mode & stack_starting)) == 0); - if(mode & stack_stopping) { + if(mode & stack_stopping) { #if 0 - crm_debug("Creating %s.start -> %s.stop ordering", rsc->id, target->id); - order_actions(from, clone_stop, pe_order_optional); + crm_debug("Creating %s.start -> %s.stop ordering", rsc->id, target->id); + order_actions(from, clone_stop, pe_order_optional); #endif - slist_iter( - other_w, action_wrapper_t, start->actions_before, lpc2, - /* Needed if the clone's started pseudo-action ever gets printed in the graph */ - if(other_w->action == clone_start) { - crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, start->uuid); - other_w->type = pe_order_none; - } - ); + GListPtr lpc2 = NULL; + for(lpc2 = start->actions_before; lpc2 != NULL; lpc2 = lpc2->next) { + action_wrapper_t *other_w = (action_wrapper_t*)lpc2->data; + + /* Needed if the clone's started pseudo-action ever gets printed in the graph */ + if(other_w->action == clone_start) { + crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, start->uuid); + other_w->type = pe_order_none; + } + } - } else if(mode & stack_starting) { + } else if(mode & stack_starting) { #if 0 - crm_debug("Creating %s.started -> %s.stop ordering", target->id, rsc->id); - order_actions(clone_start, to, pe_order_optional); + crm_debug("Creating %s.started -> %s.stop ordering", target->id, rsc->id); + order_actions(clone_start, to, pe_order_optional); #endif - slist_iter( - other_w, action_wrapper_t, clone_stop->actions_before, lpc2, - /* Needed if the clone's stop pseudo-action ever gets printed in the graph */ - if(other_w->action == stop) { - crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, clone_stop->uuid); - other_w->type = pe_order_none; - } - ); + GListPtr lpc2 = NULL; + for(lpc2 = clone_stop->actions_before; lpc2 != NULL; lpc2 = lpc2->next) { + action_wrapper_t *other_w = (action_wrapper_t*)lpc2->data; + + /* Needed if the clone's stop pseudo-action ever gets printed in the graph */ + if(other_w->action == stop) { + crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, clone_stop->uuid); + other_w->type = pe_order_none; } } - ); + } + } + } #if 0 - /* Implied now that start/stop are not morphed into migrate ops */ + /* Implied now that start/stop are not morphed into migrate ops */ - /* Anything that needed stop to complete, now also needs start to have completed */ - slist_iter( - other_w, action_wrapper_t, stop->actions_after, lpc, - other = other_w->action; - if(is_set(other->flags, pe_action_optional) || other->rsc != NULL) { - continue; - } - crm_debug("Ordering %s before %s (stop)", from->uuid, other->uuid); - order_actions(from, other, other_w->type); - ); + /* Anything that needed stop to complete, now also needs start to have completed */ + for(gIter = stop->actions_after; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other_w = (action_wrapper_t*)gIter->data; + other = other_w->action; + if(is_set(other->flags, pe_action_optional) || other->rsc != NULL) { + continue; + } + crm_debug("Ordering %s before %s (stop)", from->uuid, other->uuid); + order_actions(from, other, other_w->type); + } #endif - /* migrate_to also needs anything that the stop needed to have completed too */ - slist_iter( - other_w, action_wrapper_t, stop->actions_before, lpc, - other = other_w->action; - if(other->rsc == NULL) { - /* nothing */ + /* migrate_to also needs anything that the stop needed to have completed too */ + for(gIter = stop->actions_before; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other_w = (action_wrapper_t*)gIter->data; + + other = other_w->action; + if(other->rsc == NULL) { + /* nothing */ - } else if(is_set(other->flags, pe_action_optional) || other->rsc == rsc || other->rsc == rsc->parent) { - continue; - } - crm_debug("Ordering %s before %s (stop)", other_w->action->uuid, stop->uuid); - order_actions(other, to, other_w->type); - ); - - /* migrate_to also needs anything that the start needed to have completed too */ - slist_iter( - other_w, action_wrapper_t, start->actions_before, lpc, - other = other_w->action; - if(other->rsc == NULL) { - /* nothing */ - } else if(is_set(other->flags, pe_action_optional) || other->rsc == rsc || other->rsc == rsc->parent) { - continue; - } - crm_debug("Ordering %s before %s (start)", other_w->action->uuid, stop->uuid); - order_actions(other, to, other_w->type); - ); - - } else if(start && stop - && is_set(start->flags, pe_action_allow_reload_conversion) - && stop->node->details == start->node->details) { - action_t *rewrite = NULL; - - update_action_flags(start, pe_action_pseudo); /* easier than trying to delete it from the graph */ - - action = NULL; - key = promote_key(rsc); - action_list = find_actions(rsc->actions, key, NULL); - if(action_list) { - action = action_list->data; - } - if(action && is_set(action->flags, pe_action_optional) == FALSE) { - update_action_flags(action, pe_action_pseudo); - } - g_list_free(action_list); - crm_free(key); - - action = NULL; - key = demote_key(rsc); - action_list = find_actions(rsc->actions, key, NULL); - if(action_list) { - action = action_list->data; - } - g_list_free(action_list); - crm_free(key); + } else if(is_set(other->flags, pe_action_optional) || other->rsc == rsc || other->rsc == rsc->parent) { + continue; + } + crm_debug("Ordering %s before %s (stop)", other_w->action->uuid, stop->uuid); + order_actions(other, to, other_w->type); + } + + /* migrate_to also needs anything that the start needed to have completed too */ + for(gIter = start->actions_before; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other_w = (action_wrapper_t*)gIter->data; + + other = other_w->action; + if(other->rsc == NULL) { + /* nothing */ + } else if(is_set(other->flags, pe_action_optional) || other->rsc == rsc || other->rsc == rsc->parent) { + continue; + } + crm_debug("Ordering %s before %s (start)", other_w->action->uuid, stop->uuid); + order_actions(other, to, other_w->type); + } + + } else if(start && stop + && is_set(start->flags, pe_action_allow_reload_conversion) + && stop->node->details == start->node->details) { + action_t *rewrite = NULL; - if(action && is_set(action->flags, pe_action_optional) == FALSE) { - rewrite = action; - update_action_flags(stop, pe_action_pseudo); + update_action_flags(start, pe_action_pseudo); /* easier than trying to delete it from the graph */ + + action = NULL; + key = promote_key(rsc); + action_list = find_actions(rsc->actions, key, NULL); + if(action_list) { + action = action_list->data; + } + if(action && is_set(action->flags, pe_action_optional) == FALSE) { + update_action_flags(action, pe_action_pseudo); + } + g_list_free(action_list); + crm_free(key); + + action = NULL; + key = demote_key(rsc); + action_list = find_actions(rsc->actions, key, NULL); + if(action_list) { + action = action_list->data; + } + g_list_free(action_list); + crm_free(key); + + if(action && is_set(action->flags, pe_action_optional) == FALSE) { + rewrite = action; + update_action_flags(stop, pe_action_pseudo); - } else { - rewrite = stop; - } - crm_info("Rewriting %s of %s on %s as a reload", - rewrite->task, rsc->id, stop->node->details->uname); - - crm_free(rewrite->uuid); - crm_free(rewrite->task); - rewrite->task = crm_strdup("reload"); - rewrite->uuid = generate_op_key(rsc->id, rewrite->task, 0); - } else { - do_crm_log_unlikely(level+1, "%s nothing to do", rsc->id); + rewrite = stop; } + crm_info("Rewriting %s of %s on %s as a reload", + rewrite->task, rsc->id, stop->node->details->uname); + + crm_free(rewrite->uuid); + crm_free(rewrite->task); + rewrite->task = crm_strdup("reload"); + rewrite->uuid = generate_op_key(rsc->id, rewrite->task, 0); + + } else { + do_crm_log_unlikely(level+1, "%s nothing to do", rsc->id); + } } void native_append_meta(resource_t *rsc, xmlNode *xml) { char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION); if(value) { char *name = NULL; name = crm_meta_name(XML_RSC_ATTR_INCARNATION); crm_xml_add(xml, name, value); crm_free(name); } } diff --git a/pengine/pengine.c b/pengine/pengine.c index 1e0034df56..4605f40e5e 100644 --- a/pengine/pengine.c +++ b/pengine/pengine.c @@ -1,292 +1,297 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include xmlNode * do_calculations( pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); gboolean show_scores = FALSE; int scores_log_level = LOG_DEBUG_2; gboolean show_utilization = FALSE; int utilization_log_level = LOG_DEBUG_2; extern int transition_id; #define get_series() was_processing_error?1:was_processing_warning?2:3 typedef struct series_s { int id; const char *name; const char *param; int wrap; } series_t; series_t series[] = { { 0, "pe-unknown", "_dont_match_anything_", -1 }, { 0, "pe-error", "pe-error-series-max", -1 }, { 0, "pe-warn", "pe-warn-series-max", 200 }, { 0, "pe-input", "pe-input-series-max", 400 }, }; gboolean process_pe_message(xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender) { gboolean send_via_disk = FALSE; const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); const char *op = crm_element_value(msg, F_CRM_TASK); const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE); crm_debug_3("Processing %s op (ref=%s)...", op, ref); if(op == NULL){ /* error */ } else if(strcasecmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(safe_str_eq(crm_element_value(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE)) { /* ignore */ } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) { crm_debug_3("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcasecmp(op, CRM_OP_PECALC) == 0) { int seq = -1; int series_id = 0; int series_wrap = 0; char *filename = NULL; char *graph_file = NULL; const char *value = NULL; pe_working_set_t data_set; xmlNode *converted = NULL; xmlNode *reply = NULL; gboolean process = TRUE; #if HAVE_BZLIB_H gboolean compress = TRUE; #else gboolean compress = FALSE; #endif crm_config_error = FALSE; crm_config_warning = FALSE; was_processing_error = FALSE; was_processing_warning = FALSE; graph_file = crm_strdup(CRM_STATE_DIR"/graph.XXXXXX"); graph_file = mktemp(graph_file); set_working_set_defaults(&data_set); converted = copy_xml(xml_data); if(cli_config_update(&converted, NULL, TRUE) == FALSE) { data_set.graph = create_xml_node(NULL, XML_TAG_GRAPH); crm_xml_add_int(data_set.graph, "transition_id", 0); crm_xml_add_int(data_set.graph, "cluster-delay", 0); process = FALSE; } if(process) { do_calculations(&data_set, converted, NULL); } series_id = get_series(); series_wrap = series[series_id].wrap; value = pe_pref(data_set.config_hash, series[series_id].param); if(value != NULL) { series_wrap = crm_int_helper(value, NULL); if(errno != 0) { series_wrap = series[series_id].wrap; } } else { crm_config_warn("No value specified for cluster" " preference: %s", series[series_id].param); } seq = get_last_sequence(PE_STATE_DIR, series[series_id].name); data_set.input = NULL; reply = create_reply(msg, data_set.graph); CRM_ASSERT(reply != NULL); filename = generate_series_filename( PE_STATE_DIR, series[series_id].name, seq, compress); crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename); crm_xml_add_int(reply, "graph-errors", was_processing_error); crm_xml_add_int(reply, "graph-warnings", was_processing_warning); crm_xml_add_int(reply, "config-errors", crm_config_error); crm_xml_add_int(reply, "config-warnings", crm_config_warning); if(send_ipc_message(sender, reply) == FALSE) { if(sender && sender->ops->get_chan_status(sender) == IPC_CONNECT) { send_via_disk = TRUE; crm_err("Answer could not be sent via IPC, send via the disk instead"); crm_info("Writing the TE graph to %s", graph_file); if(write_xml_file(data_set.graph, graph_file, FALSE) < 0) { crm_err("TE graph could not be written to disk"); } } else { crm_info("Peer disconnected, discarding transition graph"); } } free_xml(reply); cleanup_alloc_calculations(&data_set); if(series_wrap != 0) { write_xml_file(xml_data, filename, compress); write_last_sequence(PE_STATE_DIR, series[series_id].name, seq+1, series_wrap); } if(was_processing_error) { crm_err("Transition %d:" " ERRORs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else if(was_processing_warning) { crm_warn("Transition %d:" " WARNINGs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else { crm_info("Transition %d: PEngine Input stored in: %s", transition_id, filename); } if(crm_config_error) { crm_info("Configuration ERRORs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } else if(crm_config_warning) { crm_info("Configuration WARNINGs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } if(send_via_disk) { reply = create_reply(msg, NULL); crm_xml_add(reply, F_CRM_TGRAPH, graph_file); crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename); CRM_ASSERT(reply != NULL); if(send_ipc_message(sender, reply) == FALSE) { crm_err("Answer could not be sent"); } free_xml(reply); } free_xml(converted); crm_free(graph_file); crm_free(filename); } else if(strcasecmp(op, CRM_OP_QUIT) == 0) { crm_warn("Received quit message, terminating"); exit(0); } return TRUE; } xmlNode * do_calculations(pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now) { + GListPtr gIter = NULL; int rsc_log_level = LOG_NOTICE; /* pe_debug_on(); */ CRM_ASSERT(xml_input || is_set(data_set->flags, pe_flag_have_status)); if(is_set(data_set->flags, pe_flag_have_status) == FALSE) { set_working_set_defaults(data_set); data_set->input = xml_input; data_set->now = now; if(data_set->now == NULL) { data_set->now = new_ha_date(TRUE); } } else { crm_trace("Already have status - reusing"); } crm_debug_5("Calculate cluster status"); stage0(data_set); - slist_iter(rsc, resource_t, data_set->resources, lpc, - if(is_set(rsc->flags, pe_rsc_orphan) - && rsc->role == RSC_ROLE_STOPPED) { - continue; - } - rsc->fns->print(rsc, NULL, pe_print_log, &rsc_log_level); - ); + gIter = data_set->resources; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + + if(is_set(rsc->flags, pe_rsc_orphan) && rsc->role == RSC_ROLE_STOPPED) { + continue; + } + rsc->fns->print(rsc, NULL, pe_print_log, &rsc_log_level); + } crm_trace("Applying placement constraints"); stage2(data_set); crm_trace("Create internal constraints"); stage3(data_set); crm_trace("Check actions"); stage4(data_set); crm_trace("Allocate resources"); stage5(data_set); crm_trace("Processing fencing and shutdown cases"); stage6(data_set); crm_trace("Applying ordering constraints"); stage7(data_set); crm_trace("Create transition graph"); stage8(data_set); crm_trace("=#=#=#=#= Summary =#=#=#=#="); crm_trace("\t========= Set %d (Un-runnable) =========", -1); if(crm_log_level > LOG_DEBUG) { - slist_iter(action, action_t, data_set->actions, lpc, - if(is_set(action->flags, pe_action_optional) == FALSE - && is_set(action->flags, pe_action_runnable) == FALSE - && is_set(action->flags, pe_action_pseudo) == FALSE) { - log_action(LOG_DEBUG_2, "\t", action, TRUE); - } - ); + gIter = data_set->actions; + for(; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; + if(is_set(action->flags, pe_action_optional) == FALSE + && is_set(action->flags, pe_action_runnable) == FALSE + && is_set(action->flags, pe_action_pseudo) == FALSE) { + log_action(LOG_DEBUG_2, "\t", action, TRUE); + } + } } return data_set->graph; } diff --git a/pengine/ptest.c b/pengine/ptest.c index 725ff71c97..e44ba8b660 100644 --- a/pengine/ptest.c +++ b/pengine/ptest.c @@ -1,494 +1,497 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBXML2 # include #endif gboolean use_stdin = FALSE; gboolean do_simulation = FALSE; gboolean inhibit_exit = FALSE; gboolean all_actions = FALSE; extern xmlNode * do_calculations( - pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); char *use_date = NULL; FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ - fprintf(dot_strm, fmt); \ - fprintf(dot_strm, "\n"); \ - } else { \ - crm_debug(DOT_PREFIX""fmt); \ - } + fprintf(dot_strm, fmt); \ + fprintf(dot_strm, "\n"); \ + } else { \ + crm_debug(DOT_PREFIX""fmt); \ + } static void init_dotfile(void) { - dot_write(" digraph \"g\" {"); + dot_write(" digraph \"g\" {"); /* dot_write(" size = \"30,30\""); */ /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } static char * create_action_name(action_t *action) { - char *action_name = NULL; - const char *action_host = NULL; - if(action->node) { - action_host = action->node->details->uname; - action_name = crm_concat(action->uuid, action_host, ' '); - - } else if(is_set(action->flags, pe_action_pseudo)) { - action_name = crm_strdup(action->uuid); + char *action_name = NULL; + const char *action_host = NULL; + if(action->node) { + action_host = action->node->details->uname; + action_name = crm_concat(action->uuid, action_host, ' '); + + } else if(is_set(action->flags, pe_action_pseudo)) { + action_name = crm_strdup(action->uuid); - } else { - action_host = ""; - action_name = crm_concat(action->uuid, action_host, ' '); - } - if(safe_str_eq(action->task, RSC_CANCEL)) { - char *tmp_action_name = action_name; - action_name = crm_concat("Cancel", tmp_action_name, ' '); - crm_free(tmp_action_name); - } + } else { + action_host = ""; + action_name = crm_concat(action->uuid, action_host, ' '); + } + if(safe_str_eq(action->task, RSC_CANCEL)) { + char *tmp_action_name = action_name; + action_name = crm_concat("Cancel", tmp_action_name, ' '); + crm_free(tmp_action_name); + } - return action_name; + return action_name; } gboolean USE_LIVE_CIB = FALSE; static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "This text"}, {"version", 0, 0, '$', "Version information" }, {"verbose", 0, 0, 'V', "Increase debug output\n"}, {"simulate", 0, 0, 'S', "Simulate the transition's execution to find invalid graphs\n"}, {"show-scores", 0, 0, 's', "Display resource allocation scores"}, {"show-utilization", 0, 0, 'U', "Display utilization information"}, {"all-actions", 0, 0, 'a', "Display all possible actions - even ones not part of the transition graph"}, {"live-check", 0, 0, 'L', "Connect to the CIB and use the current contents as input"}, {"xml-text", 1, 0, 'X', "Retrieve XML from the supplied string"}, {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, /* {"xml-pipe", 0, 0, 'p', "Retrieve XML from stdin\n"}, */ {"save-input", 1, 0, 'I', "\tSave the input to the named file"}, {"save-graph", 1, 0, 'G', "\tSave the transition graph (XML format) to the named file"}, {"save-dotfile",1, 0, 'D', "Save the transition graph (DOT format) to the named file\n"}, {0, 0, 0, 0} }; int main(int argc, char **argv) { - gboolean process = TRUE; - gboolean all_good = TRUE; - enum transition_status graph_rc = -1; - crm_graph_t *transition = NULL; - ha_time_t *a_date = NULL; - cib_t * cib_conn = NULL; + GListPtr lpc = NULL; + gboolean process = TRUE; + gboolean all_good = TRUE; + enum transition_status graph_rc = -1; + crm_graph_t *transition = NULL; + ha_time_t *a_date = NULL; + cib_t * cib_conn = NULL; - xmlNode * cib_object = NULL; - int argerr = 0; - int flag; + xmlNode * cib_object = NULL; + int argerr = 0; + int flag; - char *msg_buffer = NULL; - gboolean optional = FALSE; - pe_working_set_t data_set; + char *msg_buffer = NULL; + gboolean optional = FALSE; + pe_working_set_t data_set; - const char *source = NULL; - const char *xml_file = NULL; - const char *dot_file = NULL; - const char *graph_file = NULL; - const char *input_file = NULL; - - /* disable glib's fancy allocators that can't be free'd */ - GMemVTable vtable; - - vtable.malloc = malloc; - vtable.realloc = realloc; - vtable.free = free; - vtable.calloc = calloc; - vtable.try_malloc = malloc; - vtable.try_realloc = realloc; - - g_mem_set_vtable(&vtable); - - crm_log_init_quiet(NULL, LOG_CRIT, FALSE, FALSE, argc, argv); - crm_set_options("V?$XD:G:I:Lwx:d:aSsU", "[-?Vv] -[Xxp] {other options}", long_options, - "Calculate the cluster's response to the supplied cluster state\n"); + const char *source = NULL; + const char *xml_file = NULL; + const char *dot_file = NULL; + const char *graph_file = NULL; + const char *input_file = NULL; + + /* disable glib's fancy allocators that can't be free'd */ + GMemVTable vtable; + + vtable.malloc = malloc; + vtable.realloc = realloc; + vtable.free = free; + vtable.calloc = calloc; + vtable.try_malloc = malloc; + vtable.try_realloc = realloc; + + g_mem_set_vtable(&vtable); + + crm_log_init_quiet(NULL, LOG_CRIT, FALSE, FALSE, argc, argv); + crm_set_options("V?$XD:G:I:Lwx:d:aSsU", "[-?Vv] -[Xxp] {other options}", long_options, + "Calculate the cluster's response to the supplied cluster state\n"); - while (1) { - int option_index = 0; - flag = crm_get_option(argc, argv, &option_index); - if (flag == -1) - break; + while (1) { + int option_index = 0; + flag = crm_get_option(argc, argv, &option_index); + if (flag == -1) + break; - switch(flag) { - case 'S': - do_simulation = TRUE; - break; - case 'a': - all_actions = TRUE; - break; - case 'w': - inhibit_exit = TRUE; - break; - case 'X': - use_stdin = TRUE; - break; - case 's': - show_scores = TRUE; - break; - case 'U': - show_utilization = TRUE; - break; - case 'x': - xml_file = optarg; - break; - case 'd': - use_date = optarg; - break; - case 'D': - dot_file = optarg; - break; - case 'G': - graph_file = optarg; - break; - case 'I': - input_file = optarg; - break; - case 'V': - cl_log_enable_stderr(TRUE); - alter_debug(DEBUG_INC); - break; - case 'L': - USE_LIVE_CIB = TRUE; - break; - case '$': - case '?': - crm_help(flag, 0); - break; - default: - fprintf(stderr, "Option -%c is not yet supported\n", flag); - ++argerr; - break; - } + switch(flag) { + case 'S': + do_simulation = TRUE; + break; + case 'a': + all_actions = TRUE; + break; + case 'w': + inhibit_exit = TRUE; + break; + case 'X': + use_stdin = TRUE; + break; + case 's': + show_scores = TRUE; + break; + case 'U': + show_utilization = TRUE; + break; + case 'x': + xml_file = optarg; + break; + case 'd': + use_date = optarg; + break; + case 'D': + dot_file = optarg; + break; + case 'G': + graph_file = optarg; + break; + case 'I': + input_file = optarg; + break; + case 'V': + cl_log_enable_stderr(TRUE); + alter_debug(DEBUG_INC); + break; + case 'L': + USE_LIVE_CIB = TRUE; + break; + case '$': + case '?': + crm_help(flag, 0); + break; + default: + fprintf(stderr, "Option -%c is not yet supported\n", flag); + ++argerr; + break; } + } - if (optind < argc) { - printf("non-option ARGV-elements: "); - while (optind < argc) { - printf("%s ", argv[optind++]); - } - printf("\n"); + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) { + printf("%s ", argv[optind++]); } + printf("\n"); + } - if (optind > argc) { - ++argerr; - } + if (optind > argc) { + ++argerr; + } - if (argerr) { - crm_err("%d errors in option parsing", argerr); - crm_help('?', 1); - } + if (argerr) { + crm_err("%d errors in option parsing", argerr); + crm_help('?', 1); + } - update_all_trace_data(); /* again, so we see which trace points got updated */ + update_all_trace_data(); /* again, so we see which trace points got updated */ - if(USE_LIVE_CIB) { - int rc = cib_ok; - source = "live cib"; - cib_conn = cib_new(); - rc = cib_conn->cmds->signon(cib_conn, "ptest", cib_command); - - if(rc == cib_ok) { - crm_info("Reading XML from: live cluster"); - cib_object = get_cib_copy(cib_conn); + if(USE_LIVE_CIB) { + int rc = cib_ok; + source = "live cib"; + cib_conn = cib_new(); + rc = cib_conn->cmds->signon(cib_conn, "ptest", cib_command); + + if(rc == cib_ok) { + crm_info("Reading XML from: live cluster"); + cib_object = get_cib_copy(cib_conn); - } else { - fprintf(stderr, "Live CIB query failed: %s\n", - cib_error2string(rc)); - return 3; - } - if(cib_object == NULL) { - fprintf(stderr, "Live CIB query failed: empty result\n"); - return 3; - } - - } else if(xml_file != NULL) { - source = xml_file; - cib_object = filename2xml(xml_file); - - } else if(use_stdin) { - source = "stdin"; - cib_object = filename2xml(NULL); - } - - if(cib_object == NULL && source) { - fprintf(stderr, "Could not parse configuration input from: %s\n", source); - return 4; - - } else if(cib_object == NULL) { - fprintf(stderr, "No configuration specified\n"); - crm_help('?', 1); - } - - if(get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) { - create_xml_node(cib_object, XML_CIB_TAG_STATUS); + } else { + fprintf(stderr, "Live CIB query failed: %s\n", + cib_error2string(rc)); + return 3; } - - if(cli_config_update(&cib_object, NULL, FALSE) == FALSE) { - free_xml(cib_object); - return cib_STALE; - } - - if(validate_xml(cib_object, NULL, FALSE) != TRUE) { - free_xml(cib_object); - return cib_dtd_validation; + if(cib_object == NULL) { + fprintf(stderr, "Live CIB query failed: empty result\n"); + return 3; } + + } else if(xml_file != NULL) { + source = xml_file; + cib_object = filename2xml(xml_file); + + } else if(use_stdin) { + source = "stdin"; + cib_object = filename2xml(NULL); + } + + if(cib_object == NULL && source) { + fprintf(stderr, "Could not parse configuration input from: %s\n", source); + return 4; + + } else if(cib_object == NULL) { + fprintf(stderr, "No configuration specified\n"); + crm_help('?', 1); + } - if(input_file != NULL) { - FILE *input_strm = fopen(input_file, "w"); - if(input_strm == NULL) { - crm_perror(LOG_ERR,"Could not open %s for writing", input_file); - } else { - msg_buffer = dump_xml_formatted(cib_object); - if(fprintf(input_strm, "%s\n", msg_buffer) < 0) { - crm_perror(LOG_ERR,"Write to %s failed", input_file); - } - fflush(input_strm); - fclose(input_strm); - crm_free(msg_buffer); - } - } + if(get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) { + create_xml_node(cib_object, XML_CIB_TAG_STATUS); + } + + if(cli_config_update(&cib_object, NULL, FALSE) == FALSE) { + free_xml(cib_object); + return cib_STALE; + } + + if(validate_xml(cib_object, NULL, FALSE) != TRUE) { + free_xml(cib_object); + return cib_dtd_validation; + } - if(use_date != NULL) { - a_date = parse_date(&use_date); - log_date(LOG_WARNING, "Set fake 'now' to", - a_date, ha_log_date|ha_log_time); - log_date(LOG_WARNING, "Set fake 'now' to (localtime)", - a_date, ha_log_date|ha_log_time|ha_log_local); - } - - set_working_set_defaults(&data_set); - if(process) { - if(show_scores && show_utilization) { - fprintf(stdout, "Allocation scores and utilization information:\n"); - } else if(show_scores) { - fprintf(stdout, "Allocation scores:\n"); - } else if(show_utilization) { - fprintf(stdout, "Utilization information:\n"); + if(input_file != NULL) { + FILE *input_strm = fopen(input_file, "w"); + if(input_strm == NULL) { + crm_perror(LOG_ERR,"Could not open %s for writing", input_file); + } else { + msg_buffer = dump_xml_formatted(cib_object); + if(fprintf(input_strm, "%s\n", msg_buffer) < 0) { + crm_perror(LOG_ERR,"Write to %s failed", input_file); } - do_calculations(&data_set, cib_object, a_date); + fflush(input_strm); + fclose(input_strm); + crm_free(msg_buffer); } + } - msg_buffer = dump_xml_formatted(data_set.graph); - if(safe_str_eq(graph_file, "-")) { - fprintf(stdout, "%s\n", msg_buffer); - fflush(stdout); - } else if(graph_file != NULL) { - FILE *graph_strm = fopen(graph_file, "w"); - if(graph_strm == NULL) { - crm_perror(LOG_ERR,"Could not open %s for writing", graph_file); - } else { - if(fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) { - crm_perror(LOG_ERR,"Write to %s failed", graph_file); - } - fflush(graph_strm); - fclose(graph_strm); - } + if(use_date != NULL) { + a_date = parse_date(&use_date); + log_date(LOG_WARNING, "Set fake 'now' to", + a_date, ha_log_date|ha_log_time); + log_date(LOG_WARNING, "Set fake 'now' to (localtime)", + a_date, ha_log_date|ha_log_time|ha_log_local); + } + + set_working_set_defaults(&data_set); + if(process) { + if(show_scores && show_utilization) { + fprintf(stdout, "Allocation scores and utilization information:\n"); + } else if(show_scores) { + fprintf(stdout, "Allocation scores:\n"); + } else if(show_utilization) { + fprintf(stdout, "Utilization information:\n"); } - crm_free(msg_buffer); - - if(dot_file != NULL) { - dot_strm = fopen(dot_file, "w"); - if(dot_strm == NULL) { - crm_perror(LOG_ERR,"Could not open %s for writing", dot_file); - } + do_calculations(&data_set, cib_object, a_date); + } + + msg_buffer = dump_xml_formatted(data_set.graph); + if(safe_str_eq(graph_file, "-")) { + fprintf(stdout, "%s\n", msg_buffer); + fflush(stdout); + } else if(graph_file != NULL) { + FILE *graph_strm = fopen(graph_file, "w"); + if(graph_strm == NULL) { + crm_perror(LOG_ERR,"Could not open %s for writing", graph_file); + } else { + if(fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) { + crm_perror(LOG_ERR,"Write to %s failed", graph_file); + } + fflush(graph_strm); + fclose(graph_strm); } + } + crm_free(msg_buffer); + if(dot_file != NULL) { + dot_strm = fopen(dot_file, "w"); if(dot_strm == NULL) { - goto simulate; + crm_perror(LOG_ERR,"Could not open %s for writing", dot_file); } + } + + if(dot_strm == NULL) { + goto simulate; + } - init_dotfile(); - slist_iter( - action, action_t, data_set.actions, lpc, - - const char *style = "filled"; - const char *font = "black"; - const char *color = "black"; - const char *fill = NULL; - char *action_name = create_action_name(action); - crm_debug_3("Action %d: %p", action->id, action); - - if(is_set(action->flags, pe_action_pseudo)) { - font = "orange"; - } + init_dotfile(); + for(lpc = data_set.actions; lpc != NULL; lpc = lpc->next) { + action_t *action = (action_t*)lpc->data; + const char *style = "filled"; + const char *font = "black"; + const char *color = "black"; + const char *fill = NULL; + char *action_name = create_action_name(action); + crm_debug_3("Action %d: %p", action->id, action); + + if(is_set(action->flags, pe_action_pseudo)) { + font = "orange"; + } - style = "dashed"; - if(is_set(action->flags, pe_action_dumped)) { - style = "bold"; - color = "green"; + style = "dashed"; + if(is_set(action->flags, pe_action_dumped)) { + style = "bold"; + color = "green"; - } else if(action->rsc != NULL - && is_not_set(action->rsc->flags, pe_rsc_managed)) { - color = "purple"; - if(all_actions == FALSE) { - goto dont_write; - } + } else if(action->rsc != NULL + && is_not_set(action->rsc->flags, pe_rsc_managed)) { + color = "purple"; + if(all_actions == FALSE) { + goto dont_write; + } - } else if(is_set(action->flags, pe_action_optional)) { - color = "blue"; - if(all_actions == FALSE) { - goto dont_write; - } + } else if(is_set(action->flags, pe_action_optional)) { + color = "blue"; + if(all_actions == FALSE) { + goto dont_write; + } - } else { - color = "red"; - CRM_CHECK(is_set(action->flags, pe_action_runnable) == FALSE, ;); - } - - set_bit_inplace(action->flags, pe_action_dumped); - dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]", - action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); - dont_write: - crm_free(action_name); - ); - - - slist_iter( - action, action_t, data_set.actions, lpc, - slist_iter( - before, action_wrapper_t, action->actions_before, lpc2, - char *before_name = NULL; - char *after_name = NULL; - const char *style = "dashed"; - optional = TRUE; - if(before->state == pe_link_dumped) { - optional = FALSE; - style = "bold"; - } else if(is_set(action->flags, pe_action_pseudo) - && (before->type & pe_order_stonith_stop)) { - continue; - } else if(before->state == pe_link_dup) { - continue; - } else if(before->type == pe_order_none) { - continue; - } else if(is_set(before->action->flags, pe_action_dumped) && is_set(action->flags, pe_action_dumped)) { - optional = FALSE; - } - - if(all_actions || optional == FALSE) { - before_name = create_action_name(before->action); - after_name = create_action_name(action); - dot_write("\"%s\" -> \"%s\" [ style = %s]", - before_name, after_name, style); - crm_free(before_name); - crm_free(after_name); - } - ); - ); - dot_write("}"); - if(dot_strm != NULL) { - fflush(dot_strm); - fclose(dot_strm); + } else { + color = "red"; + CRM_CHECK(is_set(action->flags, pe_action_runnable) == FALSE, ;); } - simulate: + set_bit_inplace(action->flags, pe_action_dumped); + dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]", + action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); + dont_write: + crm_free(action_name); + } + + + for(lpc = data_set.actions; lpc != NULL; lpc = lpc->next) { + action_t *action = (action_t*)lpc->data; - if(do_simulation == FALSE) { - goto cleanup; + GListPtr lpc2 = NULL; + for(lpc2 = action->actions_before; lpc2 != NULL; lpc2 = lpc2->next) { + action_wrapper_t *before = (action_wrapper_t*)lpc2->data; + + char *before_name = NULL; + char *after_name = NULL; + const char *style = "dashed"; + optional = TRUE; + if(before->state == pe_link_dumped) { + optional = FALSE; + style = "bold"; + } else if(is_set(action->flags, pe_action_pseudo) + && (before->type & pe_order_stonith_stop)) { + continue; + } else if(before->state == pe_link_dup) { + continue; + } else if(before->type == pe_order_none) { + continue; + } else if(is_set(before->action->flags, pe_action_dumped) && is_set(action->flags, pe_action_dumped)) { + optional = FALSE; + } + + if(all_actions || optional == FALSE) { + before_name = create_action_name(before->action); + after_name = create_action_name(action); + dot_write("\"%s\" -> \"%s\" [ style = %s]", + before_name, after_name, style); + crm_free(before_name); + crm_free(after_name); + } } + } + dot_write("}"); + if(dot_strm != NULL) { + fflush(dot_strm); + fclose(dot_strm); + } + + simulate: + + if(do_simulation == FALSE) { + goto cleanup; + } - transition = unpack_graph(data_set.graph, "ptest"); - print_graph(LOG_DEBUG, transition); + transition = unpack_graph(data_set.graph, "ptest"); + print_graph(LOG_DEBUG, transition); - do { - graph_rc = run_graph(transition); + do { + graph_rc = run_graph(transition); - } while(graph_rc == transition_active); + } while(graph_rc == transition_active); - if(graph_rc != transition_complete) { - crm_crit("Transition failed: %s", transition_status(graph_rc)); - print_graph(LOG_ERR, transition); - } - destroy_graph(transition); - CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced")); + if(graph_rc != transition_complete) { + crm_crit("Transition failed: %s", transition_status(graph_rc)); + print_graph(LOG_ERR, transition); + } + destroy_graph(transition); + CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced")); cleanup: - cleanup_alloc_calculations(&data_set); - crm_log_deinit(); - - /* required for MallocDebug.app */ - if(inhibit_exit) { - GMainLoop* mainloop = g_main_new(FALSE); - g_main_run(mainloop); - } - - if(all_good) { - return 0; - } - return graph_rc; + cleanup_alloc_calculations(&data_set); + crm_log_deinit(); + + /* required for MallocDebug.app */ + if(inhibit_exit) { + GMainLoop* mainloop = g_main_new(FALSE); + g_main_run(mainloop); + } + + if(all_good) { + return 0; + } + return graph_rc; } diff --git a/pengine/utils.c b/pengine/utils.c index 601fc20c5d..d1ff4cd93c 100644 --- a/pengine/utils.c +++ b/pengine/utils.c @@ -1,743 +1,764 @@ /* * 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 void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { - if(cons == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", + if(cons == NULL) { + crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - "rsc_to_node", - cons->id, cons, - g_list_length(cons->node_list_rh)); - - if(details == FALSE) { - crm_debug_4("\t%s (node placement rule)", - safe_val3(NULL, cons, rsc_lh, id)); - - slist_iter( - node, node_t, cons->node_list_rh, lpc, - print_node("\t\t-->", node, FALSE) - ); + pre_text==NULL?"":": "); + return; + } + crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", + pre_text==NULL?"":pre_text, + pre_text==NULL?"":": ", + "rsc_to_node", + cons->id, cons, + g_list_length(cons->node_list_rh)); + + if(details == FALSE) { + GListPtr gIter = NULL; + crm_debug_4("\t%s (node placement rule)", + safe_val3(NULL, cons, rsc_lh, id)); + + gIter = cons->node_list_rh; + for(; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + + print_node("\t\t-->", node, FALSE); } + } } void print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", XML_CONS_TAG_RSC_DEPEND, cons->id, cons); if(details == FALSE) { crm_debug_4("\t%s --> %s, %d", safe_val3(NULL, cons, rsc_lh, id), safe_val3(NULL, cons, rsc_rh, id), cons->score); } } void pe_free_ordering(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { order_constraint_t *order = iterator->data; iterator = iterator->next; crm_free(order->lh_action_task); crm_free(order->rh_action_task); crm_free(order); } if(constraints != NULL) { g_list_free(constraints); } } void pe_free_rsc_to_node(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { rsc_to_node_t *cons = iterator->data; iterator = iterator->next; pe_free_shallow(cons->node_list_rh); crm_free(cons); } if(constraints != NULL) { g_list_free(constraints); } } rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, int node_weight, node_t *foo_node, pe_working_set_t *data_set) { - rsc_to_node_t *new_con = NULL; + rsc_to_node_t *new_con = NULL; - if(rsc == NULL || id == NULL) { - pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); - return NULL; + if(rsc == NULL || id == NULL) { + pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); + return NULL; - } else if(foo_node == NULL) { - CRM_CHECK(node_weight == 0, return NULL); - } + } else if(foo_node == NULL) { + CRM_CHECK(node_weight == 0, return NULL); + } - crm_malloc0(new_con, sizeof(rsc_to_node_t)); - if(new_con != NULL) { - new_con->id = id; - new_con->rsc_lh = rsc; - new_con->node_list_rh = NULL; - new_con->role_filter = RSC_ROLE_UNKNOWN; - - if(foo_node != NULL) { - node_t *copy = node_copy(foo_node); - copy->weight = merge_weights(node_weight, foo_node->weight); - new_con->node_list_rh = g_list_prepend(NULL, copy); - } + crm_malloc0(new_con, sizeof(rsc_to_node_t)); + if(new_con != NULL) { + new_con->id = id; + new_con->rsc_lh = rsc; + new_con->node_list_rh = NULL; + new_con->role_filter = RSC_ROLE_UNKNOWN; - data_set->placement_constraints = g_list_prepend( - data_set->placement_constraints, new_con); - rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con); + if(foo_node != NULL) { + node_t *copy = node_copy(foo_node); + copy->weight = merge_weights(node_weight, foo_node->weight); + new_con->node_list_rh = g_list_prepend(NULL, copy); } + + data_set->placement_constraints = g_list_prepend( + data_set->placement_constraints, new_con); + rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con); + } - return new_con; + return new_con; } const char * ordering_type2text(enum pe_ordering type) { - const char *result = ""; - if(type & pe_order_optional) { - /* was: mandatory */ - result = "right_implies_left"; - - } else if(type & pe_order_implies_then) { - /* was: recover */ - result = "left_implies_right"; - - } else if(type & pe_order_optional) { - /* pure ordering, nothing implied */ - result = "optional"; + const char *result = ""; + if(type & pe_order_optional) { + /* was: mandatory */ + result = "right_implies_left"; + + } else if(type & pe_order_implies_then) { + /* was: recover */ + result = "left_implies_right"; + + } else if(type & pe_order_optional) { + /* pure ordering, nothing implied */ + result = "optional"; - } else if(type & pe_order_runnable_left) { - result = "runnable"; + } else if(type & pe_order_runnable_left) { + result = "runnable"; /* } else { */ /* crm_err("Unknown ordering type: %.3x", type); */ - } + } - return result; + return result; } gboolean can_run_resources(const node_t *node) { - if(node == NULL) { - return FALSE; - } + if(node == NULL) { + return FALSE; + } #if 0 - if(node->weight < 0) { - return FALSE; - } + if(node->weight < 0) { + return FALSE; + } #endif - if(node->details->online == FALSE - || node->details->shutdown - || node->details->unclean - || node->details->standby) { - crm_debug_2("%s: online=%d, unclean=%d, standby=%d", - node->details->uname, node->details->online, - node->details->unclean, node->details->standby); - return FALSE; - } - return TRUE; + if(node->details->online == FALSE + || node->details->shutdown + || node->details->unclean + || node->details->standby) { + crm_debug_2("%s: online=%d, unclean=%d, standby=%d", + node->details->uname, node->details->online, + node->details->unclean, node->details->standby); + return FALSE; + } + return TRUE; } struct compare_data { const node_t *node1; const node_t *node2; int result; }; static void do_compare_capacity1(gpointer key, gpointer value, gpointer user_data) { - int node1_capacity = 0; - int node2_capacity = 0; - struct compare_data *data = user_data; + int node1_capacity = 0; + int node2_capacity = 0; + struct compare_data *data = user_data; - node1_capacity = crm_parse_int(value, "0"); - node2_capacity = crm_parse_int(g_hash_table_lookup(data->node2->details->utilization, key), "0"); + node1_capacity = crm_parse_int(value, "0"); + node2_capacity = crm_parse_int(g_hash_table_lookup(data->node2->details->utilization, key), "0"); - if (node1_capacity > node2_capacity) { - data->result--; - } else if (node1_capacity < node2_capacity) { - data->result++; - } + if (node1_capacity > node2_capacity) { + data->result--; + } else if (node1_capacity < node2_capacity) { + data->result++; + } } static void do_compare_capacity2(gpointer key, gpointer value, gpointer user_data) { - int node1_capacity = 0; - int node2_capacity = 0; - struct compare_data *data = user_data; + int node1_capacity = 0; + int node2_capacity = 0; + struct compare_data *data = user_data; - if (g_hash_table_lookup_extended(data->node1->details->utilization, key, NULL, NULL)) { - return; - } + if (g_hash_table_lookup_extended(data->node1->details->utilization, key, NULL, NULL)) { + return; + } - node1_capacity = 0; - node2_capacity = crm_parse_int(value, "0"); + node1_capacity = 0; + node2_capacity = crm_parse_int(value, "0"); - if (node1_capacity > node2_capacity) { - data->result--; - } else if (node1_capacity < node2_capacity) { - data->result++; - } + if (node1_capacity > node2_capacity) { + data->result--; + } else if (node1_capacity < node2_capacity) { + data->result++; + } } /* rc < 0 if 'node1' has more capacity remaining * rc > 0 if 'node1' has less capacity remaining */ static int compare_capacity(const node_t *node1, const node_t *node2) { - struct compare_data data; + struct compare_data data; - data.node1 = node1; - data.node2 = node2; - data.result = 0; + data.node1 = node1; + data.node2 = node2; + data.result = 0; - g_hash_table_foreach(node1->details->utilization, do_compare_capacity1, &data); - g_hash_table_foreach(node2->details->utilization, do_compare_capacity2, &data); + g_hash_table_foreach(node1->details->utilization, do_compare_capacity1, &data); + g_hash_table_foreach(node2->details->utilization, do_compare_capacity2, &data); - return data.result; + return data.result; } /* return -1 if 'a' is more preferred * return 1 if 'b' is more preferred */ gint sort_node_weight(gconstpointer a, gconstpointer b, gpointer data) { - int level = LOG_DEBUG_3; - const node_t *node1 = (const node_t*)a; - const node_t *node2 = (const node_t*)b; - const node_t *active = (node_t*)data; + int level = LOG_DEBUG_3; + const node_t *node1 = (const node_t*)a; + const node_t *node2 = (const node_t*)b; + const node_t *active = (node_t*)data; - int node1_weight = 0; - int node2_weight = 0; + int node1_weight = 0; + int node2_weight = 0; - int result = 0; + int result = 0; - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } + if(a == NULL) { return 1; } + if(b == NULL) { return -1; } - node1_weight = node1->weight; - node2_weight = node2->weight; + node1_weight = node1->weight; + node2_weight = node2->weight; - if(can_run_resources(node1) == FALSE) { - node1_weight = -INFINITY; - } - if(can_run_resources(node2) == FALSE) { - node2_weight = -INFINITY; - } + if(can_run_resources(node1) == FALSE) { + node1_weight = -INFINITY; + } + if(can_run_resources(node2) == FALSE) { + node2_weight = -INFINITY; + } - if(node1_weight > node2_weight) { - do_crm_log_unlikely(level, "%s (%d) > %s (%d) : weight", - node1->details->uname, node1_weight, - node2->details->uname, node2_weight); - return -1; - } + if(node1_weight > node2_weight) { + do_crm_log_unlikely(level, "%s (%d) > %s (%d) : weight", + node1->details->uname, node1_weight, + node2->details->uname, node2_weight); + return -1; + } - if(node1_weight < node2_weight) { - do_crm_log_unlikely(level, "%s (%d) < %s (%d) : weight", + if(node1_weight < node2_weight) { + do_crm_log_unlikely(level, "%s (%d) < %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); - return 1; - } + return 1; + } - do_crm_log_unlikely(level, "%s (%d) == %s (%d) : weight", - node1->details->uname, node1_weight, - node2->details->uname, node2_weight); + do_crm_log_unlikely(level, "%s (%d) == %s (%d) : weight", + node1->details->uname, node1_weight, + node2->details->uname, node2_weight); - if (safe_str_eq(pe_dataset->placement_strategy, "minimal")) { - goto equal; - } + if (safe_str_eq(pe_dataset->placement_strategy, "minimal")) { + goto equal; + } - if (safe_str_eq(pe_dataset->placement_strategy, "balanced")) { - result = compare_capacity(node1, node2); - if (result != 0) { - return result; - } + if (safe_str_eq(pe_dataset->placement_strategy, "balanced")) { + result = compare_capacity(node1, node2); + if (result != 0) { + return result; } + } - /* now try to balance resources across the cluster */ - if(node1->details->num_resources - < node2->details->num_resources) { - do_crm_log_unlikely(level, "%s (%d) < %s (%d) : resources", + /* now try to balance resources across the cluster */ + if(node1->details->num_resources + < node2->details->num_resources) { + do_crm_log_unlikely(level, "%s (%d) < %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); - return -1; + return -1; - } else if(node1->details->num_resources - > node2->details->num_resources) { - do_crm_log_unlikely(level, "%s (%d) > %s (%d) : resources", + } else if(node1->details->num_resources + > node2->details->num_resources) { + do_crm_log_unlikely(level, "%s (%d) > %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); - return 1; - } + return 1; + } - if(active && active->details == node1->details) { - do_crm_log_unlikely(level, "%s (%d) > %s (%d) : active", - node1->details->uname, node1->details->num_resources, - node2->details->uname, node2->details->num_resources); - return -1; - } else if(active && active->details == node2->details) { - do_crm_log_unlikely(level, "%s (%d) > %s (%d) : active", - node1->details->uname, node1->details->num_resources, - node2->details->uname, node2->details->num_resources); - return 1; - } -equal: - do_crm_log_unlikely(level, "%s = %s", node1->details->uname, node2->details->uname); - return strcmp(node1->details->uname, node2->details->uname); + if(active && active->details == node1->details) { + do_crm_log_unlikely(level, "%s (%d) > %s (%d) : active", + node1->details->uname, node1->details->num_resources, + node2->details->uname, node2->details->num_resources); + return -1; + } else if(active && active->details == node2->details) { + do_crm_log_unlikely(level, "%s (%d) > %s (%d) : active", + node1->details->uname, node1->details->num_resources, + node2->details->uname, node2->details->num_resources); + return 1; + } + equal: + do_crm_log_unlikely(level, "%s = %s", node1->details->uname, node2->details->uname); + return strcmp(node1->details->uname, node2->details->uname); } struct calculate_data { node_t *node; gboolean allocate; }; static void do_calculate_utilization(gpointer key, gpointer value, gpointer user_data) { - const char *capacity = NULL; - char *remain_capacity = NULL; - struct calculate_data *data = user_data; - - capacity = g_hash_table_lookup(data->node->details->utilization, key); - if (capacity) { - if (data->allocate) { - remain_capacity = crm_itoa(crm_parse_int(capacity, "0") - crm_parse_int(value, "0")); - } else { - remain_capacity = crm_itoa(crm_parse_int(capacity, "0") + crm_parse_int(value, "0")); - } - g_hash_table_replace(data->node->details->utilization, crm_strdup(key), remain_capacity); + const char *capacity = NULL; + char *remain_capacity = NULL; + struct calculate_data *data = user_data; + + capacity = g_hash_table_lookup(data->node->details->utilization, key); + if (capacity) { + if (data->allocate) { + remain_capacity = crm_itoa(crm_parse_int(capacity, "0") - crm_parse_int(value, "0")); + } else { + remain_capacity = crm_itoa(crm_parse_int(capacity, "0") + crm_parse_int(value, "0")); } + g_hash_table_replace(data->node->details->utilization, crm_strdup(key), remain_capacity); + } } /* Specify 'allocate' to TRUE when allocating * Otherwise to FALSE when deallocating */ static void calculate_utilization(node_t *node, resource_t *rsc, gboolean allocate) { - struct calculate_data data; + struct calculate_data data; - data.node = node; - data.allocate = allocate; + data.node = node; + data.allocate = allocate; - g_hash_table_foreach(rsc->utilization, do_calculate_utilization, &data); + g_hash_table_foreach(rsc->utilization, do_calculate_utilization, &data); - if (allocate) { - dump_rsc_utilization(show_utilization?0:utilization_log_level, __FUNCTION__, rsc, node); - } + if (allocate) { + dump_rsc_utilization(show_utilization?0:utilization_log_level, __FUNCTION__, rsc, node); + } } gboolean native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen, gboolean force) { - CRM_ASSERT(rsc->variant == pe_native); + CRM_ASSERT(rsc->variant == pe_native); - clear_bit(rsc->flags, pe_rsc_provisional); + clear_bit(rsc->flags, pe_rsc_provisional); - if(force == FALSE - && chosen != NULL - && (can_run_resources(chosen) == FALSE || chosen->weight < 0)) { - crm_debug("All nodes for resource %s are unavailable" - ", unclean or shutting down (%s: %d, %d)", - rsc->id, chosen->details->uname, can_run_resources(chosen), chosen->weight); - rsc->next_role = RSC_ROLE_STOPPED; - chosen = NULL; - } + if(force == FALSE + && chosen != NULL + && (can_run_resources(chosen) == FALSE || chosen->weight < 0)) { + crm_debug("All nodes for resource %s are unavailable" + ", unclean or shutting down (%s: %d, %d)", + rsc->id, chosen->details->uname, can_run_resources(chosen), chosen->weight); + rsc->next_role = RSC_ROLE_STOPPED; + chosen = NULL; + } - /* todo: update the old node for each resource to reflect its - * new resource count - */ - - if(rsc->allocated_to) { - node_t *old = rsc->allocated_to; - crm_info("Deallocating %s from %s", rsc->id, old->details->uname); - old->details->allocated_rsc = g_list_remove( - old->details->allocated_rsc, rsc); - old->details->num_resources--; - old->count--; - calculate_utilization(old, rsc, FALSE); - } + /* todo: update the old node for each resource to reflect its + * new resource count + */ + + if(rsc->allocated_to) { + node_t *old = rsc->allocated_to; + crm_info("Deallocating %s from %s", rsc->id, old->details->uname); + old->details->allocated_rsc = g_list_remove( + old->details->allocated_rsc, rsc); + old->details->num_resources--; + old->count--; + calculate_utilization(old, rsc, FALSE); + } - if(chosen == NULL) { - char *key = NULL; - GListPtr possible_matches = NULL; + if(chosen == NULL) { + char *key = NULL; + GListPtr gIter = NULL; + GListPtr possible_matches = NULL; - crm_debug("Could not allocate a node for %s", rsc->id); - rsc->next_role = RSC_ROLE_STOPPED; + crm_debug("Could not allocate a node for %s", rsc->id); + rsc->next_role = RSC_ROLE_STOPPED; - key = generate_op_key(rsc->id, CRMD_ACTION_STOP, 0); - possible_matches = find_actions(rsc->actions, key, NULL); + key = generate_op_key(rsc->id, CRMD_ACTION_STOP, 0); + possible_matches = find_actions(rsc->actions, key, NULL); - slist_iter( - stop, action_t, possible_matches, lpc, - update_action_flags(stop, pe_action_optional|pe_action_clear); - ); + gIter = possible_matches; + for(; gIter != NULL; gIter = gIter->next) { + action_t *stop = (action_t*)gIter->data; + update_action_flags(stop, pe_action_optional|pe_action_clear); + } - g_list_free(possible_matches); - crm_free(key); + g_list_free(possible_matches); + crm_free(key); - key = generate_op_key(rsc->id, CRMD_ACTION_START, 0); - possible_matches = find_actions(rsc->actions, key, NULL); + key = generate_op_key(rsc->id, CRMD_ACTION_START, 0); + possible_matches = find_actions(rsc->actions, key, NULL); - slist_iter( - start, action_t, possible_matches, lpc, - update_action_flags(start, pe_action_runnable|pe_action_clear); - ); + gIter = possible_matches; + for(; gIter != NULL; gIter = gIter->next) { + action_t *start = (action_t*)gIter->data; + + update_action_flags(start, pe_action_runnable|pe_action_clear); + } - g_list_free(possible_matches); - crm_free(key); + g_list_free(possible_matches); + crm_free(key); - return FALSE; - } + return FALSE; + } - crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id); - crm_free(rsc->allocated_to); - rsc->allocated_to = node_copy(chosen); + crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id); + crm_free(rsc->allocated_to); + rsc->allocated_to = node_copy(chosen); - chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc, rsc); - chosen->details->num_resources++; - chosen->count++; - calculate_utilization(chosen, rsc, TRUE); - return TRUE; + chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc, rsc); + chosen->details->num_resources++; + chosen->count++; + calculate_utilization(chosen, rsc, TRUE); + return TRUE; } char * convert_non_atomic_uuid(char *old_uuid, resource_t *rsc, gboolean allow_notify, gboolean free_original) { int interval = 0; char *uuid = NULL; char *rid = NULL; char *raw_task = NULL; int task = no_action; crm_debug_3("Processing %s", old_uuid); if(old_uuid == NULL) { return NULL; } else if(strstr(old_uuid, "notify") != NULL) { goto done; /* no conversion */ } else if(rsc->variant < pe_group) { goto done; /* no conversion */ } CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval)); if(interval > 0) { goto done; /* no conversion */ } task = text2task(raw_task); switch(task) { case stop_rsc: case start_rsc: case action_notify: case action_promote: case action_demote: break; case stopped_rsc: case started_rsc: case action_notified: case action_promoted: case action_demoted: task--; break; case monitor_rsc: case shutdown_crm: case stonith_node: task = no_action; break; default: crm_err("Unknown action: %s", raw_task); task = no_action; break; } if(task != no_action) { if(is_set(rsc->flags, pe_rsc_notify) && allow_notify) { uuid = generate_notify_key(rid, "confirmed-post", task2text(task+1)); } else { uuid = generate_op_key(rid, task2text(task+1), 0); } crm_debug_2("Converted %s -> %s", old_uuid, uuid); } done: if(uuid == NULL) { uuid = crm_strdup(old_uuid); } if(free_original) { crm_free(old_uuid); } crm_free(raw_task); crm_free(rid); return uuid; } gboolean order_actions( - action_t *lh_action, action_t *rh_action, enum pe_ordering order) + action_t *lh_action, action_t *rh_action, enum pe_ordering order) { - action_wrapper_t *wrapper = NULL; - GListPtr list = NULL; - static int load_stopped_strlen = 0; + GListPtr gIter = NULL; + action_wrapper_t *wrapper = NULL; + GListPtr list = NULL; + static int load_stopped_strlen = 0; - if(order == pe_order_none) { + if(order == pe_order_none) { + return FALSE; + } + + if (!load_stopped_strlen) { + load_stopped_strlen = strlen(LOAD_STOPPED); + } + + if (strncmp(lh_action->uuid, LOAD_STOPPED, load_stopped_strlen) == 0 + || strncmp(rh_action->uuid, LOAD_STOPPED, load_stopped_strlen) == 0) { + if (lh_action->node == NULL || rh_action->node == NULL + || lh_action->node->details != rh_action->node->details) { return FALSE; } + } - if (!load_stopped_strlen) { - load_stopped_strlen = strlen(LOAD_STOPPED); - } + crm_debug_3("Ordering Action %s before %s", + lh_action->uuid, rh_action->uuid); + + log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE); + log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE); - if (strncmp(lh_action->uuid, LOAD_STOPPED, load_stopped_strlen) == 0 - || strncmp(rh_action->uuid, LOAD_STOPPED, load_stopped_strlen) == 0) { - if (lh_action->node == NULL || rh_action->node == NULL - || lh_action->node->details != rh_action->node->details) { - return FALSE; - } + /* Filter dups, otherwise update_action_states() has too much work to do */ + gIter = lh_action->actions_after; + for(; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *after = (action_wrapper_t*)gIter->data; + + if(after->action == rh_action && (after->type & order)) { + return FALSE; } + } - crm_debug_3("Ordering Action %s before %s", - lh_action->uuid, rh_action->uuid); - - log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE); - log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE); - - /* Filter dups, otherwise update_action_states() has too much work to do */ - slist_iter(after, action_wrapper_t, lh_action->actions_after, lpc, - if(after->action == rh_action && (after->type & order)) { - return FALSE; - } - ); - - crm_malloc0(wrapper, sizeof(action_wrapper_t)); - wrapper->action = rh_action; - wrapper->type = order; + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = rh_action; + wrapper->type = order; - list = lh_action->actions_after; - list = g_list_prepend(list, wrapper); - lh_action->actions_after = list; + list = lh_action->actions_after; + list = g_list_prepend(list, wrapper); + lh_action->actions_after = list; - wrapper = NULL; + wrapper = NULL; /* order |= pe_order_implies_then; */ /* order ^= pe_order_implies_then; */ - crm_malloc0(wrapper, sizeof(action_wrapper_t)); - wrapper->action = lh_action; - wrapper->type = order; - list = rh_action->actions_before; - list = g_list_prepend(list, wrapper); - rh_action->actions_before = list; - return TRUE; + crm_malloc0(wrapper, sizeof(action_wrapper_t)); + wrapper->action = lh_action; + wrapper->type = order; + list = rh_action->actions_before; + list = g_list_prepend(list, wrapper); + rh_action->actions_before = list; + return TRUE; } void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) { - const char *node_uname = NULL; - const char *node_uuid = NULL; + const char *node_uname = NULL; + const char *node_uuid = NULL; - if(action == NULL) { + if(action == NULL) { - do_crm_log_unlikely(log_level, "%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } + do_crm_log_unlikely(log_level, "%s%s: ", + pre_text==NULL?"":pre_text, + pre_text==NULL?"":": "); + return; + } - if(is_set(action->flags, pe_action_pseudo)) { - node_uname = NULL; - node_uuid = NULL; + if(is_set(action->flags, pe_action_pseudo)) { + node_uname = NULL; + node_uuid = NULL; - } else if(action->node != NULL) { - node_uname = action->node->details->uname; - node_uuid = action->node->details->id; - } else { - node_uname = ""; - node_uuid = NULL; - } + } else if(action->node != NULL) { + node_uname = action->node->details->uname; + node_uuid = action->node->details->id; + } else { + node_uname = ""; + node_uuid = NULL; + } - switch(text2task(action->task)) { - case stonith_node: - case shutdown_crm: - do_crm_log_unlikely(log_level, - "%s%s%sAction %d: %s%s%s%s%s%s", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - is_set(action->flags, pe_action_pseudo)?"Pseduo ":is_set(action->flags, pe_action_optional)?"Optional ":is_set(action->flags, pe_action_runnable)?is_set(action->flags, pe_action_processed)?"":"(Provisional) ":"!!Non-Startable!! ", - action->id, action->uuid, - node_uname?"\ton ":"", - node_uname?node_uname:"", - node_uuid?"\t\t(":"", - node_uuid?node_uuid:"", - node_uuid?")":""); - break; - default: - do_crm_log_unlikely(log_level, - "%s%s%sAction %d: %s %s%s%s%s%s%s", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - is_set(action->flags, pe_action_optional)?"Optional ":is_set(action->flags, pe_action_pseudo)?"Pseduo ":is_set(action->flags, pe_action_runnable)?is_set(action->flags, pe_action_processed)?"":"(Provisional) ":"!!Non-Startable!! ", - action->id, action->uuid, - safe_val3("", action, rsc, id), - node_uname?"\ton ":"", - node_uname?node_uname:"", - node_uuid?"\t\t(":"", - node_uuid?node_uuid:"", - node_uuid?")":""); + switch(text2task(action->task)) { + case stonith_node: + case shutdown_crm: + do_crm_log_unlikely(log_level, + "%s%s%sAction %d: %s%s%s%s%s%s", + pre_text==NULL?"":pre_text, + pre_text==NULL?"":": ", + is_set(action->flags, pe_action_pseudo)?"Pseduo ":is_set(action->flags, pe_action_optional)?"Optional ":is_set(action->flags, pe_action_runnable)?is_set(action->flags, pe_action_processed)?"":"(Provisional) ":"!!Non-Startable!! ", + action->id, action->uuid, + node_uname?"\ton ":"", + node_uname?node_uname:"", + node_uuid?"\t\t(":"", + node_uuid?node_uuid:"", + node_uuid?")":""); + break; + default: + do_crm_log_unlikely(log_level, + "%s%s%sAction %d: %s %s%s%s%s%s%s", + pre_text==NULL?"":pre_text, + pre_text==NULL?"":": ", + is_set(action->flags, pe_action_optional)?"Optional ":is_set(action->flags, pe_action_pseudo)?"Pseduo ":is_set(action->flags, pe_action_runnable)?is_set(action->flags, pe_action_processed)?"":"(Provisional) ":"!!Non-Startable!! ", + action->id, action->uuid, + safe_val3("", action, rsc, id), + node_uname?"\ton ":"", + node_uname?node_uname:"", + node_uuid?"\t\t(":"", + node_uuid?node_uuid:"", + node_uuid?")":""); - break; - } + break; + } - if(details) { - do_crm_log_unlikely(log_level+1, "\t\t====== Preceding Actions"); - slist_iter( - other, action_wrapper_t, action->actions_before, lpc, - log_action(log_level+1, "\t\t", other->action, FALSE); - ); - do_crm_log_unlikely(log_level+1, "\t\t====== Subsequent Actions"); - slist_iter( - other, action_wrapper_t, action->actions_after, lpc, - log_action(log_level+1, "\t\t", other->action, FALSE); - ); - do_crm_log_unlikely(log_level+1, "\t\t====== End"); + if(details) { + GListPtr gIter = NULL; - } else { - do_crm_log_unlikely(log_level, "\t\t(seen=%d, before=%d, after=%d)", - action->seen_count, - g_list_length(action->actions_before), - g_list_length(action->actions_after)); + do_crm_log_unlikely(log_level+1, "\t\t====== Preceding Actions"); + + gIter = action->actions_before; + for(; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other = (action_wrapper_t*)gIter->data; + log_action(log_level+1, "\t\t", other->action, FALSE); + } + + do_crm_log_unlikely(log_level+1, "\t\t====== Subsequent Actions"); + + gIter = action->actions_after; + for(; gIter != NULL; gIter = gIter->next) { + action_wrapper_t *other = (action_wrapper_t*)gIter->data; + log_action(log_level+1, "\t\t", other->action, FALSE); } + + do_crm_log_unlikely(log_level+1, "\t\t====== End"); + + } else { + do_crm_log_unlikely(log_level, "\t\t(seen=%d, before=%d, after=%d)", + action->seen_count, + g_list_length(action->actions_before), + g_list_length(action->actions_after)); + } } action_t *get_pseudo_op(const char *name, pe_working_set_t *data_set) { action_t *op = NULL; const char *op_s = name; GListPtr possible_matches = NULL; possible_matches = find_actions(data_set->actions, name, NULL); if(possible_matches != NULL) { if(g_list_length(possible_matches) > 1) { pe_warn("Action %s exists %d times", name, g_list_length(possible_matches)); } op = g_list_nth_data(possible_matches, 0); g_list_free(possible_matches); } else { op = custom_action(NULL, crm_strdup(op_s), op_s, NULL, TRUE, TRUE, data_set); update_action_flags(op, pe_action_pseudo); update_action_flags(op, pe_action_runnable); } return op; } gboolean can_run_any(GHashTable *nodes) { - GHashTableIter iter; - node_t *node = NULL; - if(nodes == NULL) { - return FALSE; - } + GHashTableIter iter; + node_t *node = NULL; + if(nodes == NULL) { + return FALSE; + } - g_hash_table_iter_init (&iter, nodes); - while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { - if(can_run_resources(node) && node->weight >= 0) { - return TRUE; - } + g_hash_table_iter_init (&iter, nodes); + while (g_hash_table_iter_next (&iter, NULL, (void**)&node)) { + if(can_run_resources(node) && node->weight >= 0) { + return TRUE; } + } - return FALSE; + return FALSE; } enum rsc_role_e minimum_resource_state(resource_t *rsc, gboolean current) { enum rsc_role_e min_role = RSC_ROLE_MAX; if(rsc->children) { - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - enum rsc_role_e role = child_rsc->fns->state(child_rsc, current); - if(role < min_role) { - min_role = role; - } - ); + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t*)gIter->data; + enum rsc_role_e role = child_rsc->fns->state(child_rsc, current); + + if(role < min_role) { + min_role = role; + } + } return min_role; } return rsc->fns->state(rsc, current); } diff --git a/tools/ccm_epoche.c b/tools/ccm_epoche.c index 1ffafcbb1d..5e6c894ef3 100644 --- a/tools/ccm_epoche.c +++ b/tools/ccm_epoche.c @@ -1,559 +1,563 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include /* for basename() */ #include #include #include #include int command = 0; int ccm_fd = 0; gboolean do_quiet = FALSE; char *target_uuid = NULL; char *target_uname = NULL; const char *standby_value = NULL; const char *standby_scope = NULL; #include <../lib/common/stack.h> static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\tThis text"}, {"version", 0, 0, '$', "\tVersion information" }, {"verbose", 0, 0, 'V', "\tIncrease debug output"}, {"quiet", 0, 0, 'Q', "\tEssential output only"}, {"-spacer-", 1, 0, '-', "\nStack:"}, #ifdef SUPPORT_CMAN {"cman", 0, 0, 'c', "\tOnly try connecting to a cman-based cluster"}, #endif #ifdef SUPPORT_COROSYNC {"openais", 0, 0, 'A', "\tOnly try connecting to an OpenAIS-based cluster"}, #endif #ifdef SUPPORT_HEARTBEAT {"heartbeat", 0, 0, 'H', "Only try connecting to a Heartbeat-based cluster"}, #endif {"-spacer-", 1, 0, '-', "\nCommands:"}, {"epoch", 0, 0, 'e', "\tDisplay the epoch during which this node joined the cluster"}, {"quorum", 0, 0, 'q', "\tDisplay a 1 if our partition has quorum, 0 if not"}, {"list", 0, 0, 'l', "\tDisplay all known members (past and present) of this cluster (Not available for heartbeat clusters)"}, {"partition", 0, 0, 'p', "Display the members of this partition"}, {"cluster-id", 0, 0, 'i', "Display this node's cluster id"}, {"remove", 1, 0, 'R', "(Advanced, AIS-Only) Remove the (stopped) node with the specified nodeid from the cluster"}, {"-spacer-", 1, 0, '-', "\nAdditional Options:"}, {"force", 0, 0, 'f'}, {0, 0, 0, 0} }; int local_id = 0; #if SUPPORT_HEARTBEAT # include # include # include # define UUID_LEN 16 oc_ev_t *ccm_token = NULL; void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); static gboolean read_local_hb_uuid(void) { cl_uuid_t uuid; char *buffer = NULL; long start = 0, read_len = 0; FILE *input = fopen(UUID_FILE, "r"); if(input == NULL) { crm_info("Could not open UUID file %s\n", UUID_FILE); return FALSE; } /* see how big the file is */ start = ftell(input); fseek(input, 0L, SEEK_END); if(UUID_LEN != ftell(input)) { fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN); abort(); } fseek(input, 0L, start); if(start != ftell(input)) { fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input)); exit(2); } buffer = malloc(50); read_len = fread(uuid.uuid, 1, UUID_LEN, input); if(read_len != UUID_LEN) { fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len); exit(3); } else if(buffer != NULL) { cl_uuid_unparse(&uuid, buffer); fprintf(stdout, "%s\n", buffer); return TRUE; } else { fprintf(stderr, "No buffer to unparse\n"); exit(4); } free(buffer); fclose(input); return FALSE; } static void ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data) { int lpc; int node_list_size; const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data; node_list_size = oc->m_n_member; if(command == 'q') { crm_debug("Processing \"%s\" event.", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); if(ccm_have_quorum(event)) { fprintf(stdout, "1\n"); } else { fprintf(stdout, "0\n"); } } else if(command == 'e') { crm_debug("Searching %d members for our birth", oc->m_n_member); } for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname); } else if(command == 'e') { if(oc_ev_is_my_nodeid(ccm_token, &(oc->m_array[lpc]))){ crm_debug("MATCH: nodeid=%d, uname=%s, born=%d", oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_born_on); fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx+lpc].node_born_on); } } } oc_ev_callback_done(cookie); if(command == 'p') { fprintf(stdout, "\n"); } fflush(stdout); exit(0); } static gboolean ccm_age_connect(int *ccm_fd) { gboolean did_fail = FALSE; int ret = 0; crm_debug("Registering with CCM"); ret = oc_ev_register(&ccm_token); if (ret != 0) { crm_info("CCM registration failed: %d", ret); did_fail = TRUE; } if(did_fail == FALSE) { crm_debug("Setting up CCM callbacks"); ret = oc_ev_set_callback(ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set: %d", ret); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(ccm_token, OC_EV_MEMB_CLASS, 0/*don't care*/); crm_debug("Activating CCM token"); ret = oc_ev_activate(ccm_token, ccm_fd); if (ret != 0){ crm_warn("CCM Activation failed: %d", ret); did_fail = TRUE; } } return !did_fail; } static gboolean try_heartbeat(int command) { crm_debug("Attempting to process %c command", command); if(command == 'i') { if(read_local_hb_uuid()) { exit(0); } } else if(ccm_age_connect(&ccm_fd)) { int rc = 0; fd_set rset; while (1) { sleep(1); FD_ZERO(&rset); FD_SET(ccm_fd, &rset); errno = 0; rc = select(ccm_fd + 1, &rset, NULL,NULL,NULL); if(rc > 0 && oc_ev_handle_event(ccm_token) != 0) { crm_err("oc_ev_handle_event failed"); return FALSE; } else if(rc < 0 && errno != EINTR) { crm_perror(LOG_ERR, "select failed: %d", rc); return FALSE; } } } return FALSE; } #endif #if SUPPORT_CMAN # include # define MAX_NODES 256 static gboolean try_cman(int command) { int rc = -1, lpc = 0, node_count = 0; cman_node_t node; cman_cluster_t cluster; cman_handle_t cman_handle = NULL; cman_node_t cman_nodes[MAX_NODES]; memset(&cluster, 0, sizeof(cluster)); crm_debug("Attempting to process %c command", command); cman_handle = cman_init(NULL); if(cman_handle == NULL || cman_is_active(cman_handle) == FALSE) { crm_info("Couldn't connect to cman"); return FALSE; } switch(command) { case 'R': fprintf(stderr, "Node removal not supported for cman based clusters\n"); exit(cib_NOTSUPPORTED); break; case 'e': /* Age makes no sense (yet?) in a cman cluster */ fprintf(stdout, "1\n"); break; case 'q': fprintf(stdout, "%d\n", cman_is_quorate(cman_handle)); break; case 'l': case 'p': rc = cman_get_nodes(cman_handle, MAX_NODES, &node_count, cman_nodes); if (rc != 0) { fprintf(stderr, "Couldn't query cman node list: %d %d", rc, errno); goto cman_bail; } for (lpc = 0; lpc < node_count; lpc++) { if(command == 'l') { printf("%s ", cman_nodes[lpc].cn_name); } else if (cman_nodes[lpc].cn_nodeid != 0 && cman_nodes[lpc].cn_member) { /* Never allow node ID 0 to be considered a member #315711 */ printf("%s ", cman_nodes[lpc].cn_name); } } printf("\n"); break; case 'i': rc = cman_get_node(cman_handle, CMAN_NODEID_US, &node); if ( rc != 0) { fprintf(stderr, "Couldn't query cman node id: %d %d", rc, errno); goto cman_bail; } fprintf(stdout, "%u\n", node.cn_nodeid); break; default: fprintf(stderr, "Unknown option '%c'\n", command); crm_help('?', LSB_EXIT_GENERIC); } cman_finish(cman_handle); exit(0); cman_bail: cman_finish(cman_handle); exit(LSB_EXIT_GENERIC); } #endif #if SUPPORT_COROSYNC static void ais_membership_destroy(gpointer user_data) { crm_err("AIS connection terminated"); ais_fd_sync = -1; exit(1); } static gint member_sort(gconstpointer a, gconstpointer b) { const crm_node_t *node_a = a; const crm_node_t *node_b = b; return strcmp(node_a->uname, node_b->uname); } static void crm_add_member( gpointer key, gpointer value, gpointer user_data) { GList **list = user_data; crm_node_t *node = value; if(node->uname != NULL) { *list = g_list_insert_sorted(*list, node, member_sort); } } static gboolean ais_membership_dispatch(AIS_Message *wrapper, char *data, int sender) { switch(wrapper->header.id) { case crm_class_members: case crm_class_notify: case crm_class_quorum: break; default: return TRUE; break; } if(command == 'q') { if(crm_have_quorum) { fprintf(stdout, "1\n"); } else { fprintf(stdout, "0\n"); } } else if(command == 'l') { GList *nodes = NULL; + GListPtr lpc = NULL; g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes); - slist_iter(node, crm_node_t, nodes, lpc, - fprintf(stdout, "%u %s %s\n", node->id, node->uname, node->state); - ); + for(lpc = nodes; lpc != NULL; lpc = lpc->next) { + crm_node_t *node = (crm_node_t*)lpc->data; + fprintf(stdout, "%u %s %s\n", node->id, node->uname, node->state); + } fprintf(stdout, "\n"); } else if(command == 'p') { GList *nodes = NULL; + GListPtr lpc = NULL; g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes); - slist_iter(node, crm_node_t, nodes, lpc, - if(node->uname && crm_is_member_active(node)) { - fprintf(stdout, "%s ", node->uname); - } - ); + for(lpc = nodes; lpc != NULL; lpc = lpc->next) { + crm_node_t *node = (crm_node_t*)lpc->data; + if(node->uname && crm_is_member_active(node)) { + fprintf(stdout, "%s ", node->uname); + } + } fprintf(stdout, "\n"); } exit(0); return TRUE; } static gboolean try_corosync(int command) { crm_debug("Attempting to process %c command", command); if(init_ais_connection_once( pcmk_cluster_classic_ais, ais_membership_dispatch, ais_membership_destroy, NULL, NULL, &local_id)) { GMainLoop* amainloop = NULL; switch(command) { case 'R': send_ais_text(crm_class_rmpeer, target_uname, TRUE, NULL, crm_msg_ais); exit(0); case 'e': /* Age makes no sense (yet) in an AIS cluster */ fprintf(stdout, "1\n"); exit(0); case 'q': send_ais_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais); break; case 'l': case 'p': crm_info("Requesting the list of configured nodes"); send_ais_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais); break; case 'i': printf("%d\n", local_id); exit(0); default: fprintf(stderr, "Unknown option '%c'\n", command); crm_help('?', LSB_EXIT_GENERIC); } amainloop = g_main_new(FALSE); g_main_run(amainloop); } return FALSE; } #endif int main(int argc, char ** argv) { int flag = 0; int argerr = 0; gboolean force_flag = FALSE; gboolean dangerous_cmd = FALSE; unsigned long long try_stack = pcmk_cluster_heartbeat|pcmk_cluster_classic_ais|pcmk_cluster_corosync|pcmk_cluster_cman; int option_index = 0; crm_peer_init(); crm_log_init(NULL, LOG_WARNING, FALSE, FALSE, argc, argv); crm_set_options("?V$qepHAR:iflCc", "command [options]", long_options, "Tool for displaying low-level node information"); while (flag >= 0) { flag = crm_get_option(argc, argv, &option_index); switch(flag) { case -1: break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '$': case '?': crm_help(flag, LSB_EXIT_OK); break; case 'Q': do_quiet = TRUE; break; case 'H': try_stack = pcmk_cluster_heartbeat; break; case 'A': try_stack = pcmk_cluster_classic_ais; break; case 'C': try_stack = pcmk_cluster_corosync; break; case 'c': try_stack = pcmk_cluster_cman; break; case 'f': force_flag = TRUE; break; case 'R': dangerous_cmd = TRUE; command = flag; target_uname = optarg; break; case 'p': case 'e': case 'q': case 'i': case 'l': command = flag; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } if(dangerous_cmd && force_flag == FALSE) { fprintf(stderr, "The supplied command is considered dangerous." " To prevent accidental destruction of the cluster," " the --force flag is required in order to proceed.\n"); fflush(stderr); exit(LSB_EXIT_GENERIC); } #if SUPPORT_COROSYNC if(try_stack & pcmk_cluster_classic_ais) { try_corosync(command); } #endif #if SUPPORT_CMAN if(try_stack & pcmk_cluster_cman) { try_cman(command); } #endif #if SUPPORT_HEARTBEAT if(try_stack & pcmk_cluster_heartbeat) { try_heartbeat(command); } #endif return(1); } diff --git a/tools/crm_inject.c b/tools/crm_inject.c index 7eabf40595..46da60d8dd 100644 --- a/tools/crm_inject.c +++ b/tools/crm_inject.c @@ -1,1160 +1,1176 @@ /* * Copyright (C) 2009 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include cib_t *global_cib = NULL; GListPtr op_fail = NULL; gboolean quiet = FALSE; #define new_node_template "//"XML_CIB_TAG_NODE"[@uname='%s']" #define node_template "//"XML_CIB_TAG_STATE"[@uname='%s']" #define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']" #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']" /* #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s' and @"XML_LRM_ATTR_CALLID"='%d']" */ #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -#define quiet_log(fmt, args...) do { \ - if(quiet == FALSE) { \ - printf(fmt , ##args); \ - } \ +#define quiet_log(fmt, args...) do { \ + if(quiet == FALSE) { \ + printf(fmt , ##args); \ + } \ } while(0) extern void cleanup_alloc_calculations(pe_working_set_t *data_set); extern xmlNode * do_calculations( pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); char *use_date = NULL; static ha_time_t *get_date(void) { if(use_date) { char *date_m = use_date; return parse_date(&date_m); } return NULL; } static xmlNode *find_resource(xmlNode *cib_node, const char *resource) { char *xpath = NULL; xmlNode *match = NULL; const char *node = crm_element_value(cib_node, XML_ATTR_UNAME); int max = strlen(rsc_template) + strlen(resource) + strlen(node) + 1; crm_malloc0(xpath, max); snprintf(xpath, max, rsc_template, node, resource); match = get_xpath_object(xpath, cib_node, LOG_DEBUG_2); crm_free(xpath); return match; } static void create_node_entry(cib_t *cib_conn, char *node) { int rc = cib_ok; int max = strlen(new_node_template) + strlen(node) + 1; char *xpath = NULL; crm_malloc0(xpath, max); snprintf(xpath, max, new_node_template, node); rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath|cib_sync_call|cib_scope_local); if (rc == cib_NOTEXISTS) { xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE); /* Using node uname as uuid ala corosync/openais */ crm_xml_add(cib_object, XML_ATTR_ID, node); crm_xml_add(cib_object, XML_ATTR_UNAME, node); crm_xml_add(cib_object, XML_ATTR_TYPE, NORMALNODE); cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object, cib_sync_call|cib_scope_local); /* Not bothering with subsequent query to see if it exists, we'll bomb out later in the call to determine_host... */ free_xml(cib_object); } crm_free(xpath); } static xmlNode *inject_node_state(cib_t *cib_conn, char *node) { int rc = cib_ok; int max = strlen(rsc_template) + strlen(node) + 1; char *xpath = NULL; xmlNode *cib_object = NULL; crm_malloc0(xpath, max); create_node_entry(cib_conn, node); snprintf(xpath, max, node_template, node); rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, cib_xpath|cib_sync_call|cib_scope_local); if(rc == cib_NOTEXISTS) { char *uuid = NULL; cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE); determine_host(cib_conn, &node, &uuid); crm_xml_add(cib_object, XML_ATTR_UUID, uuid); crm_xml_add(cib_object, XML_ATTR_UNAME, node); cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object, cib_sync_call|cib_scope_local); free_xml(cib_object); crm_free(uuid); rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, cib_xpath|cib_sync_call|cib_scope_local); } crm_free(xpath); CRM_ASSERT(rc == cib_ok); return cib_object; } static xmlNode *modify_node(cib_t *cib_conn, char *node, gboolean up) { xmlNode *cib_node = inject_node_state(cib_conn, node); if(up) { crm_xml_add(cib_node, XML_CIB_ATTR_HASTATE, ACTIVESTATUS); crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_YES); crm_xml_add(cib_node, XML_CIB_ATTR_CRMDSTATE, ONLINESTATUS); crm_xml_add(cib_node, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_MEMBER); crm_xml_add(cib_node, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_MEMBER); } else { crm_xml_add(cib_node, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(cib_node, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(cib_node, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(cib_node, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); } crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name); return cib_node; } static void inject_transient_attr(xmlNode *cib_node, const char *name, const char *value) { xmlNode *attrs = NULL; xmlNode *container = NULL; xmlNode *nvp = NULL; const char *node_uuid = ID(cib_node); char *nvp_id = crm_concat(name, node_uuid, '-'); crm_info("Injecting attribute %s=%s into %s '%s'", name, value, xmlGetNodePath(cib_node), ID(cib_node)); attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS); if(attrs == NULL) { attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS); crm_xml_add(attrs, XML_ATTR_ID, node_uuid); } container = first_named_child(attrs, XML_TAG_ATTR_SETS); if(container == NULL) { container = create_xml_node(attrs, XML_TAG_ATTR_SETS); crm_xml_add(container, XML_ATTR_ID, node_uuid); } nvp = create_xml_node(container, XML_CIB_TAG_NVPAIR); crm_xml_add(nvp, XML_ATTR_ID, nvp_id); crm_xml_add(nvp, XML_NVPAIR_ATTR_NAME, name); crm_xml_add(nvp, XML_NVPAIR_ATTR_VALUE, value); crm_free(nvp_id); } static xmlNode *inject_resource(xmlNode *cib_node, const char *resource, const char *rclass, const char *rtype, const char *rprovider) { xmlNode *lrm = NULL; xmlNode *container = NULL; xmlNode *cib_resource = NULL; cib_resource = find_resource(cib_node, resource); if(cib_resource != NULL) { return cib_resource; } /* One day, add query for class, provider, type */ if(rclass == NULL || rtype == NULL) { fprintf(stderr, "Resource %s not found in the status section of %s." " Please supply the class and type to continue\n", resource, ID(cib_node)); return NULL; } else if(safe_str_neq(rclass, "ocf") && safe_str_neq(rclass, "stonith") && safe_str_neq(rclass, "heartbeat") && safe_str_neq(rclass, "lsb")) { fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass); return NULL; } else if(safe_str_eq(rclass, "ocf") && rprovider == NULL) { fprintf(stderr, "Please specify the provider for resource %s\n", resource); return NULL; } crm_info("Injecting new resource %s into %s '%s'", resource, xmlGetNodePath(cib_node), ID(cib_node)); lrm = first_named_child(cib_node, XML_CIB_TAG_LRM); if(lrm == NULL) { const char *node_uuid = ID(cib_node); lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM); crm_xml_add(lrm, XML_ATTR_ID, node_uuid); } container = first_named_child(lrm, XML_LRM_TAG_RESOURCES); if(container == NULL) { container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES); } cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE); crm_xml_add(cib_resource, XML_ATTR_ID, resource); crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass); crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider); crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype); return cib_resource; } static lrm_op_t *create_op( xmlNode *cib_resource, const char *task, int interval, int outcome) { lrm_op_t *op = NULL; crm_malloc0(op, sizeof(lrm_op_t)); op->app_name = crm_strdup(crm_system_name); op->rsc_id = crm_strdup(ID(cib_resource)); op->interval = interval; op->op_type = crm_strdup(task); op->rc = outcome; op->op_status = 0; op->params = NULL; /* TODO: Fill me in */ op->call_id = 0; xml_child_iter(cib_resource, xop, int tmp = 0; crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp); if(tmp > op->call_id) { op->call_id = tmp; } ); op->call_id++; return op; } static xmlNode *inject_op(xmlNode *cib_resource, lrm_op_t *op, int target_rc) { return create_operation_update(cib_resource, op, CRM_FEATURE_SET, target_rc, crm_system_name, LOG_DEBUG_2); } static void update_failcounts(xmlNode *cib_node, const char *resource, int interval, int rc) { if(rc == 0) { return; } else if(rc == 7 && interval == 0) { return; } else { char *name = NULL; char *now = crm_itoa(time(NULL)); name = crm_concat("fail-count", resource, '-'); inject_transient_attr(cib_node, name, "value++"); name = crm_concat("last-failure", resource, '-'); inject_transient_attr(cib_node, name, now); crm_free(name); crm_free(now); } } static gboolean exec_pseudo_action(crm_graph_t *graph, crm_action_t *action) { action->confirmed = TRUE; update_graph(graph, action); return TRUE; } static gboolean exec_rsc_action(crm_graph_t *graph, crm_action_t *action) { int rc = 0; + GListPtr gIter = NULL; lrm_op_t *op = NULL; int target_outcome = 0; const char *rtype = NULL; const char *rclass = NULL; const char *resource = NULL; const char *rprovider = NULL; const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC); xmlNode *cib_node = NULL; xmlNode *cib_resource = NULL; xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); if(safe_str_eq(crm_element_value(action->xml, "operation"), "probe_complete")) { crm_info("Skipping %s op for %s\n", crm_element_value(action->xml, "operation"), node); goto done; } if(action_rsc == NULL) { crm_log_xml_err(action->xml, "Bad"); crm_free(node); return FALSE; } resource = ID(action_rsc); rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS); rtype = crm_element_value(action_rsc, XML_ATTR_TYPE); rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER); if(target_rc_s != NULL) { target_outcome = crm_parse_int(target_rc_s, "0"); } CRM_ASSERT(global_cib->cmds->query(global_cib, NULL, NULL, cib_sync_call|cib_scope_local) == cib_ok); cib_node = inject_node_state(global_cib, node); CRM_ASSERT(cib_node != NULL); cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); CRM_ASSERT(cib_resource != NULL); op = convert_graph_action(cib_resource, action, 0, target_outcome); quiet_log(" * Executing action %d: %s_%s_%d on %s\n", action->id, resource, op->op_type, op->interval, node); - slist_iter(spec, char, op_fail, lpc, - - char *key = NULL; - crm_malloc0(key, strlen(spec)); - snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node); + for(gIter = op_fail; gIter != NULL; gIter = gIter->next) { + char *spec = (char*)gIter->data; + char *key = NULL; + crm_malloc0(key, strlen(spec)); + snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node); - if(strncasecmp(key, spec, strlen(key)) == 0) { - rc = sscanf(spec, "%*[^=]=%d", &op->rc); + if(strncasecmp(key, spec, strlen(key)) == 0) { + rc = sscanf(spec, "%*[^=]=%d", &op->rc); - action->failed = TRUE; - graph->abort_priority = INFINITY; - printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc); - update_failcounts(cib_node, resource, op->interval, op->rc); - break; - } - ); + action->failed = TRUE; + graph->abort_priority = INFINITY; + printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc); + update_failcounts(cib_node, resource, op->interval, op->rc); + break; + } + } inject_op(cib_resource, op, target_outcome); free_lrm_op(op); rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); done: crm_free(node); free_xml(cib_node); action->confirmed = TRUE; update_graph(graph, action); return TRUE; } static gboolean exec_crmd_action(crm_graph_t *graph, crm_action_t *action) { action->confirmed = TRUE; update_graph(graph, action); return TRUE; } #define STATUS_PATH_MAX 512 static gboolean exec_stonith_action(crm_graph_t *graph, crm_action_t *action) { int rc = 0; char xpath[STATUS_PATH_MAX]; char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); xmlNode *cib_node = modify_node(global_cib, target, FALSE); crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__); CRM_ASSERT(cib_node != NULL); quiet_log(" * Fencing %s\n", target); rc = global_cib->cmds->replace(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM); rc = global_cib->cmds->delete(global_cib, xpath, NULL, cib_xpath|cib_sync_call|cib_scope_local); snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_TAG_TRANSIENT_NODEATTRS); rc = global_cib->cmds->delete(global_cib, xpath, NULL, cib_xpath|cib_sync_call|cib_scope_local); action->confirmed = TRUE; update_graph(graph, action); free_xml(cib_node); crm_free(target); return TRUE; } static char * add_list_element(char *list, const char *value) { int len = 0; int last = 0; if(value == NULL) { return list; } if(list) { last = strlen(list); } len = last + 2; /* +1 space, +1 EOS */ len += strlen(value); crm_realloc(list, len); sprintf(list + last, " %s", value); return list; } static void print_cluster_status(pe_working_set_t *data_set) { char *online_nodes = NULL; char *offline_nodes = NULL; - slist_iter(node, node_t, data_set->nodes, lpc2, - const char *node_mode = NULL; + GListPtr gIter = NULL; + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + const char *node_mode = NULL; - if(node->details->unclean) { - if(node->details->online && node->details->unclean) { - node_mode = "UNCLEAN (online)"; + if(node->details->unclean) { + if(node->details->online && node->details->unclean) { + node_mode = "UNCLEAN (online)"; - } else if(node->details->pending) { - node_mode = "UNCLEAN (pending)"; + } else if(node->details->pending) { + node_mode = "UNCLEAN (pending)"; - } else { - node_mode = "UNCLEAN (offline)"; - } + } else { + node_mode = "UNCLEAN (offline)"; + } - } else if(node->details->pending) { - node_mode = "pending"; + } else if(node->details->pending) { + node_mode = "pending"; - } else if(node->details->standby_onfail && node->details->online) { - node_mode = "standby (on-fail)"; + } else if(node->details->standby_onfail && node->details->online) { + node_mode = "standby (on-fail)"; - } else if(node->details->standby) { - if(node->details->online) { - node_mode = "standby"; - } else { - node_mode = "OFFLINE (standby)"; - } + } else if(node->details->standby) { + if(node->details->online) { + node_mode = "standby"; + } else { + node_mode = "OFFLINE (standby)"; + } - } else if(node->details->online) { - node_mode = "online"; - online_nodes = add_list_element(online_nodes, node->details->uname); - continue; - - } else { - node_mode = "OFFLINE"; - offline_nodes = add_list_element(offline_nodes, node->details->uname); - continue; - } + } else if(node->details->online) { + node_mode = "online"; + online_nodes = add_list_element(online_nodes, node->details->uname); + continue; + + } else { + node_mode = "OFFLINE"; + offline_nodes = add_list_element(offline_nodes, node->details->uname); + continue; + } - if(safe_str_eq(node->details->uname, node->details->id)) { - printf("Node %s: %s\n", - node->details->uname, node_mode); - } else { - printf("Node %s (%s): %s\n", - node->details->uname, node->details->id, - node_mode); - } - ); + if(safe_str_eq(node->details->uname, node->details->id)) { + printf("Node %s: %s\n", + node->details->uname, node_mode); + } else { + printf("Node %s (%s): %s\n", + node->details->uname, node->details->id, + node_mode); + } + } if(online_nodes) { printf("Online: [%s ]\n", online_nodes); crm_free(online_nodes); } if(offline_nodes) { printf("OFFLINE: [%s ]\n", offline_nodes); crm_free(offline_nodes); } fprintf(stdout, "\n"); - slist_iter(rsc, resource_t, data_set->resources, lpc, - if(is_set(rsc->flags, pe_rsc_orphan) - && rsc->role == RSC_ROLE_STOPPED) { - continue; - } - rsc->fns->print(rsc, NULL, pe_print_printf, stdout); - ); + for(gIter = data_set->resources; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + if(is_set(rsc->flags, pe_rsc_orphan) + && rsc->role == RSC_ROLE_STOPPED) { + continue; + } + rsc->fns->print(rsc, NULL, pe_print_printf, stdout); + } fprintf(stdout, "\n"); } static int run_simulation(pe_working_set_t *data_set) { crm_graph_t *transition = NULL; enum transition_status graph_rc = -1; crm_graph_functions_t exec_fns = { exec_pseudo_action, exec_rsc_action, exec_crmd_action, exec_stonith_action, }; set_graph_functions(&exec_fns); quiet_log("\nExecuting cluster transition:\n"); transition = unpack_graph(data_set->graph, crm_system_name); print_graph(LOG_DEBUG, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { fprintf(stdout, "Transition failed: %s\n", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } destroy_graph(transition); if(graph_rc != transition_complete) { fprintf(stdout, "An invalid transition was produced\n"); } if(quiet == FALSE) { xmlNode *cib_object = NULL; int rc = global_cib->cmds->query(global_cib, NULL, &cib_object, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); quiet_log("\nRevised cluster status:\n"); cleanup_alloc_calculations(data_set); data_set->input = cib_object; data_set->now = get_date(); cluster_status(data_set); print_cluster_status(data_set); } if(graph_rc != transition_complete) { return graph_rc; } return 0; } static char * create_action_name(action_t *action) { - char *action_name = NULL; - const char *action_host = NULL; - if(action->node) { - action_host = action->node->details->uname; - action_name = crm_concat(action->uuid, action_host, ' '); - - } else if(is_set(action->flags, pe_action_pseudo)) { - action_name = crm_strdup(action->uuid); + char *action_name = NULL; + const char *action_host = NULL; + if(action->node) { + action_host = action->node->details->uname; + action_name = crm_concat(action->uuid, action_host, ' '); + + } else if(is_set(action->flags, pe_action_pseudo)) { + action_name = crm_strdup(action->uuid); - } else { - action_host = ""; - action_name = crm_concat(action->uuid, action_host, ' '); - } - if(safe_str_eq(action->task, RSC_CANCEL)) { - char *tmp_action_name = action_name; - action_name = crm_concat("Cancel", tmp_action_name, ' '); - crm_free(tmp_action_name); - } + } else { + action_host = ""; + action_name = crm_concat(action->uuid, action_host, ' '); + } + if(safe_str_eq(action->task, RSC_CANCEL)) { + char *tmp_action_name = action_name; + action_name = crm_concat("Cancel", tmp_action_name, ' '); + crm_free(tmp_action_name); + } - return action_name; + return action_name; } static void create_dotfile(pe_working_set_t *data_set, const char *dot_file, gboolean all_actions) { + GListPtr gIter = NULL; FILE *dot_strm = fopen(dot_file, "w"); if(dot_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", dot_file); return; } fprintf(dot_strm, " digraph \"g\" {\n"); - slist_iter( - action, action_t, data_set->actions, lpc, - + for(gIter = data_set->actions; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; const char *style = "filled"; const char *font = "black"; const char *color = "black"; const char *fill = NULL; char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(is_set(action->flags, pe_action_pseudo)) { font = "orange"; } style = "dashed"; if(is_set(action->flags, pe_action_dumped)) { style = "bold"; color = "green"; } else if(action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) { color = "purple"; if(all_actions == FALSE) { goto dont_write; } } else if(is_set(action->flags, pe_action_optional)) { color = "blue"; if(all_actions == FALSE) { goto dont_write; } } else { color = "red"; CRM_CHECK(is_set(action->flags, pe_action_runnable) == FALSE, ;); } set_bit_inplace(action->flags, pe_action_dumped); fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]\n", - action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); + action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); dont_write: crm_free(action_name); - ); + } + for(gIter = data_set->actions; gIter != NULL; gIter = gIter->next) { + action_t *action = (action_t*)gIter->data; - slist_iter( - action, action_t, data_set->actions, lpc, - slist_iter( - before, action_wrapper_t, action->actions_before, lpc2, + GListPtr gIter2 = NULL; + for(gIter2 = action->actions_before; gIter2 != NULL; gIter2 = gIter2->next) { + action_wrapper_t *before = (action_wrapper_t*)gIter2->data; + char *before_name = NULL; char *after_name = NULL; const char *style = "dashed"; gboolean optional = TRUE; if(before->state == pe_link_dumped) { optional = FALSE; style = "bold"; } else if(is_set(action->flags, pe_action_pseudo) && (before->type & pe_order_stonith_stop)) { continue; } else if(before->state == pe_link_dup) { continue; } else if(before->type == pe_order_none) { continue; } else if(is_set(before->action->flags, pe_action_dumped) && is_set(action->flags, pe_action_dumped)) { optional = FALSE; } if(all_actions || optional == FALSE) { before_name = create_action_name(before->action); after_name = create_action_name(action); fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n", before_name, after_name, style); crm_free(before_name); crm_free(after_name); } - ); - ); + } + } + fprintf(dot_strm, "}\n"); if(dot_strm != NULL) { fflush(dot_strm); fclose(dot_strm); } } static void modify_configuration( pe_working_set_t *data_set, const char *quorum, GListPtr node_up, GListPtr node_down, GListPtr node_fail, GListPtr op_inject) { int rc = cib_ok; + GListPtr gIter = NULL; xmlNode *cib_op = NULL; xmlNode *cib_node = NULL; xmlNode *cib_resource = NULL; lrm_op_t *op = NULL; if(quorum) { xmlNode *top = create_xml_node(NULL, XML_TAG_CIB); quiet_log(" + Setting quorum: %s\n", quorum); /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */ crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum); rc = global_cib->cmds->modify(global_cib, NULL, top, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); } - slist_iter(node, char, node_up, lpc, - quiet_log(" + Bringing node %s online\n", node); - cib_node = modify_node(global_cib, node, TRUE); - CRM_ASSERT(cib_node != NULL); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); - ); - - slist_iter(node, char, node_down, lpc, - quiet_log(" + Taking node %s offline\n", node); - cib_node = modify_node(global_cib, node, FALSE); - CRM_ASSERT(cib_node != NULL); + for(gIter = node_up; gIter != NULL; gIter = gIter->next) { + char *node = (char*)gIter->data; + + quiet_log(" + Bringing node %s online\n", node); + cib_node = modify_node(global_cib, node, TRUE); + CRM_ASSERT(cib_node != NULL); + + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + } - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); - ); + for(gIter = node_down; gIter != NULL; gIter = gIter->next) { + char *node = (char*)gIter->data; + + quiet_log(" + Taking node %s offline\n", node); + cib_node = modify_node(global_cib, node, FALSE); + CRM_ASSERT(cib_node != NULL); - slist_iter(node, char, node_fail, lpc, - quiet_log(" + Failing node %s\n", node); - cib_node = modify_node(global_cib, node, TRUE); - crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); - CRM_ASSERT(cib_node != NULL); + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + } - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); - ); + for(gIter = node_fail; gIter != NULL; gIter = gIter->next) { + char *node = (char*)gIter->data; + + quiet_log(" + Failing node %s\n", node); + cib_node = modify_node(global_cib, node, TRUE); + crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); + CRM_ASSERT(cib_node != NULL); + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + } - slist_iter(spec, char, op_inject, lpc, + for(gIter = op_inject; gIter != NULL; gIter = gIter->next) { + char *spec = (char*)gIter->data; + - int rc = 0; - int outcome = 0; - int interval = 0; + int rc = 0; + int outcome = 0; + int interval = 0; - char *key = NULL; - char *node = NULL; - char *task = NULL; - char *resource = NULL; + char *key = NULL; + char *node = NULL; + char *task = NULL; + char *resource = NULL; - const char *rtype = NULL; - const char *rclass = NULL; - const char *rprovider = NULL; + const char *rtype = NULL; + const char *rclass = NULL; + const char *rprovider = NULL; - resource_t *rsc = NULL; - quiet_log(" + Injecting %s into the configuration\n", spec); + resource_t *rsc = NULL; + quiet_log(" + Injecting %s into the configuration\n", spec); - crm_malloc0(key, strlen(spec)+1); - crm_malloc0(node, strlen(spec)+1); - rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome); - CRM_CHECK(rc == 3, fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc); continue); + crm_malloc0(key, strlen(spec)+1); + crm_malloc0(node, strlen(spec)+1); + rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome); + CRM_CHECK(rc == 3, fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc); continue); - parse_op_key(key, &resource, &task, &interval); - crm_free(task); + parse_op_key(key, &resource, &task, &interval); + crm_free(task); - rsc = pe_find_resource(data_set->resources, resource); - CRM_CHECK(rsc != NULL, fprintf(stderr, "Invalid resource name: %s\n", resource); continue); + rsc = pe_find_resource(data_set->resources, resource); + CRM_CHECK(rsc != NULL, fprintf(stderr, "Invalid resource name: %s\n", resource); continue); - rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); - rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); + rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); + rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); - cib_node = inject_node_state(global_cib, node); - CRM_ASSERT(cib_node != NULL); + cib_node = inject_node_state(global_cib, node); + CRM_ASSERT(cib_node != NULL); - update_failcounts(cib_node, resource, interval, rc); + update_failcounts(cib_node, resource, interval, rc); - cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); - CRM_ASSERT(cib_resource != NULL); + cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); + CRM_ASSERT(cib_resource != NULL); - op = create_op(cib_resource, task, interval, outcome); - CRM_ASSERT(op != NULL); + op = create_op(cib_resource, task, interval, outcome); + CRM_ASSERT(op != NULL); - cib_op = inject_op(cib_resource, op, 0); - CRM_ASSERT(cib_op != NULL); - free_lrm_op(op); + cib_op = inject_op(cib_resource, op, 0); + CRM_ASSERT(cib_op != NULL); + free_lrm_op(op); - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); - ); + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + } } static void setup_input(const char *input, const char *output) { int rc = cib_ok; cib_t *cib_conn = NULL; xmlNode *cib_object = NULL; char *local_output = NULL; if(input == NULL) { /* Use live CIB */ cib_conn = cib_new(); rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command); if(rc == cib_ok) { cib_object = get_cib_copy(cib_conn); } cib_conn->cmds->signoff(cib_conn); cib_delete(cib_conn); cib_conn = NULL; if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); exit(3); } } else if(safe_str_eq(input, "-")) { cib_object = filename2xml(NULL); } else { cib_object = filename2xml(input); } if(get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) { create_xml_node(cib_object, XML_CIB_TAG_STATUS); } if(cli_config_update(&cib_object, NULL, FALSE) == FALSE) { free_xml(cib_object); exit(cib_STALE); } if(validate_xml(cib_object, NULL, FALSE) != TRUE) { free_xml(cib_object); exit(cib_dtd_validation); } if(output == NULL) { char *pid = crm_itoa(getpid()); local_output = get_shadow_file(pid); output = local_output; crm_free(pid); } rc = write_xml_file(cib_object, output, FALSE); free_xml(cib_object); cib_object = NULL; if(rc < 0) { fprintf(stderr, "Could not create '%s': %s\n", output, strerror(errno)); exit(rc); } setenv("CIB_file", output, 1); crm_free(local_output); } static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\tThis text"}, {"version", 0, 0, '$', "\tVersion information" }, {"quiet", 0, 0, 'Q', "\tDisplay only essentialoutput"}, {"verbose", 0, 0, 'V', "\tIncrease debug output"}, {"-spacer-", 0, 0, '-', "\nOperations:"}, {"run", 0, 0, 'R', "\tDetermine the cluster's response to the given configuration and status"}, {"simulate", 0, 0, 'S', "Simulate the transition's execution and display the resulting cluster status"}, {"in-place", 0, 0, 'X', "Simulate the transition's execution and store the result back to the input file"}, {"show-scores", 0, 0, 's', "Show allocation scores"}, {"show-utilization", 0, 0, 'U', "Show utilization information"}, {"-spacer-", 0, 0, '-', "\nSynthetic Cluster Events:"}, {"node-up", 1, 0, 'u', "\tBring a node online"}, {"node-down", 1, 0, 'd', "\tTake a node offline"}, {"node-fail", 1, 0, 'f', "\tMark a node as failed"}, {"op-inject", 1, 0, 'i', "\t$rsc_$task_$interval@$node=$rc - Inject the specified task before running the simulation"}, {"op-fail", 1, 0, 'F', "\t$rsc_$task_$interval@$node=$rc - Fail the specified task while running the simulation"}, {"set-datetime", 1, 0, 't', "Set date/time"}, {"quorum", 1, 0, 'q', "\tSpecify a value for quorum"}, {"-spacer-", 0, 0, '-', "\nOutput Options:"}, {"save-input", 1, 0, 'I', "\tSave the input configuration to the named file"}, {"save-output", 1, 0, 'O', "Save the output configuration to the named file"}, {"save-graph", 1, 0, 'G', "\tSave the transition graph (XML format) to the named file"}, {"save-dotfile", 1, 0, 'D', "Save the transition graph (DOT format) to the named file"}, {"all-actions", 0, 0, 'a', "\tDisplay all possible actions in the DOT graph - even ones not part of the transition"}, {"-spacer-", 0, 0, '-', "\nData Source:"}, {"live-check", 0, 0, 'L', "\tConnect to the CIB and use the current contents as input"}, {"xml-file", 1, 0, 'x', "\tRetrieve XML from the named file"}, {"xml-pipe", 0, 0, 'p', "\tRetrieve XML from stdin"}, {0, 0, 0, 0} }; int main(int argc, char ** argv) { int rc = 0; guint modified = 0; gboolean store = FALSE; gboolean process = FALSE; gboolean verbose = FALSE; gboolean simulate = FALSE; gboolean all_actions = FALSE; pe_working_set_t data_set; const char *xml_file = "-"; const char *quorum = NULL; const char *dot_file = NULL; const char *graph_file = NULL; const char *input_file = NULL; const char *output_file = NULL; int flag = 0; int index = 0; int argerr = 0; GListPtr node_up = NULL; GListPtr node_down = NULL; GListPtr node_fail = NULL; GListPtr op_inject = NULL; xmlNode *input = NULL; crm_log_init(NULL, LOG_ERR, FALSE, FALSE, argc, argv); crm_set_options("?$VQx:Lpu:d:f:i:RSXD:G:I:O:sUaF:t:q:", "datasource operation [additional options]", long_options, "Tool for simulating the cluster's response to events"); if(argc < 2) { crm_help('?', LSB_EXIT_EINVAL); } while (1) { flag = crm_get_option(argc, argv, &index); if (flag == -1) break; switch(flag) { case 'V': verbose = TRUE; alter_debug(DEBUG_INC); cl_log_enable_stderr(TRUE); break; case '?': case '$': crm_help(flag, LSB_EXIT_OK); break; case 'p': xml_file = "-"; break; case 'Q': quiet = TRUE; break; case 'L': xml_file = NULL; break; case 'x': xml_file = optarg; break; case 'u': modified++; node_up = g_list_append(node_up, optarg); break; case 'd': modified++; node_down = g_list_append(node_down, optarg); break; case 'f': modified++; node_fail = g_list_append(node_fail, optarg); break; case 't': use_date = crm_strdup(optarg); break; case 'i': modified++; op_inject = g_list_append(op_inject, optarg); break; case 'F': process = TRUE; simulate = TRUE; op_fail = g_list_append(op_fail, optarg); break; case 'q': modified++; quorum = optarg; break; case 'a': all_actions = TRUE; break; case 's': process = TRUE; show_scores = TRUE; break; case 'U': process = TRUE; show_utilization = TRUE; break; case 'S': process = TRUE; simulate = TRUE; break; case 'X': store = TRUE; process = TRUE; simulate = TRUE; break; case 'R': process = TRUE; break; case 'D': process = TRUE; dot_file = optarg; break; case 'G': process = TRUE; graph_file = optarg; break; case 'I': input_file = optarg; break; case 'O': simulate = TRUE; output_file = optarg; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } update_all_trace_data(); /* again, so we see which trace points got updated */ setup_input(xml_file, store?xml_file:output_file); global_cib = cib_new(); global_cib->cmds->signon(global_cib, crm_system_name, cib_command); set_working_set_defaults(&data_set); if(data_set.now != NULL) { quiet_log(" + Setting effective cluster time: %s", use_date); log_date(LOG_WARNING, "Set fake 'now' to", data_set.now, ha_log_date|ha_log_time); } rc = global_cib->cmds->query(global_cib, NULL, &input, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); data_set.input = input; data_set.now = get_date(); cluster_status(&data_set); if(quiet == FALSE) { quiet_log("\nCurrent cluster status:\n"); print_cluster_status(&data_set); } if(modified) { quiet_log("Performing requested modifications\n"); modify_configuration(&data_set, quorum, node_up, node_down, node_fail, op_inject); rc = global_cib->cmds->query(global_cib, NULL, &input, cib_sync_call); if(rc != cib_ok) { fprintf(stderr, "Could not connect to the CIB for input: %s\n", cib_error2string(rc)); goto done; } cleanup_alloc_calculations(&data_set); data_set.now = get_date(); data_set.input = input; } if(input_file != NULL) { rc = write_xml_file(input, input_file, FALSE); if(rc < 0) { fprintf(stderr, "Could not create '%s': %s\n", input_file, strerror(errno)); goto done; } } rc = 0; if(process || simulate) { ha_time_t *local_date = NULL; if(show_scores && show_utilization) { printf("Allocation scores and utilization information:\n"); } else if(show_scores) { fprintf(stdout, "Allocation scores:\n"); } else if(show_utilization) { printf("Utilization information:\n"); } do_calculations(&data_set, input, local_date); input = NULL; /* Don't try and free it twice */ if(graph_file != NULL) { char *msg_buffer = dump_xml_formatted(data_set.graph); FILE *graph_strm = fopen(graph_file, "w"); if(graph_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", graph_file); } else { if(fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) { crm_perror(LOG_ERR,"Write to %s failed", graph_file); } fflush(graph_strm); fclose(graph_strm); } crm_free(msg_buffer); } if(dot_file != NULL) { create_dotfile(&data_set, dot_file, all_actions); } if(quiet == FALSE && verbose == FALSE) { + GListPtr gIter = NULL; quiet_log("%sTransition Summary:\n", show_scores||show_utilization||modified?"\n":""); fflush(stdout); crm_log_level = LOG_NOTICE; cl_log_enable_stderr(TRUE); - slist_iter( - rsc, resource_t, data_set.resources, lpc, + for(gIter = data_set.resources; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; LogActions(rsc, &data_set); - ); + } cl_log_enable_stderr(FALSE); } } if(simulate) { rc = run_simulation(&data_set); } done: cleanup_alloc_calculations(&data_set); global_cib->cmds->signoff(global_cib); cib_delete(global_cib); crm_free(use_date); crm_xml_cleanup(); fflush(stderr); return rc; } diff --git a/tools/crm_mon.c b/tools/crm_mon.c index 8723b9a383..4698a8d7a8 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -1,1955 +1,1970 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <../lib/pengine/unpack.h> /* GMainLoop *mainloop = NULL; */ void wait_for_refresh(int offset, const char *prefix, int msec); void clean_up(int rc); void crm_diff_update(const char *event, xmlNode *msg); gboolean mon_refresh_display(gpointer user_data); int cib_connect(gboolean full); char *xml_file = NULL; char *as_html_file = NULL; char *pid_file = NULL; char *snmp_target = NULL; char *snmp_community = NULL; gboolean as_console = TRUE;; gboolean simple_status = FALSE; gboolean group_by_node = FALSE; gboolean inactive_resources = FALSE; gboolean web_cgi = FALSE; int reconnect_msec = 5000; gboolean daemonize = FALSE; GMainLoop *mainloop = NULL; guint timer_id = 0; GList *attr_list = NULL; const char *crm_mail_host = NULL; const char *crm_mail_prefix = NULL; const char *crm_mail_from = NULL; const char *crm_mail_to = NULL; const char *external_agent = NULL; const char *external_recipient = NULL; cib_t *cib = NULL; xmlNode *current_cib = NULL; gboolean one_shot = FALSE; gboolean has_warnings = FALSE; gboolean print_failcount = FALSE; gboolean print_operations = FALSE; gboolean print_timing = FALSE; gboolean print_nodes_attr = FALSE; -#define FILTER_STR {"shutdown", "terminate", "standby", "fail-count", \ - "last-failure", "probe_complete", "#id", "#uname", \ - "#is_dc", NULL} +#define FILTER_STR {"shutdown", "terminate", "standby", "fail-count", \ + "last-failure", "probe_complete", "#id", "#uname", \ + "#is_dc", NULL} gboolean log_diffs = FALSE; gboolean log_updates = FALSE; long last_refresh = 0; crm_trigger_t *refresh_trigger = NULL; /* * 1.3.6.1.4.1.32723 has been assigned to the project by IANA * http://www.iana.org/assignments/enterprise-numbers */ #define PACEMAKER_PREFIX "1.3.6.1.4.1.32723" #define PACEMAKER_TRAP_PREFIX PACEMAKER_PREFIX ".1" #define snmp_crm_trap_oid PACEMAKER_TRAP_PREFIX #define snmp_crm_oid_node PACEMAKER_TRAP_PREFIX ".1" #define snmp_crm_oid_rsc PACEMAKER_TRAP_PREFIX ".2" #define snmp_crm_oid_task PACEMAKER_TRAP_PREFIX ".3" #define snmp_crm_oid_desc PACEMAKER_TRAP_PREFIX ".4" #define snmp_crm_oid_status PACEMAKER_TRAP_PREFIX ".5" #define snmp_crm_oid_rc PACEMAKER_TRAP_PREFIX ".6" #define snmp_crm_oid_trc PACEMAKER_TRAP_PREFIX ".7" #if CURSES_ENABLED -# define print_dot() if(as_console) { \ - printw("."); \ - clrtoeol(); \ - refresh(); \ - } else { \ - fprintf(stdout, "."); \ +# define print_dot() if(as_console) { \ + printw("."); \ + clrtoeol(); \ + refresh(); \ + } else { \ + fprintf(stdout, "."); \ } #else # define print_dot() fprintf(stdout, "."); #endif #if CURSES_ENABLED # define print_as(fmt, args...) if(as_console) { \ printw(fmt, ##args); \ clrtoeol(); \ refresh(); \ } else { \ - fprintf(stdout, fmt, ##args); \ + fprintf(stdout, fmt, ##args); \ } #else # define print_as(fmt, args...) fprintf(stdout, fmt, ##args); #endif static void blank_screen(void) { #if CURSES_ENABLED int lpc = 0; for(lpc = 0; lpc < LINES; lpc++) { move(lpc, 0); clrtoeol(); } move(0, 0); refresh(); #endif } static gboolean mon_timer_popped(gpointer data) { int rc = cib_ok; if(timer_id > 0) { g_source_remove(timer_id); } rc = cib_connect(TRUE); if(rc != cib_ok) { print_dot(); timer_id = g_timeout_add(reconnect_msec, mon_timer_popped, NULL); } return FALSE; } static void mon_cib_connection_destroy(gpointer user_data) { print_as("Connection to the CIB terminated\n"); if(cib) { print_as("Reconnecting..."); cib->cmds->signoff(cib); timer_id = g_timeout_add(reconnect_msec, mon_timer_popped, NULL); } return; } /* * Mainloop signal handler. */ static void mon_shutdown(int nsig) { clean_up(LSB_EXIT_OK); } #if ON_DARWIN # define sighandler_t sig_t #endif #if CURSES_ENABLED static sighandler_t ncurses_winch_handler; static void mon_winresize(int nsig) { static int not_done; int lines = 0, cols = 0; if(!not_done++) { if(ncurses_winch_handler) /* the original ncurses WINCH signal handler does the * magic of retrieving the new window size; * otherwise, we'd have to use ioctl or tgetent */ (*ncurses_winch_handler) (SIGWINCH); getmaxyx(stdscr, lines, cols); resizeterm(lines,cols); mainloop_set_trigger(refresh_trigger); } not_done--; } #endif int cib_connect(gboolean full) { int rc = cib_ok; static gboolean need_pass = TRUE; CRM_CHECK(cib != NULL, return cib_missing); if(getenv("CIB_passwd") != NULL) { need_pass = FALSE; } if(cib->state != cib_connected_query && cib->state != cib_connected_command) { crm_debug_4("Connecting to the CIB"); if(as_console && need_pass && cib->variant == cib_remote) { need_pass = FALSE; print_as("Password:"); } rc = cib->cmds->signon(cib, crm_system_name, cib_query); if(rc != cib_ok) { return rc; } current_cib = get_cib_copy(cib); mon_refresh_display(NULL); if(full) { if(rc == cib_ok) { rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy); if(rc == cib_NOTSUPPORTED) { print_as("Notification setup failed, won't be able to reconnect after failure"); if(as_console) { sleep(2); } rc = cib_ok; } } if(rc == cib_ok) { cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update); rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update); } if(rc != cib_ok) { print_as("Notification setup failed, could not monitor CIB actions"); if(as_console) { sleep(2); } clean_up(-rc); } } } return rc; } static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\tThis text"}, {"version", 0, 0, '$', "\tVersion information" }, {"verbose", 0, 0, 'V', "\tIncrease debug output"}, {"-spacer-", 1, 0, '-', "\nModes:"}, {"as-html", 1, 0, 'h', "Write cluster status to the named file"}, {"web-cgi", 0, 0, 'w', "\tWeb mode with output suitable for cgi"}, {"simple-status", 0, 0, 's', "Display the cluster status once as a simple one line output (suitable for nagios)"}, {"snmp-traps", 1, 0, 'S', "Send SNMP traps to this station", !ENABLE_SNMP}, {"snmp-community", 1, 0, 'C', "Specify community for SNMP traps(default is NULL)", !ENABLE_SNMP}, {"mail-to", 1, 0, 'T', "Send Mail alerts to this user. See also --mail-from, --mail-host, --mail-prefix", !ENABLE_ESMTP}, {"-spacer-", 1, 0, '-', "\nDisplay Options:"}, {"group-by-node", 0, 0, 'n', "\tGroup resources by node" }, {"inactive", 0, 0, 'r', "\tDisplay inactive resources" }, {"failcounts", 0, 0, 'f', "\tDisplay resource fail counts"}, {"operations", 0, 0, 'o', "\tDisplay resource operation history" }, {"timing-details", 0, 0, 't', "\tDisplay resource operation history with timing details" }, {"show-node-attributes", 0, 0, 'A', "Display node attributes\n" }, {"-spacer-", 1, 0, '-', "\nAdditional Options:"}, {"interval", 1, 0, 'i', "\tUpdate frequency in seconds" }, {"one-shot", 0, 0, '1', "\tDisplay the cluster status once on the console and exit"}, {"disable-ncurses",0, 0, 'N', "\tDisable the use of ncurses", !CURSES_ENABLED}, {"daemonize", 0, 0, 'd', "\tRun in the background as a daemon"}, {"pid-file", 1, 0, 'p', "\t(Advanced) Daemon pid file location"}, {"mail-from", 1, 0, 'F', "\tMail alerts should come from the named user", !ENABLE_ESMTP}, {"mail-host", 1, 0, 'H', "\tMail alerts should be sent via the named host", !ENABLE_ESMTP}, {"mail-prefix", 1, 0, 'P', "Subjects for mail alerts should start with this string", !ENABLE_ESMTP}, {"external-agent", 1, 0, 'E', "A program to run when resource operations take place."}, {"external-recipient",1, 0, 'e', "A recipient for your program (assuming you want the program to send something to someone)."}, {"xml-file", 1, 0, 'x', NULL, 1}, {"-spacer-", 1, 0, '-', "\nExamples:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', "Display the cluster´s status on the console with updates as they occur:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_mon", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Display the cluster´s status on the console just once then exit:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_mon -1", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Display your cluster´s status, group resources by node, and include inactive resources in the list:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_mon --group-by-node --inactive", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Start crm_mon as a background daemon and have it write the cluster´s status to an HTML file:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_mon --daemonize --as-html /path/to/docroot/filename.html", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Start crm_mon as a background daemon and have it send email alerts:", pcmk_option_paragraph|!ENABLE_ESMTP}, {"-spacer-", 1, 0, '-', " crm_mon --daemonize --mail-to user@example.com --mail-host mail.example.com", pcmk_option_example|!ENABLE_ESMTP}, {"-spacer-", 1, 0, '-', "Start crm_mon as a background daemon and have it send SNMP alerts:", pcmk_option_paragraph|!ENABLE_SNMP}, {"-spacer-", 1, 0, '-', " crm_mon --daemonize --snmp-traps snmptrapd.example.com", pcmk_option_example|!ENABLE_SNMP}, {NULL, 0, 0, 0} }; int main(int argc, char **argv) { int flag; int argerr = 0; int exit_code = 0; int option_index = 0; pid_file = crm_strdup("/tmp/ClusterMon.pid"); crm_log_init_quiet(NULL, LOG_CRIT, FALSE, FALSE, argc, argv); crm_set_options("V?$i:nrh:dp:s1wx:oftANS:T:F:H:P:E:e:C:", "mode [options]", long_options, "Provides a summary of cluster's current state." "\n\nOutputs varying levels of detail in a number of different formats.\n"); #ifndef ON_DARWIN /* prevent zombies */ signal(SIGCLD, SIG_IGN); #endif if (strcmp(crm_system_name, "crm_mon.cgi")==0) { web_cgi = TRUE; one_shot = TRUE; } while (1) { flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'i': reconnect_msec = crm_get_msec(optarg); break; case 'n': group_by_node = TRUE; break; case 'r': inactive_resources = TRUE; break; case 'd': daemonize = TRUE; break; case 't': print_timing = TRUE; print_operations = TRUE; break; case 'o': print_operations = TRUE; break; case 'f': print_failcount = TRUE; break; case 'A': print_nodes_attr = TRUE; break; case 'p': crm_free(pid_file); pid_file = crm_strdup(optarg); break; case 'x': xml_file = crm_strdup(optarg); one_shot = TRUE; break; case 'h': as_html_file = crm_strdup(optarg); break; case 'w': web_cgi = TRUE; one_shot = TRUE; break; case 's': simple_status = TRUE; one_shot = TRUE; break; case 'S': snmp_target = optarg; break; case 'T': crm_mail_to = optarg; break; case 'F': crm_mail_from = optarg; break; case 'H': crm_mail_host = optarg; break; case 'P': crm_mail_prefix = optarg; break; case 'E': external_agent = optarg; break; case 'e': external_recipient = optarg; break; case '1': one_shot = TRUE; break; case 'N': as_console = FALSE; break; case 'C': snmp_community = optarg; break; case '$': case '?': crm_help(flag, LSB_EXIT_OK); break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } if(one_shot) { as_console = FALSE; } else if(daemonize) { as_console = FALSE; cl_log_enable_stderr(FALSE); if(!as_html_file && !snmp_target && !crm_mail_to && !external_agent) { printf("Looks like you forgot to specify one or more of: --as-html, --mail-to, --snmp-target, --external-agent\n"); crm_help('?', LSB_EXIT_GENERIC); } crm_make_daemon(crm_system_name, TRUE, pid_file); } else if(as_console) { #if CURSES_ENABLED initscr(); cbreak(); noecho(); cl_log_enable_stderr(FALSE); #else one_shot = TRUE; as_console = FALSE; printf("Defaulting to one-shot mode\n"); printf("You need to have curses available at compile time to enable console mode\n"); #endif } crm_info("Starting %s", crm_system_name); if(xml_file != NULL) { current_cib = filename2xml(xml_file); mon_refresh_display(NULL); return exit_code; } if(current_cib == NULL) { cib = cib_new(); if(!one_shot) { print_as("Attempting connection to the cluster..."); } do { exit_code = cib_connect(!one_shot); if(one_shot) { break; } else if(exit_code != cib_ok) { print_dot(); sleep(reconnect_msec/1000); } } while(exit_code == cib_connection); if(exit_code != cib_ok) { print_as("\nConnection to cluster failed: %s\n", cib_error2string(exit_code)); if(as_console) { sleep(2); } clean_up(-exit_code); } } if(one_shot) { return exit_code; } mainloop = g_main_new(FALSE); mainloop_add_signal(SIGTERM, mon_shutdown); mainloop_add_signal(SIGINT, mon_shutdown); #if CURSES_ENABLED if(as_console) { ncurses_winch_handler = signal(SIGWINCH, mon_winresize); if(ncurses_winch_handler == SIG_DFL || - ncurses_winch_handler == SIG_IGN || - ncurses_winch_handler == SIG_ERR) + ncurses_winch_handler == SIG_IGN || + ncurses_winch_handler == SIG_ERR) ncurses_winch_handler = NULL; } #endif refresh_trigger = mainloop_add_trigger(G_PRIORITY_LOW, mon_refresh_display, NULL); g_main_run(mainloop); g_main_destroy(mainloop); crm_info("Exiting %s", crm_system_name); clean_up(0); return 0; /* never reached */ } void wait_for_refresh(int offset, const char *prefix, int msec) { int lpc = msec / 1000; struct timespec sleept = {1 , 0}; if(as_console == FALSE) { timer_id = g_timeout_add(msec, mon_timer_popped, NULL); return; } crm_notice("%sRefresh in %ds...", prefix?prefix:"", lpc); while(lpc > 0) { #if CURSES_ENABLED move(offset, 0); /* printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */ printw("%sRefresh in %ds...\n", prefix?prefix:"", lpc); clrtoeol(); refresh(); #endif lpc--; if(lpc == 0) { timer_id = g_timeout_add( 1000, mon_timer_popped, NULL); } else { if (nanosleep(&sleept, NULL) != 0) { return; } } } } #define mon_warn(fmt...) do { \ if (!has_warnings) { \ print_as("Warning:"); \ } else { \ print_as(","); \ } \ print_as(fmt); \ has_warnings = TRUE; \ } while(0) static int print_simple_status(pe_working_set_t *data_set) { node_t *dc = NULL; + GListPtr gIter = NULL; int nodes_online = 0; int nodes_standby = 0; dc = data_set->dc_node; if(dc == NULL) { mon_warn("No DC "); } - slist_iter(node, node_t, data_set->nodes, lpc2, - if(node->details->standby && node->details->online) { - nodes_standby++; - } else if(node->details->online) { - nodes_online++; - } else { - mon_warn("offline node: %s", node->details->uname); - } - ); + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + if(node->details->standby && node->details->online) { + nodes_standby++; + } else if(node->details->online) { + nodes_online++; + } else { + mon_warn("offline node: %s", node->details->uname); + } + } if (!has_warnings) { print_as("Ok: %d nodes online", nodes_online); if (nodes_standby > 0) { print_as(", %d standby nodes", nodes_standby); } print_as(", %d resources configured", g_list_length(data_set->resources)); } print_as("\n"); return 0; } extern int get_failcount(node_t *node, resource_t *rsc, int *last_failure, pe_working_set_t *data_set); static void print_date(time_t time) { int lpc = 0; char date_str[26]; asctime_r(localtime(&time), date_str); for(; lpc < 26; lpc++) { if(date_str[lpc] == '\n') { date_str[lpc] = 0; } } print_as("'%s'", date_str); } static void print_rsc_summary(pe_working_set_t *data_set, node_t *node, resource_t *rsc, gboolean all) { gboolean printed = FALSE; time_t last_failure = 0; char *fail_attr = crm_concat("fail-count", rsc->id, '-'); const char *value = g_hash_table_lookup(node->details->attrs, fail_attr); int failcount = char2score(value); /* Get the true value, not the effective one from get_failcount() */ get_failcount(node, rsc, (int*)&last_failure, data_set); crm_free(fail_attr); if(all || failcount || last_failure > 0) { printed = TRUE; print_as(" %s: migration-threshold=%d", rsc->id, rsc->migration_threshold); } if(failcount > 0) { printed = TRUE; print_as(" fail-count=%d", failcount); } if(last_failure > 0) { printed = TRUE; print_as(" last-failure="); print_date(last_failure); } if(printed) { print_as("\n"); } } static void print_rsc_history(pe_working_set_t *data_set, node_t *node, xmlNode *rsc_entry) { + GListPtr gIter = NULL; GListPtr op_list = NULL; gboolean print_name = TRUE; GListPtr sorted_op_list = NULL; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); sorted_op_list = g_list_sort(op_list, sort_op_by_callid); - slist_iter(xml_op, xmlNode, sorted_op_list, lpc, - const char *value = NULL; - const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); - const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); - const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); - const char *interval = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); - int rc = crm_parse_int(op_rc, "0"); + for(gIter = sorted_op_list; gIter != NULL; gIter = gIter->next) { + xmlNode *xml_op = (xmlNode*)gIter->data; + const char *value = NULL; + const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); + const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); + const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); + const char *interval = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); + int rc = crm_parse_int(op_rc, "0"); - if(safe_str_eq(task, CRMD_ACTION_STATUS) - && safe_str_eq(interval, "0")) { - task = "probe"; - } + if(safe_str_eq(task, CRMD_ACTION_STATUS) + && safe_str_eq(interval, "0")) { + task = "probe"; + } - if(rc == 7 && safe_str_eq(task, "probe")) { - continue; + if(rc == 7 && safe_str_eq(task, "probe")) { + continue; - } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { - continue; - } + } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { + continue; + } - if(print_name) { - print_name = FALSE; - if(rsc == NULL) { - print_as("Orphan resource: %s", rsc_id); - } else { - print_rsc_summary(data_set, node, rsc, TRUE); - } - } + if(print_name) { + print_name = FALSE; + if(rsc == NULL) { + print_as("Orphan resource: %s", rsc_id); + } else { + print_rsc_summary(data_set, node, rsc, TRUE); + } + } - print_as(" + (%s) %s:", call, task); - if(safe_str_neq(interval, "0")) { - print_as(" interval=%sms", interval); - } - - if(print_timing) { - int int_value; - const char *attr = "last-rc-change"; - value = crm_element_value(xml_op, attr); - if(value) { - int_value = crm_parse_int(value, NULL); - print_as(" %s=", attr); - print_date(int_value); - } - - attr = "last-run"; - value = crm_element_value(xml_op, attr); - if(value) { - int_value = crm_parse_int(value, NULL); - print_as(" %s=", attr); - print_date(int_value); - } + print_as(" + (%s) %s:", call, task); + if(safe_str_neq(interval, "0")) { + print_as(" interval=%sms", interval); + } + + if(print_timing) { + int int_value; + const char *attr = "last-rc-change"; + value = crm_element_value(xml_op, attr); + if(value) { + int_value = crm_parse_int(value, NULL); + print_as(" %s=", attr); + print_date(int_value); + } + + attr = "last-run"; + value = crm_element_value(xml_op, attr); + if(value) { + int_value = crm_parse_int(value, NULL); + print_as(" %s=", attr); + print_date(int_value); + } - attr = "exec-time"; - value = crm_element_value(xml_op, attr); - if(value) { - int_value = crm_parse_int(value, NULL); - print_as(" %s=%dms", attr, int_value); - } + attr = "exec-time"; + value = crm_element_value(xml_op, attr); + if(value) { + int_value = crm_parse_int(value, NULL); + print_as(" %s=%dms", attr, int_value); + } - attr = "queue-time"; - value = crm_element_value(xml_op, attr); - if(value) { - int_value = crm_parse_int(value, NULL); - print_as(" %s=%dms", attr, int_value); - } - } - - print_as(" rc=%s (%s)\n", op_rc, execra_code2string(rc)); + attr = "queue-time"; + value = crm_element_value(xml_op, attr); + if(value) { + int_value = crm_parse_int(value, NULL); + print_as(" %s=%dms", attr, int_value); + } + } - ); + print_as(" rc=%s (%s)\n", op_rc, execra_code2string(rc)); + } /* no need to free the contents */ g_list_free(sorted_op_list); } static void print_attr_msg(node_t *node, GListPtr rsc_list, const char *attrname, const char *attrvalue) { - slist_iter(rsc, resource_t, rsc_list, lpc2, - + GListPtr gIter = NULL; + for(gIter = rsc_list; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; const char *type = g_hash_table_lookup(rsc->meta, "type"); if(rsc->children != NULL) { print_attr_msg(node, rsc->children, attrname, attrvalue); } if(safe_str_eq(type, "ping") || safe_str_eq(type, "pingd")) { const char *name = "pingd"; const char *multiplier = NULL; char **host_list = NULL; int host_list_num = 0; int expected_score = 0; if(g_hash_table_lookup(rsc->meta, "name") != NULL) { name = g_hash_table_lookup(rsc->meta, "name"); } /* To identify the resource with the attribute name. */ if(safe_str_eq(name, attrname)) { int value = crm_parse_int(attrvalue, "0"); multiplier = g_hash_table_lookup(rsc->meta, "multiplier"); host_list = g_strsplit(g_hash_table_lookup(rsc->meta, "host_list"), " ", 0); host_list_num = g_strv_length(host_list); g_strfreev(host_list); /* pingd multiplier is the same as the default value. */ expected_score = host_list_num * crm_parse_int(multiplier, "1"); /* pingd is abnormal score. */ if(value <= 0) { print_as("\t: Connectivity is lost"); } else if(value < expected_score) { print_as("\t: Connectivity is degraded (Expected=%d)", expected_score); } } } - ); + } } static int compare_attribute(gconstpointer a, gconstpointer b) { int rc; rc = strcmp((const char*)a, (const char*)b); return rc; } static void create_attr_list(gpointer name, gpointer value, gpointer data) { int i; const char *filt_str[] = FILTER_STR; CRM_CHECK(name != NULL, return); /* filtering automatic attributes */ for(i = 0; filt_str[i] != NULL; i++) { if(g_str_has_prefix(name, filt_str[i])) { return; } } attr_list = g_list_insert_sorted(attr_list, name, compare_attribute); } static void print_node_attribute(gpointer name, gpointer node_data) { const char *value = NULL; node_t *node = (node_t *)node_data; value = g_hash_table_lookup(node->details->attrs, name); print_as(" + %-32s\t: %-10s", (char *)name, value); print_attr_msg(node, node->details->running_rsc, name, value); print_as("\n"); } static void print_node_summary(pe_working_set_t *data_set, gboolean operations) { xmlNode *lrm_rsc = NULL; xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input); if(operations) { print_as("\nOperations:\n"); } else { print_as("\nMigration summary:\n"); } xml_child_iter_filter( cib_status, node_state, XML_CIB_TAG_STATE, node_t *node = pe_find_node_id(data_set->nodes, ID(node_state)); if(node == NULL || node->details->online == FALSE){ continue; } print_as("* Node %s: ", crm_element_value(node_state, XML_ATTR_UNAME)); print_as("\n"); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); xml_child_iter_filter( lrm_rsc, rsc_entry, XML_LRM_TAG_RESOURCE, if(operations) { print_rsc_history(data_set, node, rsc_entry); } else { const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc) { print_rsc_summary(data_set, node, rsc, FALSE); } else { print_as(" %s: orphan\n", rsc_id); } } ); ); } static char * add_list_element(char *list, const char *value) { int len = 0; int last = 0; if(value == NULL) { return list; } if(list) { last = strlen(list); } len = last + 2; /* +1 space, +1 EOS */ len += strlen(value); crm_realloc(list, len); sprintf(list + last, " %s", value); return list; } static int print_status(pe_working_set_t *data_set) { static int updates = 0; + GListPtr gIter = NULL; node_t *dc = NULL; char *since_epoch = NULL; char *online_nodes = NULL; char *offline_nodes = NULL; xmlNode *dc_version = NULL; xmlNode *quorum_node = NULL; xmlNode *stack = NULL; time_t a_time = time(NULL); int configured_resources = 0; int print_opts = pe_print_ncurses; const char *quorum_votes = "unknown"; if(as_console) { blank_screen(); } else { print_opts = pe_print_printf; } updates++; dc = data_set->dc_node; print_as("============\n"); if(a_time == (time_t)-1) { crm_perror(LOG_ERR,"set_node_tstamp(): Invalid time returned"); return 1; } since_epoch = ctime(&a_time); if(since_epoch != NULL) { print_as("Last updated: %s", since_epoch); } stack = get_xpath_object("//nvpair[@name='cluster-infrastructure']", data_set->input, LOG_DEBUG); if(stack) { - print_as("Stack: %s\n", crm_element_value(stack, XML_NVPAIR_ATTR_VALUE)); + print_as("Stack: %s\n", crm_element_value(stack, XML_NVPAIR_ATTR_VALUE)); } dc_version = get_xpath_object("//nvpair[@name='dc-version']", data_set->input, LOG_DEBUG); if(dc == NULL) { print_as("Current DC: NONE\n"); } else { const char *quorum = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM); if(safe_str_neq(dc->details->uname, dc->details->id)) { print_as("Current DC: %s (%s)", dc->details->uname, dc->details->id); } else { print_as("Current DC: %s", dc->details->uname); } print_as(" - partition %s quorum\n", crm_is_true(quorum)?"with":"WITHOUT"); if(dc_version) { print_as("Version: %s\n", crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE)); } } quorum_node = get_xpath_object("//nvpair[@name='"XML_ATTR_EXPECTED_VOTES"']", data_set->input, LOG_DEBUG); if(quorum_node) { quorum_votes = crm_element_value(quorum_node, XML_NVPAIR_ATTR_VALUE); } - slist_iter(rsc, resource_t, data_set->resources, lpc, - if(is_not_set(rsc->flags, pe_rsc_orphan)) { - configured_resources++; - } - ); + for(gIter = data_set->resources; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + if(is_not_set(rsc->flags, pe_rsc_orphan)) { + configured_resources++; + } + } print_as("%d Nodes configured, %s expected votes\n", g_list_length(data_set->nodes), quorum_votes); print_as("%d Resources configured.\n", configured_resources); print_as("============\n\n"); - slist_iter(node, node_t, data_set->nodes, lpc2, - const char *node_mode = NULL; + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + const char *node_mode = NULL; - if(node->details->unclean) { - if(node->details->online && node->details->unclean) { - node_mode = "UNCLEAN (online)"; + if(node->details->unclean) { + if(node->details->online && node->details->unclean) { + node_mode = "UNCLEAN (online)"; - } else if(node->details->pending) { - node_mode = "UNCLEAN (pending)"; + } else if(node->details->pending) { + node_mode = "UNCLEAN (pending)"; - } else { - node_mode = "UNCLEAN (offline)"; - } + } else { + node_mode = "UNCLEAN (offline)"; + } - } else if(node->details->pending) { - node_mode = "pending"; + } else if(node->details->pending) { + node_mode = "pending"; - } else if(node->details->standby_onfail && node->details->online) { - node_mode = "standby (on-fail)"; + } else if(node->details->standby_onfail && node->details->online) { + node_mode = "standby (on-fail)"; - } else if(node->details->standby) { - if(node->details->online) { - node_mode = "standby"; - } else { - node_mode = "OFFLINE (standby)"; - } + } else if(node->details->standby) { + if(node->details->online) { + node_mode = "standby"; + } else { + node_mode = "OFFLINE (standby)"; + } - } else if(node->details->online) { - node_mode = "online"; - if(group_by_node == FALSE) { - online_nodes = add_list_element(online_nodes, node->details->uname); - continue; - } - - } else { - node_mode = "OFFLINE"; - if(group_by_node == FALSE) { - offline_nodes = add_list_element(offline_nodes, node->details->uname); - continue; - } - } - - if(safe_str_eq(node->details->uname, node->details->id)) { - print_as("Node %s: %s\n", - node->details->uname, node_mode); - } else { - print_as("Node %s (%s): %s\n", - node->details->uname, node->details->id, - node_mode); - } + } else if(node->details->online) { + node_mode = "online"; + if(group_by_node == FALSE) { + online_nodes = add_list_element(online_nodes, node->details->uname); + continue; + } + + } else { + node_mode = "OFFLINE"; + if(group_by_node == FALSE) { + offline_nodes = add_list_element(offline_nodes, node->details->uname); + continue; + } + } + + if(safe_str_eq(node->details->uname, node->details->id)) { + print_as("Node %s: %s\n", + node->details->uname, node_mode); + } else { + print_as("Node %s (%s): %s\n", + node->details->uname, node->details->id, + node_mode); + } - if(group_by_node) { - slist_iter(rsc, resource_t, - node->details->running_rsc, lpc2, - rsc->fns->print( - rsc, "\t", print_opts|pe_print_rsconly, stdout); - ); - } - ); + if(group_by_node) { + GListPtr gIter2 = NULL; + for(gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) { + resource_t *rsc = (resource_t*)gIter2->data; + rsc->fns->print(rsc, "\t", print_opts|pe_print_rsconly, stdout); + } + } + } if(online_nodes) { print_as("Online: [%s ]\n", online_nodes); crm_free(online_nodes); } if(offline_nodes) { print_as("OFFLINE: [%s ]\n", offline_nodes); crm_free(offline_nodes); } if(group_by_node == FALSE && inactive_resources) { print_as("\nFull list of resources:\n"); } else if(inactive_resources) { print_as("\nInactive resources:\n"); } if(group_by_node == FALSE || inactive_resources) { print_as("\n"); - slist_iter(rsc, resource_t, data_set->resources, lpc2, - gboolean is_active = rsc->fns->active(rsc, TRUE); - gboolean partially_active = rsc->fns->active(rsc, FALSE); - if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { - continue; + for(gIter = data_set->resources; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + + gboolean is_active = rsc->fns->active(rsc, TRUE); + gboolean partially_active = rsc->fns->active(rsc, FALSE); + if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { + continue; - } else if(group_by_node == FALSE) { - if(partially_active || inactive_resources) { - rsc->fns->print(rsc, NULL, print_opts, stdout); - } + } else if(group_by_node == FALSE) { + if(partially_active || inactive_resources) { + rsc->fns->print(rsc, NULL, print_opts, stdout); + } - } else if(is_active == FALSE && inactive_resources) { - rsc->fns->print(rsc, NULL, print_opts, stdout); - } - ); + } else if(is_active == FALSE && inactive_resources) { + rsc->fns->print(rsc, NULL, print_opts, stdout); + } + } } if(print_nodes_attr) { print_as("\nNode Attributes:\n"); - slist_iter( - node, node_t, data_set->nodes, lpc, + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + if(node == NULL || node->details->online == FALSE){ continue; } attr_list = NULL; print_as("* Node %s:\n", node->details->uname); g_hash_table_foreach(node->details->attrs, create_attr_list, NULL); g_list_foreach(attr_list, print_node_attribute, node); - ); + } } if(print_operations || print_failcount) { print_node_summary(data_set, print_operations); } if(xml_has_children(data_set->failed)) { print_as("\nFailed actions:\n"); xml_child_iter(data_set->failed, xml_op, int val = 0; const char *id = ID(xml_op); const char *last = crm_element_value(xml_op, "last_run"); const char *node = crm_element_value(xml_op, XML_ATTR_UNAME); const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); const char *rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); const char *status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); val = crm_parse_int(status, "0"); print_as(" %s (node=%s, call=%s, rc=%s, status=%s", id, node, call, rc, op_status2text(val)); if(last) { time_t run_at = crm_parse_int(last, "0"); print_as(", last-run=%s, queued=%sms, exec=%sms\n", ctime(&run_at), crm_element_value(xml_op, "exec_time"), crm_element_value(xml_op, "queue_time")); } val = crm_parse_int(rc, "0"); print_as("): %s\n", execra_code2string(val)); ); } #if CURSES_ENABLED if(as_console) { refresh(); } #endif return 0; } static int print_html_status(pe_working_set_t *data_set, const char *filename, gboolean web_cgi) { FILE *stream; + GListPtr gIter = NULL; node_t *dc = NULL; static int updates = 0; char *filename_tmp = NULL; if (web_cgi) { stream=stdout; fprintf(stream, "Content-type: text/html\n\n"); } else { filename_tmp = crm_concat(filename, "tmp", '.'); stream = fopen(filename_tmp, "w"); if(stream == NULL) { crm_perror(LOG_ERR,"Cannot open %s for writing", filename_tmp); crm_free(filename_tmp); return -1; } } updates++; dc = data_set->dc_node; fprintf(stream, ""); fprintf(stream, ""); fprintf(stream, "Cluster status"); /* content="%d;url=http://webdesign.about.com" */ fprintf(stream, "", reconnect_msec/1000); fprintf(stream, ""); /*** SUMMARY ***/ fprintf(stream, "

    Cluster summary

    "); { char *now_str = NULL; time_t now = time(NULL); now_str = ctime(&now); now_str[24] = EOS; /* replace the newline */ fprintf(stream, "Last updated: %s
    \n", now_str); } if(dc == NULL) { fprintf(stream, "Current DC: NONE
    "); } else { fprintf(stream, "Current DC: %s (%s)
    ", dc->details->uname, dc->details->id); } fprintf(stream, "%d Nodes configured.
    ", g_list_length(data_set->nodes)); fprintf(stream, "%d Resources configured.
    ", g_list_length(data_set->resources)); /*** CONFIG ***/ fprintf(stream, "

    Config Options

    \n"); fprintf(stream, "\n"); fprintf(stream, "\n", is_set(data_set->flags, pe_flag_stonith_enabled)?"enabled":"disabled"); fprintf(stream, "\n", is_set(data_set->flags, pe_flag_symmetric_cluster)?"":"a-"); fprintf(stream, "\n
    STONITH of failed nodes:%s
    Cluster is:%ssymmetric
    No Quorum Policy:"); switch (data_set->no_quorum_policy) { case no_quorum_freeze: fprintf(stream, "Freeze resources"); break; case no_quorum_stop: fprintf(stream, "Stop ALL resources"); break; case no_quorum_ignore: fprintf(stream, "Ignore"); break; case no_quorum_suicide: fprintf(stream, "Suicide"); break; } fprintf(stream, "\n
    \n"); /*** NODE LIST ***/ fprintf(stream, "

    Node List

    \n"); fprintf(stream, "
      \n"); - slist_iter(node, node_t, data_set->nodes, lpc2, - fprintf(stream, "
    • "); - if(node->details->standby_onfail && node->details->online) { - fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"standby (on-fail)\n"); - } else if(node->details->standby && node->details->online) { - fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"standby\n"); - } else if(node->details->standby) { - fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"OFFLINE (standby)\n"); - } else if(node->details->online) { - fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"online\n"); - } else { - fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"OFFLINE\n"); - } - if(group_by_node) { - fprintf(stream, "
        \n"); - slist_iter(rsc, resource_t, - node->details->running_rsc, lpc2, - fprintf(stream, "
      • "); - rsc->fns->print(rsc, NULL, - pe_print_html|pe_print_rsconly, stream); - fprintf(stream, "
      • \n"); - ); - fprintf(stream, "
      \n"); - } - fprintf(stream, "
    • \n"); - ); + for(gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { + node_t *node = (node_t*)gIter->data; + + fprintf(stream, "
    • "); + if(node->details->standby_onfail && node->details->online) { + fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"standby (on-fail)\n"); + } else if(node->details->standby && node->details->online) { + fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"standby\n"); + } else if(node->details->standby) { + fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"OFFLINE (standby)\n"); + } else if(node->details->online) { + fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"online\n"); + } else { + fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"OFFLINE\n"); + } + if(group_by_node) { + GListPtr lpc2 = NULL; + fprintf(stream, "
        \n"); + for(lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) { + resource_t *rsc = (resource_t*)lpc2->data; + + fprintf(stream, "
      • "); + rsc->fns->print(rsc, NULL, pe_print_html|pe_print_rsconly, stream); + fprintf(stream, "
      • \n"); + } + fprintf(stream, "
      \n"); + } + fprintf(stream, "
    • \n"); + } fprintf(stream, "
    \n"); if(group_by_node && inactive_resources) { fprintf(stream, "

    Inactive Resources

    \n"); } else if(group_by_node == FALSE) { fprintf(stream, "

    Resource List

    \n"); } if(group_by_node == FALSE || inactive_resources) { - slist_iter(rsc, resource_t, data_set->resources, lpc2, - gboolean is_active = rsc->fns->active(rsc, TRUE); - gboolean partially_active = rsc->fns->active(rsc, FALSE); - if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { - continue; + for(gIter = data_set->resources; gIter != NULL; gIter = gIter->next) { + resource_t *rsc = (resource_t*)gIter->data; + gboolean is_active = rsc->fns->active(rsc, TRUE); + gboolean partially_active = rsc->fns->active(rsc, FALSE); + if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { + continue; - } else if(group_by_node == FALSE) { - if(partially_active || inactive_resources) { - rsc->fns->print(rsc, NULL, pe_print_html, stream); - } + } else if(group_by_node == FALSE) { + if(partially_active || inactive_resources) { + rsc->fns->print(rsc, NULL, pe_print_html, stream); + } - } else if(is_active == FALSE && inactive_resources) { - rsc->fns->print(rsc, NULL, pe_print_html, stream); - } - ); + } else if(is_active == FALSE && inactive_resources) { + rsc->fns->print(rsc, NULL, pe_print_html, stream); + } + } } fprintf(stream, ""); fflush(stream); fclose(stream); if (!web_cgi) { if(rename(filename_tmp, filename) != 0) { crm_perror(LOG_ERR,"Unable to rename %s->%s", filename_tmp, filename); } crm_free(filename_tmp); } return 0; } #if ENABLE_SNMP #include #include #include #include #include #include #define add_snmp_field(list, oid_string, value) do { \ oid name[MAX_OID_LEN]; \ size_t name_length = MAX_OID_LEN; \ if (snmp_parse_oid(oid_string, name, &name_length)) { \ int s_rc = snmp_add_var(list, name, name_length, 's', (value)); \ if(s_rc != 0) { \ crm_err("Could not add %s=%s rc=%d", oid_string, value, s_rc); \ } else { \ crm_debug_2("Added %s=%s", oid_string, value); \ } \ } else { \ crm_err("Could not parse OID: %s", oid_string); \ } \ } while(0) \ #define add_snmp_field_int(list, oid_string, value) do { \ oid name[MAX_OID_LEN]; \ size_t name_length = MAX_OID_LEN; \ if (snmp_parse_oid(oid_string, name, &name_length)) { \ if(NULL == snmp_pdu_add_variable( \ list, name, name_length, ASN_INTEGER, \ (u_char *) & value, sizeof(value))) { \ - crm_err("Could not add %s=%d", oid_string, value); \ + crm_err("Could not add %s=%d", oid_string, value); \ } else { \ crm_debug_2("Added %s=%d", oid_string, value); \ } \ } else { \ crm_err("Could not parse OID: %s", oid_string); \ } \ } while(0) \ static int snmp_input(int operation, netsnmp_session *session, int reqid, netsnmp_pdu *pdu, void *magic) { return 1; } static netsnmp_session *crm_snmp_init(const char *target, char *community) { static netsnmp_session *session = NULL; #ifdef NETSNMPV53 char target53[128]; snprintf(target53, sizeof(target53), "%s:162", target); #endif if(session) { return session; } if(target == NULL) { return NULL; } if(crm_log_level > LOG_INFO) { char *debug_tokens = crm_strdup("run:shell,snmptrap,tdomain"); debug_register_tokens(debug_tokens); snmp_set_do_debugging(1); } crm_malloc0(session, sizeof(netsnmp_session)); snmp_sess_init(session); session->version = SNMP_VERSION_2c; session->callback = snmp_input; session->callback_magic = NULL; if(community) { session->community_len = strlen(community); session->community = (unsigned char*)community; } session = snmp_add(session, #ifdef NETSNMPV53 netsnmp_tdomain_transport(target53, 0, "udp"), #else netsnmp_transport_open_client("snmptrap", target), #endif NULL, NULL); if (session == NULL) { snmp_sess_perror("Could not create snmp transport", session); } return session; } #endif static int send_snmp_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc, int status, const char *desc) { int ret = 1; #if ENABLE_SNMP static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 }; static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 }; netsnmp_pdu *trap_pdu; netsnmp_session *session = crm_snmp_init(snmp_target, snmp_community); trap_pdu = snmp_pdu_create(SNMP_MSG_TRAP2); if ( !trap_pdu ) { crm_err("Failed to create SNMP notification"); return SNMPERR_GENERR; } if(1) { /* send uptime */ char csysuptime[20]; time_t now = time(NULL); sprintf(csysuptime, "%ld", now); snmp_add_var(trap_pdu, sysuptime_oid, sizeof(sysuptime_oid) / sizeof(oid), 't', csysuptime); } /* Indicate what the trap is by setting snmpTrapOid.0 */ ret = snmp_add_var(trap_pdu, snmptrap_oid, sizeof(snmptrap_oid) / sizeof(oid), 'o', snmp_crm_trap_oid); if (ret != 0) { crm_err("Failed set snmpTrapOid.0=%s", snmp_crm_trap_oid); return ret; } /* Add extries to the trap */ add_snmp_field(trap_pdu, snmp_crm_oid_rsc, rsc); add_snmp_field(trap_pdu, snmp_crm_oid_node, node); add_snmp_field(trap_pdu, snmp_crm_oid_task, task); add_snmp_field(trap_pdu, snmp_crm_oid_desc, desc); add_snmp_field_int(trap_pdu, snmp_crm_oid_rc, rc); add_snmp_field_int(trap_pdu, snmp_crm_oid_trc, target_rc); add_snmp_field_int(trap_pdu, snmp_crm_oid_status, status); /* Send and cleanup */ ret = snmp_send(session, trap_pdu); if(ret == 0) { /* error */ snmp_sess_perror("Could not send SNMP trap", session); snmp_free_pdu(trap_pdu); ret = SNMPERR_GENERR; } else { ret = SNMPERR_SUCCESS; } #else crm_err("Sending SNMP traps is not supported by this installation"); #endif return ret; } #if ENABLE_ESMTP #include #include static void print_recipient_status( smtp_recipient_t recipient, const char *mailbox, void *arg) { const smtp_status_t *status; status = smtp_recipient_status (recipient); printf ("%s: %d %s", mailbox, status->code, status->text); } static void event_cb (smtp_session_t session, int event_no, void *arg, ...) { int *ok; va_list alist; va_start(alist, arg); switch(event_no) { case SMTP_EV_CONNECT: case SMTP_EV_MAILSTATUS: case SMTP_EV_RCPTSTATUS: case SMTP_EV_MESSAGEDATA: case SMTP_EV_MESSAGESENT: case SMTP_EV_DISCONNECT: break; case SMTP_EV_WEAK_CIPHER: { int bits = va_arg(alist, long); ok = va_arg(alist, int*); crm_debug("SMTP_EV_WEAK_CIPHER, bits=%d - accepted.", bits); *ok = 1; break; } case SMTP_EV_STARTTLS_OK: crm_debug("SMTP_EV_STARTTLS_OK - TLS started here."); break; case SMTP_EV_INVALID_PEER_CERTIFICATE: { long vfy_result = va_arg(alist, long); ok = va_arg(alist, int*); /* There is a table in handle_invalid_peer_certificate() of mail-file.c */ crm_err("SMTP_EV_INVALID_PEER_CERTIFICATE: %ld", vfy_result); *ok = 1; break; } case SMTP_EV_NO_PEER_CERTIFICATE: ok = va_arg(alist, int*); crm_debug("SMTP_EV_NO_PEER_CERTIFICATE - accepted."); *ok = 1; break; case SMTP_EV_WRONG_PEER_CERTIFICATE: ok = va_arg(alist, int*); crm_debug("SMTP_EV_WRONG_PEER_CERTIFICATE - accepted."); *ok = 1; break; case SMTP_EV_NO_CLIENT_CERTIFICATE: ok = va_arg(alist, int*); crm_debug("SMTP_EV_NO_CLIENT_CERTIFICATE - accepted."); *ok = 1; break; default: crm_debug("Got event: %d - ignored.\n", event_no); } va_end(alist); } #endif #define BODY_MAX 2048 #if ENABLE_ESMTP static void crm_smtp_debug (const char *buf, int buflen, int writing, void *arg) { char type = 0; int lpc = 0, last = 0, level = *(int*)arg; if (writing == SMTP_CB_HEADERS) { type = 'H'; } else if(writing) { type = 'C'; } else { type = 'S'; } for(; lpc < buflen; lpc++) { switch(buf[lpc]) { case 0: case '\n': if(last > 0) { do_crm_log(level, " %.*s", lpc-last, buf+last); } else { do_crm_log(level, "%c: %.*s", type, lpc-last, buf+last); } last = lpc + 1; break; } } } #endif static int send_custom_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc, int status, const char *desc) { - pid_t pid; - /*setenv needs chars, these are ints*/ - char *rc_s = crm_itoa(rc); - char *status_s = crm_itoa(status); - char *target_rc_s = crm_itoa(target_rc); - - crm_debug("Sending external notification to '%s' via '%s'", external_recipient, external_agent); - - setenv("CRM_notify_recipient",external_recipient,1); - setenv("CRM_notify_node",node,1); - setenv("CRM_notify_rsc",rsc,1); - setenv("CRM_notify_task",task,1); - setenv("CRM_notify_desc",desc,1); - setenv("CRM_notify_rc",rc_s,1); - setenv("CRM_notify_target_rc",target_rc_s,1); - setenv("CRM_notify_status",status_s,1); - - pid=fork(); - if(pid == -1) { - cl_perror("notification fork() failed."); - } - if(pid == 0) { - /* crm_debug("notification: I am the child. Executing the nofitication program."); */ - execl(external_agent,external_agent,NULL); - } - - crm_debug_2("Finished running custom notification program '%s'.",external_agent); - crm_free(target_rc_s); - crm_free(status_s); - crm_free(rc_s); - return 0; + pid_t pid; + /*setenv needs chars, these are ints*/ + char *rc_s = crm_itoa(rc); + char *status_s = crm_itoa(status); + char *target_rc_s = crm_itoa(target_rc); + + crm_debug("Sending external notification to '%s' via '%s'", external_recipient, external_agent); + + setenv("CRM_notify_recipient",external_recipient,1); + setenv("CRM_notify_node",node,1); + setenv("CRM_notify_rsc",rsc,1); + setenv("CRM_notify_task",task,1); + setenv("CRM_notify_desc",desc,1); + setenv("CRM_notify_rc",rc_s,1); + setenv("CRM_notify_target_rc",target_rc_s,1); + setenv("CRM_notify_status",status_s,1); + + pid=fork(); + if(pid == -1) { + cl_perror("notification fork() failed."); + } + if(pid == 0) { + /* crm_debug("notification: I am the child. Executing the nofitication program."); */ + execl(external_agent,external_agent,NULL); + } + + crm_debug_2("Finished running custom notification program '%s'.",external_agent); + crm_free(target_rc_s); + crm_free(status_s); + crm_free(rc_s); + return 0; } static int send_smtp_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc, int status, const char *desc) { #if ENABLE_ESMTP smtp_session_t session; smtp_message_t message; auth_context_t authctx; struct sigaction sa; int len = 20; int noauth = 1; int smtp_debug = LOG_DEBUG; char crm_mail_body[BODY_MAX]; char *crm_mail_subject = NULL; if(node == NULL) { node = "-"; } if(rsc == NULL) { rsc = "-"; } if(desc == NULL) { desc = "-"; } if(crm_mail_to == NULL) { return 1; } if(crm_mail_host == NULL) { crm_mail_host = "localhost:25"; } if(crm_mail_prefix == NULL) { crm_mail_prefix = "Cluster notification"; } crm_debug("Sending '%s' mail to %s via %s", crm_mail_prefix, crm_mail_to, crm_mail_host); len += strlen(crm_mail_prefix); len += strlen(task); len += strlen(rsc); len += strlen(node); len += strlen(desc); len++; crm_malloc0(crm_mail_subject, len); snprintf(crm_mail_subject, len, "%s - %s event for %s on %s: %s\r\n", crm_mail_prefix, task, rsc, node, desc); len = 0; len += snprintf(crm_mail_body+len, BODY_MAX-len, "\r\n%s\r\n", crm_mail_prefix); len += snprintf(crm_mail_body+len, BODY_MAX-len, "====\r\n\r\n"); if(rc==target_rc) { len += snprintf(crm_mail_body+len, BODY_MAX-len, "Completed operation %s for resource %s on %s\r\n", task, rsc, node); } else { len += snprintf(crm_mail_body+len, BODY_MAX-len, "Operation %s for resource %s on %s failed: %s\r\n", task, rsc, node, desc); } len += snprintf(crm_mail_body+len, BODY_MAX-len, "\r\nDetails:\r\n"); len += snprintf(crm_mail_body+len, BODY_MAX-len, "\toperation status: (%d) %s\r\n", status, op_status2text(status)); if(status == LRM_OP_DONE) { len += snprintf(crm_mail_body+len, BODY_MAX-len, "\tscript returned: (%d) %s\r\n", rc, execra_code2string(rc)); len += snprintf(crm_mail_body+len, BODY_MAX-len, "\texpected return value: (%d) %s\r\n", target_rc, execra_code2string(target_rc)); } auth_client_init(); session = smtp_create_session(); message = smtp_add_message(session); smtp_starttls_enable (session, Starttls_ENABLED); sa.sa_handler = SIG_IGN; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (SIGPIPE, &sa, NULL); smtp_set_server (session, crm_mail_host); authctx = auth_create_context (); auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0); smtp_set_eventcb(session, event_cb, NULL); /* Now tell libESMTP it can use the SMTP AUTH extension. */ if (!noauth) { crm_debug("Adding authentication context"); smtp_auth_set_context (session, authctx); } if(crm_mail_from == NULL) { struct utsname us; char auto_from[BODY_MAX]; CRM_ASSERT(uname(&us) == 0); snprintf(auto_from, BODY_MAX, "crm_mon@%s", us.nodename); smtp_set_reverse_path (message, auto_from); } else { /* NULL is ok */ smtp_set_reverse_path (message, crm_mail_from); } smtp_set_header (message, "To", NULL/*phrase*/, NULL/*addr*/); /* "Phrase" */ smtp_add_recipient (message, crm_mail_to); /* Set the Subject: header and override any subject line in the message headers. */ smtp_set_header (message, "Subject", crm_mail_subject); smtp_set_header_option (message, "Subject", Hdr_OVERRIDE, 1); smtp_set_message_str(message, crm_mail_body); smtp_set_monitorcb (session, crm_smtp_debug, &smtp_debug, 1); if (smtp_start_session (session)) { char buf[128]; int rc = smtp_errno(); crm_err("SMTP server problem: %s (%d)", smtp_strerror (rc, buf, sizeof buf), rc); } else { char buf[128]; int rc = smtp_errno(); const smtp_status_t *smtp_status = smtp_message_transfer_status(message); if(rc != 0) { crm_err("SMTP server problem: %s (%d)", smtp_strerror (rc, buf, sizeof buf), rc); } crm_info("Send status: %d %s", smtp_status->code, crm_str(smtp_status->text)); smtp_enumerate_recipients (message, print_recipient_status, NULL); } smtp_destroy_session(session); auth_destroy_context(authctx); auth_client_exit(); #endif return 0; } static void handle_rsc_op(xmlNode *rsc_op) { int rc = -1; int status = -1; int action = -1; int interval = 0; int target_rc = -1; int transition_num = -1; gboolean notify = TRUE; char *rsc = NULL; char *task = NULL; const char *desc = NULL; const char *node = NULL; const char *magic = NULL; const char *id = ID(rsc_op); char *update_te_uuid = NULL; xmlNode *n = rsc_op; magic = crm_element_value(rsc_op, XML_ATTR_TRANSITION_MAGIC); if(magic == NULL) { /* non-change */ return; } if(FALSE == decode_transition_magic( magic, &update_te_uuid, &transition_num, &action, &status, &rc, &target_rc)) { crm_err("Invalid event %s detected for %s", magic, id); return; } if(parse_op_key(id, &rsc, &task, &interval) == FALSE) { crm_err("Invalid event detected for %s", id); goto bail; } while(n != NULL && safe_str_neq(XML_CIB_TAG_STATE, TYPE(n))) { n = n->parent; } node = crm_element_value(n, XML_ATTR_UNAME); if(node == NULL) { node = ID(n); } if(node == NULL) { crm_err("No node detected for event %s (%s)", magic, id); goto bail; } /* look up where we expected it to be? */ desc = cib_error2string(cib_ok); if(status == LRM_OP_DONE && target_rc == rc) { crm_notice("%s of %s on %s completed: %s", task, rsc, node, desc); if(rc == EXECRA_NOT_RUNNING) { notify = FALSE; } } else if(status == LRM_OP_DONE) { desc = execra_code2string(rc); crm_warn("%s of %s on %s failed: %s", task, rsc, node, desc); } else { desc = op_status2text(status); crm_warn("%s of %s on %s failed: %s", task, rsc, node, desc); } if(notify && snmp_target) { send_snmp_trap(node, rsc, task, target_rc, rc, status, desc); } if(notify && crm_mail_to) { send_smtp_trap(node, rsc, task, target_rc, rc, status, desc); } if(notify && external_agent) { send_custom_trap(node, rsc, task, target_rc, rc, status, desc); } bail: crm_free(update_te_uuid); crm_free(rsc); crm_free(task); } void crm_diff_update(const char *event, xmlNode *msg) { int rc = -1; long now = time(NULL); const char *op = NULL; unsigned int log_level = LOG_INFO; xmlNode *diff = NULL; xmlNode *cib_last = NULL; xmlNode *update = get_message_xml(msg, F_CIB_UPDATE); print_dot(); if(msg == NULL) { crm_err("NULL update"); return; } crm_element_value_int(msg, F_CIB_RC, &rc); op = crm_element_value(msg, F_CIB_OPERATION); diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); if(rc < cib_ok) { log_level = LOG_WARNING; do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, cib_error2string(rc)); return; } if(current_cib != NULL) { cib_last = current_cib; current_cib = NULL; rc = cib_process_diff(op, cib_force_diff, NULL, NULL, diff, cib_last, ¤t_cib, NULL); if(rc != cib_ok) { crm_debug("Update didn't apply, requesting full copy: %s", cib_error2string(rc)); free_xml(current_cib); current_cib = NULL; } } if(current_cib == NULL) { current_cib = get_cib_copy(cib); } if(log_diffs && diff) { log_cib_diff(LOG_DEBUG, diff, op); } if(log_updates && update != NULL) { do_crm_log_xml(LOG_DEBUG, "raw_update", update); } if(diff && (crm_mail_to || snmp_target || external_agent)) { /* Process operation updates */ xmlXPathObject *xpathObj = xpath_search( diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RSC_OP); if(xpathObj && xpathObj->nodesetval->nodeNr > 0) { int lpc = 0, max = xpathObj->nodesetval->nodeNr; for(lpc = 0; lpc < max; lpc++) { xmlNode *rsc_op = getXpathResult(xpathObj, lpc); handle_rsc_op(rsc_op); } } if (xpathObj) { xmlXPathFreeObject(xpathObj); } } if((now - last_refresh) > (reconnect_msec/1000)) { /* Force a refresh */ mon_refresh_display(NULL); } else { mainloop_set_trigger(refresh_trigger); } free_xml(cib_last); } gboolean mon_refresh_display(gpointer user_data) { xmlNode *cib_copy = copy_xml(current_cib); pe_working_set_t data_set; last_refresh = time(NULL); if(cli_config_update(&cib_copy, NULL, FALSE) == FALSE) { if(cib) { cib->cmds->signoff(cib); } print_as("Upgrade failed: %s", cib_error2string(cib_dtd_validation)); if(as_console) { sleep(2); } clean_up(LSB_EXIT_GENERIC); return FALSE; } set_working_set_defaults(&data_set); data_set.input = cib_copy; cluster_status(&data_set); if(as_html_file || web_cgi) { if (print_html_status(&data_set, as_html_file, web_cgi) != 0) { fprintf(stderr, "Critical: Unable to output html file\n"); clean_up(LSB_EXIT_GENERIC); } } else if(daemonize) { /* do nothing */ } else if (simple_status) { print_simple_status(&data_set); if (has_warnings) { clean_up(LSB_EXIT_GENERIC); } } else { print_status(&data_set); } cleanup_calculations(&data_set); return TRUE; } /* * De-init ncurses, signoff from the CIB and deallocate memory. */ void clean_up(int rc) { #if ENABLE_SNMP netsnmp_session *session = crm_snmp_init(NULL, NULL); if(session) { snmp_close(session); snmp_shutdown("snmpapp"); } #endif #if CURSES_ENABLED if(as_console) { as_console = FALSE; echo(); nocbreak(); endwin(); } #endif if (cib != NULL) { cib->cmds->signoff(cib); cib_delete(cib); cib = NULL; } crm_free(as_html_file); crm_free(xml_file); crm_free(pid_file); if(rc >= 0) { exit(rc); } return; } diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 54bb8496ae..db4ab8a7de 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -1,1623 +1,1663 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include gboolean do_force = FALSE; gboolean BE_QUIET = FALSE; const char *attr_set_type = XML_TAG_ATTR_SETS; char *host_id = NULL; const char *rsc_id = NULL; const char *host_uname = NULL; const char *prop_name = NULL; const char *prop_value = NULL; const char *rsc_type = NULL; const char *prop_id = NULL; const char *prop_set = NULL; char *move_lifetime = NULL; char rsc_cmd = 'L'; char *our_pid = NULL; IPC_Channel *crmd_channel = NULL; char *xml_file = NULL; int cib_options = cib_sync_call; int crmd_replies_needed = 0; GMainLoop *mainloop = NULL; extern void cleanup_alloc_calculations(pe_working_set_t *data_set); #define CMD_ERR(fmt, args...) do { \ crm_warn(fmt, ##args); \ fprintf(stderr, fmt, ##args); \ } while(0) #define message_timeout_ms 60*1000 static gboolean resource_ipc_timeout(gpointer data) { - fprintf(stderr, "No messages received in %d seconds.. aborting\n", - (int)message_timeout_ms/1000); - crm_err("No messages received in %d seconds", - (int)message_timeout_ms/1000); - exit(-1); + fprintf(stderr, "No messages received in %d seconds.. aborting\n", + (int)message_timeout_ms/1000); + crm_err("No messages received in %d seconds", + (int)message_timeout_ms/1000); + exit(-1); } static void resource_ipc_connection_destroy(gpointer user_data) { - crm_info("Connection to CRMd was terminated"); - exit(1); + crm_info("Connection to CRMd was terminated"); + exit(1); } static void start_mainloop(void) { mainloop = g_main_new(FALSE); crmd_replies_needed++; /* The welcome message */ fprintf(stderr, "Waiting for %d replies from the CRMd", crmd_replies_needed); crm_debug("Waiting for %d replies from the CRMd", crmd_replies_needed); g_timeout_add(message_timeout_ms, resource_ipc_timeout, NULL); g_main_run(mainloop); } static gboolean resource_ipc_callback(IPC_Channel * server, void *private_data) { int lpc = 0; xmlNode *msg = NULL; gboolean stay_connected = TRUE; while(IPC_ISRCONN(server)) { if(server->ops->is_message_pending(server) == 0) { break; } msg = xmlfromIPC(server, MAX_IPC_DELAY); if (msg == NULL) { break; } lpc++; fprintf(stderr, "."); crm_log_xml(LOG_DEBUG_2, "[inbound]", msg); crmd_replies_needed--; if(crmd_replies_needed == 0) { fprintf(stderr, " OK\n"); crm_debug("Got all the replies we expected"); crm_xml_cleanup(); exit(0); } free_xml(msg); msg = NULL; if(server->ch_status != IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages (%d)", lpc, server->ch_status); if (server->ch_status != IPC_CONNECT) { stay_connected = FALSE; } return stay_connected; } static int do_find_resource(const char *rsc, pe_working_set_t *data_set) { - int found = 0; - resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); + int found = 0; + GListPtr lpc = NULL; + resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); - if(the_rsc == NULL) { - return cib_NOTEXISTS; - } + if(the_rsc == NULL) { + return cib_NOTEXISTS; + } - slist_iter(node, node_t, the_rsc->running_on, lpc, - crm_debug_3("resource %s is running on: %s", - rsc, node->details->uname); - if(BE_QUIET) { - fprintf(stdout, "%s\n", node->details->uname); - } else { - const char *state = ""; - if(the_rsc->variant == pe_native && the_rsc->role == RSC_ROLE_MASTER) { - state = "Master"; - } - fprintf(stdout, "resource %s is running on: %s %s\n", - rsc, node->details->uname, state); - } - - found++; - ); + for(lpc = the_rsc->running_on; lpc != NULL; lpc = lpc->next) { + node_t *node = (node_t*)lpc->data; - if(BE_QUIET == FALSE && found == 0) { - fprintf(stderr, "resource %s is NOT running\n", rsc); + crm_debug_3("resource %s is running on: %s", + rsc, node->details->uname); + if(BE_QUIET) { + fprintf(stdout, "%s\n", node->details->uname); + } else { + const char *state = ""; + if(the_rsc->variant == pe_native && the_rsc->role == RSC_ROLE_MASTER) { + state = "Master"; + } + fprintf(stdout, "resource %s is running on: %s %s\n", + rsc, node->details->uname, state); } + + found++; + } - return 0; + if(BE_QUIET == FALSE && found == 0) { + fprintf(stderr, "resource %s is NOT running\n", rsc); + } + + return 0; } #define cons_string(x) x?x:"NA" static void print_cts_constraints(pe_working_set_t *data_set) { xmlNode *lifetime = NULL; xmlNode * cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input); xml_child_iter(cib_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { continue; } lifetime = first_named_child(xml_obj, "lifetime"); if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) { continue; } if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { printf("Constraint %s %s %s %s %s %s %s\n", crm_element_name(xml_obj), cons_string(crm_element_value(xml_obj, XML_ATTR_ID)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET)), cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE))); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { /* unpack_rsc_location(xml_obj, data_set); */ } ); } static void print_cts_rsc(resource_t *rsc) { + GListPtr lpc = NULL; const char *host = NULL; gboolean needs_quorum = TRUE; const char *rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); const char *rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(safe_str_eq(rclass, "stonith")) { needs_quorum = FALSE; } else { xml_child_iter_filter(rsc->ops_xml, op, "op", - const char *name = crm_element_value(op, "name"); - if(safe_str_neq(name, CRMD_ACTION_START)) { - const char *value = crm_element_value(op, "requires"); - if(safe_str_eq(value, "nothing")) { - needs_quorum = FALSE; + const char *name = crm_element_value(op, "name"); + if(safe_str_neq(name, CRMD_ACTION_START)) { + const char *value = crm_element_value(op, "requires"); + if(safe_str_eq(value, "nothing")) { + needs_quorum = FALSE; + } + break; } - break; - } - ); + ); } if(rsc->running_on != NULL && g_list_length(rsc->running_on) == 1) { node_t *tmp = rsc->running_on->data; host = tmp->details->uname; } printf("Resource: %s %s %s %s %s %s %s %s %d %lld 0x%.16llx\n", crm_element_name(rsc->xml), rsc->id, rsc->clone_name?rsc->clone_name:rsc->id, rsc->parent?rsc->parent->id:"NA", rprov?rprov:"NA", rclass, rtype, host?host:"NA", needs_quorum, rsc->flags, rsc->flags); - slist_iter(child, resource_t, rsc->children, lpc, - print_cts_rsc(child); - ); + for(lpc = rsc->children; lpc != NULL; lpc = lpc->next) { + resource_t *child = (resource_t*)lpc->data; + + print_cts_rsc(child); + } } static void print_raw_rsc(resource_t *rsc) { - GListPtr children = rsc->children; + GListPtr lpc = NULL; + GListPtr children = rsc->children; - if(children == NULL) { - printf("%s\n", rsc->id); - } + if(children == NULL) { + printf("%s\n", rsc->id); + } - slist_iter(child, resource_t, children, lpc, - print_raw_rsc(child); - ); + for(lpc = children; lpc != NULL; lpc = lpc->next) { + resource_t *child = (resource_t*)lpc->data; + + print_raw_rsc(child); + } } static int do_find_resource_list(pe_working_set_t *data_set, gboolean raw) { - int found = 0; + int found = 0; - slist_iter( - rsc, resource_t, data_set->resources, lpc, - if(is_set(rsc->flags, pe_rsc_orphan) - && rsc->fns->active(rsc, TRUE) == FALSE) { - continue; - } - rsc->fns->print( - rsc, NULL, pe_print_printf|pe_print_rsconly, stdout); - found++; - ); - - if(found == 0) { - printf("NO resources configured\n"); - return cib_NOTEXISTS; + GListPtr lpc = NULL; + for(lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + resource_t *rsc = (resource_t*)lpc->data; + + if(is_set(rsc->flags, pe_rsc_orphan) + && rsc->fns->active(rsc, TRUE) == FALSE) { + continue; } + rsc->fns->print( + rsc, NULL, pe_print_printf|pe_print_rsconly, stdout); + found++; + } - return 0; + if(found == 0) { + printf("NO resources configured\n"); + return cib_NOTEXISTS; + } + + return 0; } static resource_t *find_rsc_or_clone(const char *rsc, pe_working_set_t *data_set) { resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { char *as_clone = crm_concat(rsc, "0", ':'); the_rsc = pe_find_resource(data_set->resources, as_clone); crm_free(as_clone); } return the_rsc; } static int dump_resource(const char *rsc, pe_working_set_t *data_set) { - char *rsc_xml = NULL; - resource_t *the_rsc = find_rsc_or_clone(rsc, data_set); + char *rsc_xml = NULL; + resource_t *the_rsc = find_rsc_or_clone(rsc, data_set); - if(the_rsc == NULL) { - return cib_NOTEXISTS; - } - the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout); + if(the_rsc == NULL) { + return cib_NOTEXISTS; + } + the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout); - rsc_xml = dump_xml_formatted(the_rsc->xml); + rsc_xml = dump_xml_formatted(the_rsc->xml); - fprintf(stdout, "raw xml:\n%s\n", rsc_xml); + fprintf(stdout, "raw xml:\n%s\n", rsc_xml); - crm_free(rsc_xml); + crm_free(rsc_xml); - return 0; + return 0; } static int dump_resource_attr( - const char *rsc, const char *attr, pe_working_set_t *data_set) + const char *rsc, const char *attr, pe_working_set_t *data_set) { - int rc = cib_NOTEXISTS; - node_t *current = NULL; - GHashTable *params = NULL; - resource_t *the_rsc = find_rsc_or_clone(rsc, data_set); - const char *value = NULL; + int rc = cib_NOTEXISTS; + node_t *current = NULL; + GHashTable *params = NULL; + resource_t *the_rsc = find_rsc_or_clone(rsc, data_set); + const char *value = NULL; - if(the_rsc == NULL) { - return cib_NOTEXISTS; - } + if(the_rsc == NULL) { + return cib_NOTEXISTS; + } - if(g_list_length(the_rsc->running_on) == 1) { - current = the_rsc->running_on->data; + if(g_list_length(the_rsc->running_on) == 1) { + current = the_rsc->running_on->data; - } else if(g_list_length(the_rsc->running_on) > 1) { - CMD_ERR("%s is active on more than one node," - " returning the default value for %s\n", - the_rsc->id, crm_str(value)); - } + } else if(g_list_length(the_rsc->running_on) > 1) { + CMD_ERR("%s is active on more than one node," + " returning the default value for %s\n", + the_rsc->id, crm_str(value)); + } - params = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); + params = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, g_hash_destroy_str); - if(safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) { - get_rsc_attributes(params, the_rsc, current, data_set); - } else if(safe_str_eq(attr_set_type, XML_TAG_META_SETS)) { - get_meta_attributes(params, the_rsc, current, data_set); - } else { - unpack_instance_attributes(data_set->input, the_rsc->xml, XML_TAG_UTILIZATION, NULL, - params, NULL, FALSE, data_set->now); - } + if(safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) { + get_rsc_attributes(params, the_rsc, current, data_set); + } else if(safe_str_eq(attr_set_type, XML_TAG_META_SETS)) { + get_meta_attributes(params, the_rsc, current, data_set); + } else { + unpack_instance_attributes(data_set->input, the_rsc->xml, XML_TAG_UTILIZATION, NULL, + params, NULL, FALSE, data_set->now); + } - crm_debug("Looking up %s in %s", attr, the_rsc->id); - value = g_hash_table_lookup(params, attr); - if(value != NULL) { - fprintf(stdout, "%s\n", value); - rc = 0; - } + crm_debug("Looking up %s in %s", attr, the_rsc->id); + value = g_hash_table_lookup(params, attr); + if(value != NULL) { + fprintf(stdout, "%s\n", value); + rc = 0; + } - g_hash_table_destroy(params); - return rc; + g_hash_table_destroy(params); + return rc; } static int find_resource_attr( cib_t *the_cib, const char *attr, const char *rsc, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, char **value) { int offset = 0; static int xpath_max = 1024; enum cib_errors rc = cib_ok; xmlNode *xml_search = NULL; char *xpath_string = NULL; CRM_ASSERT(value != NULL); *value = NULL; crm_malloc0(xpath_string, xpath_max); offset += snprintf(xpath_string + offset, xpath_max - offset, "%s", get_object_path("resources")); offset += snprintf(xpath_string + offset, xpath_max - offset, "//*[@id=\"%s\"]", rsc); if(set_type) { offset += snprintf(xpath_string + offset, xpath_max - offset, "//%s", set_type); if(set_name) { offset += snprintf(xpath_string + offset, xpath_max - offset, "[@id=\"%s\"]", set_name); } } offset += snprintf(xpath_string + offset, xpath_max - offset, "//nvpair["); if(attr_id) { offset += snprintf(xpath_string + offset, xpath_max - offset, "@id=\"%s\"", attr_id); } if(attr_name) { if(attr_id) { offset += snprintf(xpath_string + offset, xpath_max - offset, " and "); } offset += snprintf(xpath_string + offset, xpath_max - offset, "@name=\"%s\"", attr_name); } offset += snprintf(xpath_string + offset, xpath_max - offset, "]"); rc = the_cib->cmds->query( the_cib, xpath_string, &xml_search, cib_sync_call|cib_scope_local|cib_xpath); if(rc != cib_ok) { goto bail; } crm_log_xml_debug(xml_search, "Match"); if(xml_has_children(xml_search)) { rc = cib_missing_data; printf("Multiple attributes match name=%s\n", attr_name); xml_child_iter(xml_search, child, printf(" Value: %s \t(id=%s)\n", crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); ); } else { const char *tmp = crm_element_value(xml_search, attr); if(tmp) { *value = crm_strdup(tmp); } } bail: crm_free(xpath_string); free_xml(xml_search); return rc; } static int set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, const char *attr_value, cib_t *cib, pe_working_set_t *data_set) { - int rc = cib_ok; + int rc = cib_ok; - char *local_attr_id = NULL; - char *local_attr_set = NULL; + char *local_attr_id = NULL; + char *local_attr_set = NULL; - xmlNode *xml_top = NULL; - xmlNode *xml_obj = NULL; + xmlNode *xml_top = NULL; + xmlNode *xml_obj = NULL; - gboolean use_attributes_tag = FALSE; - resource_t *rsc = find_rsc_or_clone(rsc_id, data_set); + gboolean use_attributes_tag = FALSE; + resource_t *rsc = find_rsc_or_clone(rsc_id, data_set); - if(rsc == NULL) { - return cib_NOTEXISTS; - } + if(rsc == NULL) { + return cib_NOTEXISTS; + } - if(safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) { - rc = find_resource_attr( - cib, XML_ATTR_ID, rsc_id, XML_TAG_META_SETS, attr_set, attr_id, attr_name, &local_attr_id); - if(rc == cib_ok) { - printf("WARNING: There is already a meta attribute called %s (id=%s)\n", attr_name, local_attr_id); - } + if(safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) { + rc = find_resource_attr( + cib, XML_ATTR_ID, rsc_id, XML_TAG_META_SETS, attr_set, attr_id, attr_name, &local_attr_id); + if(rc == cib_ok) { + printf("WARNING: There is already a meta attribute called %s (id=%s)\n", attr_name, local_attr_id); } - rc = find_resource_attr( - cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id); + } + rc = find_resource_attr( + cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id); - if(rc == cib_ok) { - crm_debug("Found a match for name=%s: id=%s", attr_name, local_attr_id); - attr_id = local_attr_id; + if(rc == cib_ok) { + crm_debug("Found a match for name=%s: id=%s", attr_name, local_attr_id); + attr_id = local_attr_id; - } else if(rc != cib_NOTEXISTS) { - crm_free(local_attr_id); - return rc; + } else if(rc != cib_NOTEXISTS) { + crm_free(local_attr_id); + return rc; - } else { - const char *value = NULL; - xmlNode *cib_top = NULL; - const char *tag = crm_element_name(rsc->xml); + } else { + const char *value = NULL; + xmlNode *cib_top = NULL; + const char *tag = crm_element_name(rsc->xml); - rc = cib->cmds->query(cib, "/cib", &cib_top, cib_sync_call|cib_scope_local|cib_xpath|cib_no_children); - value = crm_element_value(cib_top, "ignore_dtd"); - if(value != NULL) { - use_attributes_tag = TRUE; + rc = cib->cmds->query(cib, "/cib", &cib_top, cib_sync_call|cib_scope_local|cib_xpath|cib_no_children); + value = crm_element_value(cib_top, "ignore_dtd"); + if(value != NULL) { + use_attributes_tag = TRUE; - } else { - value = crm_element_value(cib_top, XML_ATTR_VALIDATION); - if(value && strstr(value, "-0.6")) { - use_attributes_tag = TRUE; - } + } else { + value = crm_element_value(cib_top, XML_ATTR_VALIDATION); + if(value && strstr(value, "-0.6")) { + use_attributes_tag = TRUE; } - free_xml(cib_top); + } + free_xml(cib_top); - if(attr_set == NULL) { - local_attr_set = crm_concat(rsc_id, attr_set_type, '-'); - attr_set = local_attr_set; - } - if(attr_id == NULL) { - local_attr_id = crm_concat(attr_set, attr_name, '-'); - attr_id = local_attr_id; - } + if(attr_set == NULL) { + local_attr_set = crm_concat(rsc_id, attr_set_type, '-'); + attr_set = local_attr_set; + } + if(attr_id == NULL) { + local_attr_id = crm_concat(attr_set, attr_name, '-'); + attr_id = local_attr_id; + } - if(use_attributes_tag && safe_str_eq(tag, XML_CIB_TAG_MASTER)) { - tag = "master_slave"; /* use the old name */ - } + if(use_attributes_tag && safe_str_eq(tag, XML_CIB_TAG_MASTER)) { + tag = "master_slave"; /* use the old name */ + } - xml_top = create_xml_node(NULL, tag); - crm_xml_add(xml_top, XML_ATTR_ID, rsc_id); + xml_top = create_xml_node(NULL, tag); + crm_xml_add(xml_top, XML_ATTR_ID, rsc_id); - xml_obj = create_xml_node(xml_top, attr_set_type); - crm_xml_add(xml_obj, XML_ATTR_ID, attr_set); + xml_obj = create_xml_node(xml_top, attr_set_type); + crm_xml_add(xml_obj, XML_ATTR_ID, attr_set); - if(use_attributes_tag) { - xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); - } + if(use_attributes_tag) { + xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); } + } - xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); - if(xml_top == NULL) { - xml_top = xml_obj; - } + xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); + if(xml_top == NULL) { + xml_top = xml_obj; + } - crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); + crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); + crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); + crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); - crm_log_xml_debug(xml_top, "Update"); + crm_log_xml_debug(xml_top, "Update"); - rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, cib_options); - free_xml(xml_top); - crm_free(local_attr_id); - crm_free(local_attr_set); - return rc; + rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, cib_options); + free_xml(xml_top); + crm_free(local_attr_id); + crm_free(local_attr_set); + return rc; } static int delete_resource_attr( - const char *rsc_id, const char *attr_set, const char *attr_id, - const char *attr_name, cib_t *cib, pe_working_set_t *data_set) + const char *rsc_id, const char *attr_set, const char *attr_id, + const char *attr_name, cib_t *cib, pe_working_set_t *data_set) { - xmlNode *xml_obj = NULL; + xmlNode *xml_obj = NULL; - int rc = cib_ok; - char *local_attr_id = NULL; - resource_t *rsc = find_rsc_or_clone(rsc_id, data_set); + int rc = cib_ok; + char *local_attr_id = NULL; + resource_t *rsc = find_rsc_or_clone(rsc_id, data_set); - if(rsc == NULL) { - return cib_NOTEXISTS; - } + if(rsc == NULL) { + return cib_NOTEXISTS; + } - rc = find_resource_attr( - cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id); + rc = find_resource_attr( + cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id); - if(rc == cib_NOTEXISTS) { - return cib_ok; + if(rc == cib_NOTEXISTS) { + return cib_ok; - } else if(rc != cib_ok) { - return rc; - } + } else if(rc != cib_ok) { + return rc; + } - if(attr_id == NULL) { - attr_id = local_attr_id; - } + if(attr_id == NULL) { + attr_id = local_attr_id; + } - xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); - crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); + xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); + crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); + crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); - crm_log_xml_debug(xml_obj, "Delete"); + crm_log_xml_debug(xml_obj, "Delete"); - rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, cib_options); + rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, cib_options); - if(rc == cib_ok) { - printf("Deleted %s option: id=%s%s%s%s%s\n", rsc_id, local_attr_id, - attr_set?" set=":"", attr_set?attr_set:"", - attr_name?" name=":"", attr_name?attr_name:""); - } + if(rc == cib_ok) { + printf("Deleted %s option: id=%s%s%s%s%s\n", rsc_id, local_attr_id, + attr_set?" set=":"", attr_set?attr_set:"", + attr_name?" name=":"", attr_name?attr_name:""); + } - free_xml(xml_obj); - crm_free(local_attr_id); - return rc; + free_xml(xml_obj); + crm_free(local_attr_id); + return rc; } static int dump_resource_prop( - const char *rsc, const char *attr, pe_working_set_t *data_set) + const char *rsc, const char *attr, pe_working_set_t *data_set) { - const char *value = NULL; - resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); + const char *value = NULL; + resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); - if(the_rsc == NULL) { - return cib_NOTEXISTS; - } + if(the_rsc == NULL) { + return cib_NOTEXISTS; + } - value = crm_element_value(the_rsc->xml, attr); + value = crm_element_value(the_rsc->xml, attr); - if(value != NULL) { - fprintf(stdout, "%s\n", value); - return 0; - } - return cib_NOTEXISTS; + if(value != NULL) { + fprintf(stdout, "%s\n", value); + return 0; + } + return cib_NOTEXISTS; } static int send_lrm_rsc_op(IPC_Channel *crmd_channel, const char *op, const char *host_uname, const char *rsc_id, gboolean only_failed, pe_working_set_t *data_set) { - char *key = NULL; - int rc = cib_send_failed; - xmlNode *cmd = NULL; - xmlNode *xml_rsc = NULL; - const char *value = NULL; - xmlNode *params = NULL; - xmlNode *msg_data = NULL; - resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); + char *key = NULL; + int rc = cib_send_failed; + xmlNode *cmd = NULL; + xmlNode *xml_rsc = NULL; + const char *value = NULL; + xmlNode *params = NULL; + xmlNode *msg_data = NULL; + resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); - if(rsc == NULL) { - CMD_ERR("Resource %s not found\n", rsc_id); - return cib_NOTEXISTS; + if(rsc == NULL) { + CMD_ERR("Resource %s not found\n", rsc_id); + return cib_NOTEXISTS; - } else if(rsc->variant != pe_native) { - CMD_ERR("We can only process primitive resources, not %s\n", rsc_id); - return cib_invalid_argument; + } else if(rsc->variant != pe_native) { + CMD_ERR("We can only process primitive resources, not %s\n", rsc_id); + return cib_invalid_argument; - } else if(host_uname == NULL) { - CMD_ERR("Please supply a hostname with -H\n"); - return cib_invalid_argument; - } + } else if(host_uname == NULL) { + CMD_ERR("Please supply a hostname with -H\n"); + return cib_invalid_argument; + } - key = crm_concat("0:0:crm-resource", our_pid, '-'); + key = crm_concat("0:0:crm-resource", our_pid, '-'); - msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); - crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); - crm_free(key); + msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); + crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); + crm_free(key); - xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); - if(rsc->clone_name) { - crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->clone_name); - crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->id); + xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); + if(rsc->clone_name) { + crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->clone_name); + crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->id); - } else { - crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id); - crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->long_name); - } + } else { + crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id); + crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->long_name); + } - value = crm_element_value(rsc->xml, XML_ATTR_TYPE); - crm_xml_add(xml_rsc, XML_ATTR_TYPE, value); - if(value == NULL) { - CMD_ERR("%s has no type! Aborting...\n", rsc_id); - return cib_NOTEXISTS; - } + value = crm_element_value(rsc->xml, XML_ATTR_TYPE); + crm_xml_add(xml_rsc, XML_ATTR_TYPE, value); + if(value == NULL) { + CMD_ERR("%s has no type! Aborting...\n", rsc_id); + return cib_NOTEXISTS; + } - value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value); - if(value == NULL) { - CMD_ERR("%s has no class! Aborting...\n", rsc_id); - return cib_NOTEXISTS; - } + value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value); + if(value == NULL) { + CMD_ERR("%s has no class! Aborting...\n", rsc_id); + return cib_NOTEXISTS; + } - value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value); + value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); + crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value); - params = create_xml_node(msg_data, XML_TAG_ATTRS); - crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); + params = create_xml_node(msg_data, XML_TAG_ATTRS); + crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); - key = crm_meta_name(XML_LRM_ATTR_INTERVAL); - crm_xml_add(params, key, "60000"); /* 1 minute */ - crm_free(key); + key = crm_meta_name(XML_LRM_ATTR_INTERVAL); + crm_xml_add(params, key, "60000"); /* 1 minute */ + crm_free(key); - cmd = create_request(op, msg_data, host_uname, - CRM_SYSTEM_CRMD, crm_system_name, our_pid); + cmd = create_request(op, msg_data, host_uname, + CRM_SYSTEM_CRMD, crm_system_name, our_pid); /* crm_log_xml_warn(cmd, "send_lrm_rsc_op"); */ - free_xml(msg_data); + free_xml(msg_data); - if(send_ipc_message(crmd_channel, cmd)) { - rc = 0; + if(send_ipc_message(crmd_channel, cmd)) { + rc = 0; - } else { - CMD_ERR("Could not send %s op to the crmd", op); - rc = cib_connection; - } + } else { + CMD_ERR("Could not send %s op to the crmd", op); + rc = cib_connection; + } - free_xml(cmd); - return rc; + free_xml(cmd); + return rc; } static int delete_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, resource_t *rsc, pe_working_set_t *data_set) { int rc = cib_ok; if(rsc == NULL) { return cib_NOTEXISTS; } else if(rsc->children) { - slist_iter(child, resource_t, rsc->children, lpc, - delete_lrm_rsc(crmd_channel, host_uname, child, data_set)); + GListPtr lpc = NULL; + for(lpc = rsc->children; lpc != NULL; lpc = lpc->next) { + resource_t *child = (resource_t*)lpc->data; + + delete_lrm_rsc(crmd_channel, host_uname, child, data_set); + } return cib_ok; } else if(host_uname == NULL) { - slist_iter(node, node_t, data_set->nodes, lpc, - if(node->details->online) { - delete_lrm_rsc(crmd_channel, node->details->uname, rsc, data_set); - } - ); + GListPtr lpc = NULL; + for(lpc = data_set->nodes; lpc != NULL; lpc = lpc->next) { + node_t *node = (node_t*)lpc->data; + + if(node->details->online) { + delete_lrm_rsc(crmd_channel, node->details->uname, rsc, data_set); + } + } + return cib_ok; } printf("Cleaning up %s on %s\n", rsc->id, host_uname); rc = send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc->id, TRUE, data_set); if(rc == cib_ok) { char *attr_name = NULL; const char *id = rsc->id; crmd_replies_needed++; if(rsc->clone_name) { id = rsc->clone_name; } attr_name = crm_concat("fail-count", id, '-'); attrd_lazy_update('D', host_uname, attr_name, NULL, XML_CIB_TAG_STATUS, NULL, NULL); crm_free(attr_name); } return rc; } static int fail_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { crm_warn("Failing: %s", rsc_id); #if HAVE_STRUCT_LRM_OPS_FAIL_RSC crmd_replies_needed++; #endif return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_FAIL, host_uname, rsc_id, FALSE, data_set); } static int refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname) { - xmlNode *cmd = NULL; - int rc = cib_send_failed; + xmlNode *cmd = NULL; + int rc = cib_send_failed; - cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname, - CRM_SYSTEM_CRMD, crm_system_name, our_pid); + cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname, + CRM_SYSTEM_CRMD, crm_system_name, our_pid); - if(send_ipc_message(crmd_channel, cmd)) { - rc = 0; - } - free_xml(cmd); - return rc; + if(send_ipc_message(crmd_channel, cmd)) { + rc = 0; + } + free_xml(cmd); + return rc; } static int move_resource( - const char *rsc_id, - const char *existing_node, const char *preferred_node, - cib_t * cib_conn) + const char *rsc_id, + const char *existing_node, const char *preferred_node, + cib_t * cib_conn) { - char *later_s = NULL; - enum cib_errors rc = cib_ok; - char *id = NULL; - xmlNode *rule = NULL; - xmlNode *expr = NULL; - xmlNode *constraints = NULL; - xmlNode *fragment = NULL; + char *later_s = NULL; + enum cib_errors rc = cib_ok; + char *id = NULL; + xmlNode *rule = NULL; + xmlNode *expr = NULL; + xmlNode *constraints = NULL; + xmlNode *fragment = NULL; - xmlNode *can_run = NULL; - xmlNode *dont_run = NULL; + xmlNode *can_run = NULL; + xmlNode *dont_run = NULL; - fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS); - constraints = fragment; + fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS); + constraints = fragment; - id = crm_concat("cli-prefer", rsc_id, '-'); - can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); - crm_xml_add(can_run, XML_ATTR_ID, id); - crm_free(id); + id = crm_concat("cli-prefer", rsc_id, '-'); + can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); + crm_xml_add(can_run, XML_ATTR_ID, id); + crm_free(id); - id = crm_concat("cli-standby", rsc_id, '-'); - dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); - crm_xml_add(dont_run, XML_ATTR_ID, id); - crm_free(id); + id = crm_concat("cli-standby", rsc_id, '-'); + dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); + crm_xml_add(dont_run, XML_ATTR_ID, id); + crm_free(id); - if(move_lifetime) { - char *life = crm_strdup(move_lifetime); - char *life_mutable = life; + if(move_lifetime) { + char *life = crm_strdup(move_lifetime); + char *life_mutable = life; - ha_time_t *now = NULL; - ha_time_t *later = NULL; - ha_time_t *duration = parse_time_duration(&life_mutable); + ha_time_t *now = NULL; + ha_time_t *later = NULL; + ha_time_t *duration = parse_time_duration(&life_mutable); - if(duration == NULL) { - CMD_ERR("Invalid duration specified: %s\n", - move_lifetime); - CMD_ERR("Please refer to" - " http://en.wikipedia.org/wiki/ISO_8601#Duration" - " for examples of valid durations\n"); - crm_free(life); - return cib_invalid_argument; - } - now = new_ha_date(TRUE); - later = add_time(now, duration); - log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time); - log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time); - log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local); - later_s = date_to_string(later, ha_log_date|ha_log_time); - printf("Migration will take effect until: %s\n", later_s); - - free_ha_date(duration); - free_ha_date(later); - free_ha_date(now); - crm_free(life); + if(duration == NULL) { + CMD_ERR("Invalid duration specified: %s\n", + move_lifetime); + CMD_ERR("Please refer to" + " http://en.wikipedia.org/wiki/ISO_8601#Duration" + " for examples of valid durations\n"); + crm_free(life); + return cib_invalid_argument; } + now = new_ha_date(TRUE); + later = add_time(now, duration); + log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time); + log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time); + log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local); + later_s = date_to_string(later, ha_log_date|ha_log_time); + printf("Migration will take effect until: %s\n", later_s); + + free_ha_date(duration); + free_ha_date(later); + free_ha_date(now); + crm_free(life); + } - if(existing_node == NULL) { - crm_log_xml_notice(can_run, "Deleting"); - rc = cib_conn->cmds->delete( - cib_conn, XML_CIB_TAG_CONSTRAINTS, dont_run, cib_options); - if(rc == cib_NOTEXISTS) { - rc = cib_ok; + if(existing_node == NULL) { + crm_log_xml_notice(can_run, "Deleting"); + rc = cib_conn->cmds->delete( + cib_conn, XML_CIB_TAG_CONSTRAINTS, dont_run, cib_options); + if(rc == cib_NOTEXISTS) { + rc = cib_ok; - } else if(rc != cib_ok) { - goto bail; - } + } else if(rc != cib_ok) { + goto bail; + } - } else { - if(BE_QUIET == FALSE) { - fprintf(stderr, - "WARNING: Creating rsc_location constraint '%s'" - " with a score of -INFINITY for resource %s" - " on %s.\n", - ID(dont_run), rsc_id, existing_node); - CMD_ERR("\tThis will prevent %s from running" - " on %s until the constraint is removed using" - " the 'crm_resource -U' command or manually" - " with cibadmin\n", rsc_id, existing_node); - CMD_ERR("\tThis will be the case even if %s is" - " the last node in the cluster\n", existing_node); - CMD_ERR("\tThis message can be disabled with -Q\n"); - } + } else { + if(BE_QUIET == FALSE) { + fprintf(stderr, + "WARNING: Creating rsc_location constraint '%s'" + " with a score of -INFINITY for resource %s" + " on %s.\n", + ID(dont_run), rsc_id, existing_node); + CMD_ERR("\tThis will prevent %s from running" + " on %s until the constraint is removed using" + " the 'crm_resource -U' command or manually" + " with cibadmin\n", rsc_id, existing_node); + CMD_ERR("\tThis will be the case even if %s is" + " the last node in the cluster\n", existing_node); + CMD_ERR("\tThis message can be disabled with -Q\n"); + } - crm_xml_add(dont_run, "rsc", rsc_id); + crm_xml_add(dont_run, "rsc", rsc_id); - rule = create_xml_node(dont_run, XML_TAG_RULE); - expr = create_xml_node(rule, XML_TAG_EXPRESSION); - id = crm_concat("cli-standby-rule", rsc_id, '-'); - crm_xml_add(rule, XML_ATTR_ID, id); - crm_free(id); + rule = create_xml_node(dont_run, XML_TAG_RULE); + expr = create_xml_node(rule, XML_TAG_EXPRESSION); + id = crm_concat("cli-standby-rule", rsc_id, '-'); + crm_xml_add(rule, XML_ATTR_ID, id); + crm_free(id); - crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); - crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); + crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); + crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); - id = crm_concat("cli-standby-expr", rsc_id, '-'); - crm_xml_add(expr, XML_ATTR_ID, id); - crm_free(id); + id = crm_concat("cli-standby-expr", rsc_id, '-'); + crm_xml_add(expr, XML_ATTR_ID, id); + crm_free(id); - crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); - crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); - crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node); - crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); - - if(later_s) { - expr = create_xml_node(rule, "date_expression"); - id = crm_concat("cli-standby-lifetime-end",rsc_id,'-'); - crm_xml_add(expr, XML_ATTR_ID, id); - crm_free(id); + crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); + crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); + crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node); + crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); + + if(later_s) { + expr = create_xml_node(rule, "date_expression"); + id = crm_concat("cli-standby-lifetime-end",rsc_id,'-'); + crm_xml_add(expr, XML_ATTR_ID, id); + crm_free(id); - crm_xml_add(expr, "operation", "lt"); - crm_xml_add(expr, "end", later_s); - } - - add_node_copy(constraints, dont_run); + crm_xml_add(expr, "operation", "lt"); + crm_xml_add(expr, "end", later_s); } + + add_node_copy(constraints, dont_run); + } - if(preferred_node == NULL) { - crm_log_xml_notice(can_run, "Deleting"); - rc = cib_conn->cmds->delete( - cib_conn, XML_CIB_TAG_CONSTRAINTS, can_run, cib_options); - if(rc == cib_NOTEXISTS) { - rc = cib_ok; + if(preferred_node == NULL) { + crm_log_xml_notice(can_run, "Deleting"); + rc = cib_conn->cmds->delete( + cib_conn, XML_CIB_TAG_CONSTRAINTS, can_run, cib_options); + if(rc == cib_NOTEXISTS) { + rc = cib_ok; - } else if(rc != cib_ok) { - goto bail; - } + } else if(rc != cib_ok) { + goto bail; + } - } else { - crm_xml_add(can_run, "rsc", rsc_id); + } else { + crm_xml_add(can_run, "rsc", rsc_id); - rule = create_xml_node(can_run, XML_TAG_RULE); - expr = create_xml_node(rule, XML_TAG_EXPRESSION); - id = crm_concat("cli-prefer-rule", rsc_id, '-'); - crm_xml_add(rule, XML_ATTR_ID, id); - crm_free(id); + rule = create_xml_node(can_run, XML_TAG_RULE); + expr = create_xml_node(rule, XML_TAG_EXPRESSION); + id = crm_concat("cli-prefer-rule", rsc_id, '-'); + crm_xml_add(rule, XML_ATTR_ID, id); + crm_free(id); - crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); - crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); + crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); + crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); - id = crm_concat("cli-prefer-expr", rsc_id, '-'); - crm_xml_add(expr, XML_ATTR_ID, id); - crm_free(id); - - crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); - crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); - crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node); - crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); - - if(later_s) { - expr = create_xml_node(rule, "date_expression"); - id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-'); - crm_xml_add(expr, XML_ATTR_ID, id); - crm_free(id); + id = crm_concat("cli-prefer-expr", rsc_id, '-'); + crm_xml_add(expr, XML_ATTR_ID, id); + crm_free(id); + + crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); + crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); + crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node); + crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); + + if(later_s) { + expr = create_xml_node(rule, "date_expression"); + id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-'); + crm_xml_add(expr, XML_ATTR_ID, id); + crm_free(id); - crm_xml_add(expr, "operation", "lt"); - crm_xml_add(expr, "end", later_s); - } - - add_node_copy(constraints, can_run); + crm_xml_add(expr, "operation", "lt"); + crm_xml_add(expr, "end", later_s); } + + add_node_copy(constraints, can_run); + } - if(preferred_node != NULL || existing_node != NULL) { - crm_log_xml_notice(fragment, "CLI Update"); - rc = cib_conn->cmds->update( - cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options); - } + if(preferred_node != NULL || existing_node != NULL) { + crm_log_xml_notice(fragment, "CLI Update"); + rc = cib_conn->cmds->update( + cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options); + } bail: - free_xml(fragment); - free_xml(dont_run); - free_xml(can_run); - crm_free(later_s); - return rc; + free_xml(fragment); + free_xml(dont_run); + free_xml(can_run); + crm_free(later_s); + return rc; } static int list_resource_operations( const char *rsc_id, const char *host_uname, gboolean active, pe_working_set_t *data_set) { resource_t *rsc = NULL; int opts = pe_print_printf|pe_print_rsconly|pe_print_suppres_nl; GListPtr ops = find_operations(rsc_id, host_uname, active, data_set); - slist_iter(xml_op, xmlNode, ops, lpc, - const char *op_rsc = crm_element_value(xml_op, "resource"); - const char *last = crm_element_value(xml_op, "last_run"); - const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); - int status = crm_parse_int(status_s, "0"); - - rsc = pe_find_resource(data_set->resources, op_rsc); - rsc->fns->print(rsc, "", opts, stdout); + GListPtr lpc = NULL; + for(lpc = ops; lpc != NULL; lpc = lpc->next) { + xmlNode *xml_op = (xmlNode*)lpc->data; + + const char *op_rsc = crm_element_value(xml_op, "resource"); + const char *last = crm_element_value(xml_op, "last_run"); + const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); + int status = crm_parse_int(status_s, "0"); + + rsc = pe_find_resource(data_set->resources, op_rsc); + rsc->fns->print(rsc, "", opts, stdout); - fprintf(stdout, ": %s (node=%s, call=%s, rc=%s", - ID(xml_op), - crm_element_value(xml_op, XML_ATTR_UNAME), - crm_element_value(xml_op, XML_LRM_ATTR_CALLID), - crm_element_value(xml_op, XML_LRM_ATTR_RC)); - if(last) { - time_t run_at = crm_parse_int(last, "0"); - fprintf(stdout, ", last-run=%s, exec=%sms\n", - ctime(&run_at), crm_element_value(xml_op, "exec_time")); - } - fprintf(stdout, "): %s\n", op_status2text(status)); - ); + fprintf(stdout, ": %s (node=%s, call=%s, rc=%s", + ID(xml_op), + crm_element_value(xml_op, XML_ATTR_UNAME), + crm_element_value(xml_op, XML_LRM_ATTR_CALLID), + crm_element_value(xml_op, XML_LRM_ATTR_RC)); + if(last) { + time_t run_at = crm_parse_int(last, "0"); + fprintf(stdout, ", last-run=%s, exec=%sms\n", + ctime(&run_at), crm_element_value(xml_op, "exec_time")); + } + fprintf(stdout, "): %s\n", op_status2text(status)); + } return cib_ok; } #include "../pengine/pengine.h" static void show_location(resource_t *rsc, const char *prefix) { + GListPtr lpc = NULL; GListPtr list = rsc->rsc_location; int offset = 0; if(prefix) { offset = strlen(prefix) - 2; } - slist_iter(cons, rsc_to_node_t, list, lpc, - slist_iter(node, node_t, cons->node_list_rh, lpc2, - char *score = score2char(node->weight); - fprintf(stdout, "%s: Node %-*s (score=%s, id=%s)\n", - prefix?prefix:" ", 71-offset, node->details->uname, score, cons->id); - crm_free(score); - ); - ); + for(lpc = list; lpc != NULL; lpc = lpc->next) { + rsc_to_node_t *cons = (rsc_to_node_t*)lpc->data; + + GListPtr lpc2 = NULL; + for(lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) { + node_t *node = (node_t*)lpc2->data; + char *score = score2char(node->weight); + fprintf(stdout, "%s: Node %-*s (score=%s, id=%s)\n", + prefix?prefix:" ", 71-offset, node->details->uname, score, cons->id); + crm_free(score); + } + } } static void show_colocation(resource_t *rsc, gboolean dependants, gboolean recursive, int offset) { char *prefix = NULL; + GListPtr lpc = NULL; GListPtr list = rsc->rsc_cons; crm_malloc0(prefix, (offset*4) + 1); memset(prefix, ' ', offset*4); if(dependants) { - list = rsc->rsc_cons_lhs; + list = rsc->rsc_cons_lhs; } if(is_set(rsc->flags, pe_rsc_allocating)) { /* Break colocation loops */ printf("loop %s\n", rsc->id); return; } set_bit(rsc->flags, pe_rsc_allocating); - slist_iter(cons, rsc_colocation_t, list, lpc, - char *score = NULL; - resource_t *peer = cons->rsc_rh; + for(lpc = list; lpc != NULL; lpc = lpc->next) { + rsc_colocation_t *cons = (rsc_colocation_t*)lpc->data; + + char *score = NULL; + resource_t *peer = cons->rsc_rh; - if(dependants) { - peer = cons->rsc_lh; - } + if(dependants) { + peer = cons->rsc_lh; + } - if(is_set(peer->flags, pe_rsc_allocating)) { - if(dependants == FALSE) { - fprintf(stdout, "%s%-*s (id=%s - loop)\n", prefix, 80-(4*offset), peer->id, cons->id); - } - continue; - } + if(is_set(peer->flags, pe_rsc_allocating)) { + if(dependants == FALSE) { + fprintf(stdout, "%s%-*s (id=%s - loop)\n", prefix, 80-(4*offset), peer->id, cons->id); + } + continue; + } - if(dependants && recursive) { - show_colocation(peer, dependants, recursive, offset+1); - } + if(dependants && recursive) { + show_colocation(peer, dependants, recursive, offset+1); + } - score = score2char(cons->score); - if(cons->role_rh > RSC_ROLE_STARTED) { - fprintf(stdout, "%s%-*s (score=%s, %s role=%s, id=%s)\n", prefix, 80-(4*offset), - peer->id, score, dependants?"needs":"with", role2text(cons->role_rh), cons->id); - } else { - fprintf(stdout, "%s%-*s (score=%s, id=%s)\n", prefix, 80-(4*offset), - peer->id, score, cons->id); - } - show_location(peer, prefix); - crm_free(score); + score = score2char(cons->score); + if(cons->role_rh > RSC_ROLE_STARTED) { + fprintf(stdout, "%s%-*s (score=%s, %s role=%s, id=%s)\n", prefix, 80-(4*offset), + peer->id, score, dependants?"needs":"with", role2text(cons->role_rh), cons->id); + } else { + fprintf(stdout, "%s%-*s (score=%s, id=%s)\n", prefix, 80-(4*offset), + peer->id, score, cons->id); + } + show_location(peer, prefix); + crm_free(score); - if(!dependants && recursive) { - show_colocation(peer, dependants, recursive, offset+1); - } - ); + if(!dependants && recursive) { + show_colocation(peer, dependants, recursive, offset+1); + } + } crm_free(prefix); } static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\t\tThis text"}, {"version", 0, 0, '$', "\t\tVersion information" }, {"verbose", 0, 0, 'V', "\t\tIncrease debug output"}, {"quiet", 0, 0, 'Q', "\t\tPrint only the value on stdout\n"}, {"resource", 1, 0, 'r', "\tResource ID" }, {"-spacer-",1, 0, '-', "\nQueries:"}, {"list", 0, 0, 'L', "\t\tList all resources"}, {"list-raw", 0, 0, 'l', "\tList the IDs of all instantiated resources (no groups/clones/...)"}, {"list-cts", 0, 0, 'c', NULL, 1}, {"list-operations", 0, 0, 'O', "\tList active resource operations. Optionally filtered by resource (-r) and/or node (-N)"}, {"list-all-operations", 0, 0, 'o', "List all resource operations. Optionally filtered by resource (-r) and/or node (-N)\n"}, {"query-xml", 0, 0, 'q', "\tQuery the definition of a resource"}, {"locate", 0, 0, 'W', "\t\tDisplay the current location(s) of a resource"}, {"stack", 0, 0, 'A', "\t\tDisplay the prerequisites and dependents of a resource"}, {"constraints",0, 0, 'a', "\tDisplay the (co)location constraints that apply to a resource"}, {"-spacer-", 1, 0, '-', "\nCommands:"}, {"set-parameter", 1, 0, 'p', "Set the named parameter for a resource. See also -m, --meta"}, {"get-parameter", 1, 0, 'g', "Display the named parameter for a resource. See also -m, --meta"}, {"delete-parameter",1, 0, 'd', "Delete the named parameter for a resource. See also -m, --meta"}, {"get-property", 1, 0, 'G', "Display the 'class', 'type' or 'provider' of a resource", 1}, {"set-property", 1, 0, 'S', "(Advanced) Set the class, type or provider of a resource", 1}, {"move", 0, 0, 'M', "\t\tMove a resource from its current location, optionally specifying a destination (-N) and/or a period for which it should take effect (-u)" "\n\t\t\t\tIf -N is not specified, the cluster will force the resource to move by creating a rule for the current location and a score of -INFINITY" "\n\t\t\t\tNOTE: This will prevent the resource from running on this node until the constraint is removed with -U"}, {"un-move", 0, 0, 'U', "\tRemove all constraints created by a move command"}, {"-spacer-", 1, 0, '-', "\nAdvanced Commands:"}, {"delete", 0, 0, 'D', "\t\tDelete a resource from the CIB"}, {"fail", 0, 0, 'F', "\t\tTell the cluster this resource has failed"}, {"refresh", 0, 0, 'R', "\t\t(Advanced) Refresh the CIB from the LRM"}, {"cleanup", 0, 0, 'C', "\t\t(Advanced) Delete a resource from the LRM"}, {"reprobe", 0, 0, 'P', "\t\t(Advanced) Re-check for resources started outside of the CRM\n"}, {"-spacer-", 1, 0, '-', "\nAdditional Options:"}, {"node", 1, 0, 'N', "\tHost uname"}, {"resource-type", 1, 0, 't', "Resource type (primitive, clone, group, ...)"}, {"parameter-value", 1, 0, 'v', "Value to use with -p, -g or -d"}, {"lifetime", 1, 0, 'u', "\tLifespan of migration constraints\n"}, {"meta", 0, 0, 'm', "\t\tModify a resource's configuration option rather than one which is passed to the resource agent script. For use with -p, -g, -d"}, {"utilization", 0, 0, 'z', "\tModify a resource's utilization attribute. For use with -p, -g, -d"}, {"set-name", 1, 0, 's', "\t(Advanced) ID of the instance_attributes object to change"}, {"nvpair", 1, 0, 'i', "\t(Advanced) ID of the nvpair object to change/delete"}, {"force", 0, 0, 'f', "\n" /* Is this actually true anymore? - "\t\tForce the resource to move by creating a rule for the current location and a score of -INFINITY" - "\n\t\tThis should be used if the resource's stickiness and constraint scores total more than INFINITY (Currently 100,000)" - "\n\t\tNOTE: This will prevent the resource from running on this node until the constraint is removed with -U or the --lifetime duration expires\n"*/ }, + "\t\tForce the resource to move by creating a rule for the current location and a score of -INFINITY" + "\n\t\tThis should be used if the resource's stickiness and constraint scores total more than INFINITY (Currently 100,000)" + "\n\t\tNOTE: This will prevent the resource from running on this node until the constraint is removed with -U or the --lifetime duration expires\n"*/ }, {"xml-file", 1, 0, 'x', NULL, 1},\ - /* legacy options */ + /* legacy options */ {"host-uname", 1, 0, 'H', NULL, 1}, {"migrate", 0, 0, 'M', NULL, 1}, {"un-migrate", 0, 0, 'U', NULL, 1}, {"-spacer-", 1, 0, '-', "\nExamples:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', "List the configured resources:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --list", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Display the current location of 'myResource':", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --locate", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Move 'myResource' to another machine:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Move 'myResource' to a specific machine:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move --node altNode", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Allow (but not force) 'myResource' to move back to its original location:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --un-move", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Tell the cluster that 'myResource' failed:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --fail", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Stop a 'myResource' (and anything that depends on it):", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --set-parameter target-role --meta --parameter-value Stopped", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Tell the cluster not to manage 'myResource':", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', "The cluster will not attempt to start or stop the resource under any circumstances."}, {"-spacer-", 1, 0, '-', "Useful when performing maintenance tasks on a resource.", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --set-parameter is-managed --meta --parameter-value false", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Erase the operation history of 'myResource' on 'aNode':", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', "The cluster will 'forget' the existing resource state (including any errors) and attempt to recover the resource."}, {"-spacer-", 1, 0, '-', "Useful when a resource had failed permanently and has been repaired by an administrator.", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --cleanup --node aNode", pcmk_option_example}, {0, 0, 0, 0} }; int main(int argc, char **argv) { - pe_working_set_t data_set; - xmlNode *cib_xml_copy = NULL; + pe_working_set_t data_set; + xmlNode *cib_xml_copy = NULL; - cib_t * cib_conn = NULL; - enum cib_errors rc = cib_ok; + cib_t * cib_conn = NULL; + enum cib_errors rc = cib_ok; - gboolean need_cib = TRUE; - int option_index = 0; - int argerr = 0; - int flag; + gboolean need_cib = TRUE; + int option_index = 0; + int argerr = 0; + int flag; - crm_log_init(NULL, LOG_ERR, FALSE, FALSE, argc, argv); - crm_set_options("V?$LRQDCPp:WMUr:H:h:v:t:p:g:d:i:s:G:S:fx:lmzu:FOocqN:aA", "(query|command) [options]", long_options, - "Perform tasks related to cluster resources.\n Allows resources to be queried (definition and location), modified, and moved around the cluster.\n"); + crm_log_init(NULL, LOG_ERR, FALSE, FALSE, argc, argv); + crm_set_options("V?$LRQDCPp:WMUr:H:h:v:t:p:g:d:i:s:G:S:fx:lmzu:FOocqN:aA", "(query|command) [options]", long_options, + "Perform tasks related to cluster resources.\n Allows resources to be queried (definition and location), modified, and moved around the cluster.\n"); - if(argc < 2) { - crm_help('?', LSB_EXIT_EINVAL); - } + if(argc < 2) { + crm_help('?', LSB_EXIT_EINVAL); + } - while (1) { - flag = crm_get_option(argc, argv, &option_index); - if (flag == -1) - break; + while (1) { + flag = crm_get_option(argc, argv, &option_index); + if (flag == -1) + break; - switch(flag) { - case 'V': - cl_log_enable_stderr(TRUE); - alter_debug(DEBUG_INC); - break; - case '$': - case '?': - crm_help(flag, LSB_EXIT_OK); - break; - case 'x': - xml_file = crm_strdup(optarg); - break; - case 'Q': - BE_QUIET = TRUE; - break; - case 'm': - attr_set_type = XML_TAG_META_SETS; - break; - case 'z': - attr_set_type = XML_TAG_UTILIZATION; - break; - case 'u': - move_lifetime = crm_strdup(optarg); - break; - case 'f': - do_force = TRUE; - break; - case 'i': - prop_id = optarg; - break; - case 's': - prop_set = optarg; - break; - case 'r': - rsc_id = optarg; - break; - case 'v': - prop_value = optarg; - break; - case 't': - rsc_type = optarg; - break; - case 'R': - case 'P': - need_cib = FALSE; - rsc_cmd = flag; - break; - case 'L': - case 'c': - case 'l': - case 'q': - case 'D': - case 'F': - case 'C': - case 'W': - case 'M': - case 'U': - case 'O': - case 'o': - case 'A': - case 'a': - rsc_cmd = flag; - break; - case 'p': - case 'g': - case 'd': - case 'S': - case 'G': - prop_name = optarg; - rsc_cmd = flag; - break; - case 'h': - case 'H': - case 'N': - crm_debug_2("Option %c => %s", flag, optarg); - host_uname = optarg; - break; + switch(flag) { + case 'V': + cl_log_enable_stderr(TRUE); + alter_debug(DEBUG_INC); + break; + case '$': + case '?': + crm_help(flag, LSB_EXIT_OK); + break; + case 'x': + xml_file = crm_strdup(optarg); + break; + case 'Q': + BE_QUIET = TRUE; + break; + case 'm': + attr_set_type = XML_TAG_META_SETS; + break; + case 'z': + attr_set_type = XML_TAG_UTILIZATION; + break; + case 'u': + move_lifetime = crm_strdup(optarg); + break; + case 'f': + do_force = TRUE; + break; + case 'i': + prop_id = optarg; + break; + case 's': + prop_set = optarg; + break; + case 'r': + rsc_id = optarg; + break; + case 'v': + prop_value = optarg; + break; + case 't': + rsc_type = optarg; + break; + case 'R': + case 'P': + need_cib = FALSE; + rsc_cmd = flag; + break; + case 'L': + case 'c': + case 'l': + case 'q': + case 'D': + case 'F': + case 'C': + case 'W': + case 'M': + case 'U': + case 'O': + case 'o': + case 'A': + case 'a': + rsc_cmd = flag; + break; + case 'p': + case 'g': + case 'd': + case 'S': + case 'G': + prop_name = optarg; + rsc_cmd = flag; + break; + case 'h': + case 'H': + case 'N': + crm_debug_2("Option %c => %s", flag, optarg); + host_uname = optarg; + break; - default: - CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); - ++argerr; - break; - } + default: + CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); + ++argerr; + break; } + } - if (optind < argc && argv[optind] != NULL) { - CMD_ERR("non-option ARGV-elements: "); - while (optind < argc && argv[optind] != NULL) { - CMD_ERR("%s ", argv[optind++]); - ++argerr; - } - CMD_ERR("\n"); + if (optind < argc && argv[optind] != NULL) { + CMD_ERR("non-option ARGV-elements: "); + while (optind < argc && argv[optind] != NULL) { + CMD_ERR("%s ", argv[optind++]); + ++argerr; } + CMD_ERR("\n"); + } - if (optind > argc) { - ++argerr; - } + if (optind > argc) { + ++argerr; + } - if (argerr) { - crm_help('?', LSB_EXIT_GENERIC); - } + if (argerr) { + crm_help('?', LSB_EXIT_GENERIC); + } - crm_malloc0(our_pid, 11); - if(our_pid != NULL) { - snprintf(our_pid, 10, "%d", getpid()); - our_pid[10] = '\0'; - } + crm_malloc0(our_pid, 11); + if(our_pid != NULL) { + snprintf(our_pid, 10, "%d", getpid()); + our_pid[10] = '\0'; + } - if(do_force) { - crm_debug("Forcing..."); - cib_options |= cib_scope_local|cib_quorum_override; - } + if(do_force) { + crm_debug("Forcing..."); + cib_options |= cib_scope_local|cib_quorum_override; + } + + set_working_set_defaults(&data_set); + if(need_cib) { + resource_t *rsc = NULL; + if(xml_file != NULL) { + cib_xml_copy = filename2xml(xml_file); + + } else { + cib_conn = cib_new(); + rc = cib_conn->cmds->signon( + cib_conn, crm_system_name, cib_command); + if(rc != cib_ok) { + CMD_ERR("Error signing on to the CIB service: %s\n", + cib_error2string(rc)); + return rc; + } - set_working_set_defaults(&data_set); - if(need_cib) { - resource_t *rsc = NULL; - if(xml_file != NULL) { - cib_xml_copy = filename2xml(xml_file); - - } else { - cib_conn = cib_new(); - rc = cib_conn->cmds->signon( - cib_conn, crm_system_name, cib_command); - if(rc != cib_ok) { - CMD_ERR("Error signing on to the CIB service: %s\n", - cib_error2string(rc)); - return rc; - } - - cib_xml_copy = get_cib_copy(cib_conn); - } + cib_xml_copy = get_cib_copy(cib_conn); + } - if(cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) { - rc = cib_STALE; - goto bail; - } - - data_set.input = cib_xml_copy; - data_set.now = new_ha_date(TRUE); - - cluster_status(&data_set); - if(rsc_id) { - rsc = find_rsc_or_clone(rsc_id, &data_set); - } - if(rsc == NULL) { - rc = cib_NOTEXISTS; - } + if(cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) { + rc = cib_STALE; + goto bail; } - if(rsc_cmd == 'R' - || rsc_cmd == 'C' - || rsc_cmd == 'F' - || rsc_cmd == 'P') { - GCHSource *src = NULL; - src = init_client_ipc_comms(CRM_SYSTEM_CRMD, resource_ipc_callback, - NULL, &crmd_channel); - - if(src == NULL) { - CMD_ERR("Error signing on to the CRMd service\n"); - rc = cib_connection; - goto bail; - } - - send_hello_message( - crmd_channel, our_pid, crm_system_name, "0", "1"); + data_set.input = cib_xml_copy; + data_set.now = new_ha_date(TRUE); - set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy); + cluster_status(&data_set); + if(rsc_id) { + rsc = find_rsc_or_clone(rsc_id, &data_set); } + if(rsc == NULL) { + rc = cib_NOTEXISTS; + } + } - if(rsc_cmd == 'L') { - rc = cib_ok; - do_find_resource_list(&data_set, FALSE); + if(rsc_cmd == 'R' + || rsc_cmd == 'C' + || rsc_cmd == 'F' + || rsc_cmd == 'P') { + GCHSource *src = NULL; + src = init_client_ipc_comms(CRM_SYSTEM_CRMD, resource_ipc_callback, + NULL, &crmd_channel); + + if(src == NULL) { + CMD_ERR("Error signing on to the CRMd service\n"); + rc = cib_connection; + goto bail; + } - } else if(rsc_cmd == 'l') { - int found = 0; - rc = cib_ok; - slist_iter( - rsc, resource_t, data_set.resources, lpc, - found++; - print_raw_rsc(rsc); - ); + send_hello_message( + crmd_channel, our_pid, crm_system_name, "0", "1"); + + set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy); + } + + if(rsc_cmd == 'L') { + rc = cib_ok; + do_find_resource_list(&data_set, FALSE); + + } else if(rsc_cmd == 'l') { + int found = 0; + GListPtr lpc = NULL; + rc = cib_ok; + for(lpc = data_set.resources; lpc != NULL; lpc = lpc->next) { + resource_t *rsc = (resource_t*)lpc->data; - if(found == 0) { - printf("NO resources configured\n"); - rc = cib_NOTEXISTS; - goto bail; - } + found++; + print_raw_rsc(rsc); + } + + if(found == 0) { + printf("NO resources configured\n"); + rc = cib_NOTEXISTS; + goto bail; + } - } else if(rsc_cmd == 'A' || rsc_cmd == 'a') { - resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); - xmlNode * cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set.input); - if(rsc == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } + } else if(rsc_cmd == 'A' || rsc_cmd == 'a') { + GListPtr lpc = NULL; + resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); + xmlNode * cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set.input); + if(rsc == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } - unpack_constraints(cib_constraints, &data_set); + unpack_constraints(cib_constraints, &data_set); - slist_iter(r, resource_t, data_set.resources, lpc, - clear_bit(r->flags, pe_rsc_allocating)); - show_colocation(rsc, TRUE, rsc_cmd=='A', 1); + for(lpc = data_set.resources; lpc != NULL; lpc = lpc->next) { + resource_t *r = (resource_t*)lpc->data; + clear_bit(r->flags, pe_rsc_allocating); + } + + show_colocation(rsc, TRUE, rsc_cmd=='A', 1); - fprintf(stdout, "* %s\n", rsc->id); - show_location(rsc, NULL); + fprintf(stdout, "* %s\n", rsc->id); + show_location(rsc, NULL); - slist_iter(r, resource_t, data_set.resources, lpc, - clear_bit(r->flags, pe_rsc_allocating)); - show_colocation(rsc, FALSE, rsc_cmd=='A', 1); + for(lpc = data_set.resources; lpc != NULL; lpc = lpc->next) { + resource_t *r = (resource_t*)lpc->data; + clear_bit(r->flags, pe_rsc_allocating); + } - } else if(rsc_cmd == 'c') { - int found = 0; - rc = cib_ok; - slist_iter( - rsc, resource_t, data_set.resources, lpc, - found++; - print_cts_rsc(rsc); - ); - print_cts_constraints(&data_set); + show_colocation(rsc, FALSE, rsc_cmd=='A', 1); + + } else if(rsc_cmd == 'c') { + int found = 0; + GListPtr lpc = NULL; + rc = cib_ok; + for(lpc = data_set.resources; lpc != NULL; lpc = lpc->next) { + resource_t *rsc = (resource_t*)lpc->data; + print_cts_rsc(rsc); + found++; + } + print_cts_constraints(&data_set); - } else if(rsc_cmd == 'C') { - resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); - rc = delete_lrm_rsc(crmd_channel, host_uname, rsc, &data_set); - if(rc == cib_ok) { - start_mainloop(); - } + } else if(rsc_cmd == 'C') { + resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); + rc = delete_lrm_rsc(crmd_channel, host_uname, rsc, &data_set); + if(rc == cib_ok) { + start_mainloop(); + } - } else if(rsc_cmd == 'F') { - rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); - if(rc == cib_ok) { - start_mainloop(); - } + } else if(rsc_cmd == 'F') { + rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); + if(rc == cib_ok) { + start_mainloop(); + } - } else if(rsc_cmd == 'O') { - rc = list_resource_operations(rsc_id, host_uname, TRUE, &data_set); + } else if(rsc_cmd == 'O') { + rc = list_resource_operations(rsc_id, host_uname, TRUE, &data_set); - } else if(rsc_cmd == 'o') { - rc = list_resource_operations(rsc_id, host_uname, FALSE, &data_set); + } else if(rsc_cmd == 'o') { + rc = list_resource_operations(rsc_id, host_uname, FALSE, &data_set); - } else if(rc == cib_NOTEXISTS) { - CMD_ERR("Resource %s not found: %s\n", - crm_str(rsc_id), cib_error2string(rc)); - - } else if(rsc_cmd == 'W') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = do_find_resource(rsc_id, &data_set); + } else if(rc == cib_NOTEXISTS) { + CMD_ERR("Resource %s not found: %s\n", + crm_str(rsc_id), cib_error2string(rc)); + + } else if(rsc_cmd == 'W') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = do_find_resource(rsc_id, &data_set); - } else if(rsc_cmd == 'q') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = dump_resource(rsc_id, &data_set); - - } else if(rsc_cmd == 'U') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = move_resource(rsc_id, NULL, NULL, cib_conn); - - } else if(rsc_cmd == 'M') { - node_t *dest = NULL; - node_t *current = NULL; - const char *current_uname = NULL; - resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); - if(rsc != NULL && rsc->running_on != NULL) { - current = rsc->running_on->data; - if(current != NULL) { - current_uname = current->details->uname; - } - } - - if(host_uname != NULL) { - dest = pe_find_node(data_set.nodes, host_uname); - } + } else if(rsc_cmd == 'q') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = dump_resource(rsc_id, &data_set); + + } else if(rsc_cmd == 'U') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = move_resource(rsc_id, NULL, NULL, cib_conn); + + } else if(rsc_cmd == 'M') { + node_t *dest = NULL; + node_t *current = NULL; + const char *current_uname = NULL; + resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); + if(rsc != NULL && rsc->running_on != NULL) { + current = rsc->running_on->data; + if(current != NULL) { + current_uname = current->details->uname; + } + } + + if(host_uname != NULL) { + dest = pe_find_node(data_set.nodes, host_uname); + } - if(rsc == NULL) { - CMD_ERR("Resource %s not moved:" - " not found\n", rsc_id); - - } else if(rsc->variant == pe_native - && g_list_length(rsc->running_on) > 1) { - CMD_ERR("Resource %s not moved:" - " active on multiple nodes\n", rsc_id); + if(rsc == NULL) { + CMD_ERR("Resource %s not moved:" + " not found\n", rsc_id); + + } else if(rsc->variant == pe_native + && g_list_length(rsc->running_on) > 1) { + CMD_ERR("Resource %s not moved:" + " active on multiple nodes\n", rsc_id); - } else if(host_uname != NULL && dest == NULL) { - CMD_ERR("Error performing operation: " - "%s is not a known node\n", host_uname); - rc = cib_NOTEXISTS; - - } else if(host_uname != NULL - && safe_str_eq(current_uname, host_uname)) { - CMD_ERR("Error performing operation: " - "%s is already active on %s\n", - rsc_id, host_uname); - - } else if(current_uname != NULL - && (do_force || host_uname == NULL)) { - rc = move_resource(rsc_id, current_uname, - host_uname, cib_conn); + } else if(host_uname != NULL && dest == NULL) { + CMD_ERR("Error performing operation: " + "%s is not a known node\n", host_uname); + rc = cib_NOTEXISTS; + + } else if(host_uname != NULL + && safe_str_eq(current_uname, host_uname)) { + CMD_ERR("Error performing operation: " + "%s is already active on %s\n", + rsc_id, host_uname); + + } else if(current_uname != NULL + && (do_force || host_uname == NULL)) { + rc = move_resource(rsc_id, current_uname, + host_uname, cib_conn); - } else if(host_uname != NULL) { - rc = move_resource( - rsc_id, NULL, host_uname, cib_conn); - - } else { - CMD_ERR("Resource %s not moved: " - "not-active and no preferred location" - " specified.\n", rsc_id); - rc = cib_missing; - } - - } else if(rsc_cmd == 'G') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = dump_resource_prop(rsc_id, prop_name, &data_set); - - } else if(rsc_cmd == 'S') { - xmlNode *msg_data = NULL; - if(prop_value == NULL || strlen(prop_value) == 0) { - CMD_ERR("You need to supply a value with the -v option\n"); - rc = CIBRES_MISSING_FIELD; - goto bail; - - } else if(cib_conn == NULL) { - rc = cib_connection; - goto bail; - } - - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - CRM_LOG_ASSERT(rsc_type != NULL); - CRM_LOG_ASSERT(prop_name != NULL); - CRM_LOG_ASSERT(prop_value != NULL); - - msg_data = create_xml_node(NULL, rsc_type); - crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); - crm_xml_add(msg_data, prop_name, prop_value); + } else if(host_uname != NULL) { + rc = move_resource( + rsc_id, NULL, host_uname, cib_conn); + + } else { + CMD_ERR("Resource %s not moved: " + "not-active and no preferred location" + " specified.\n", rsc_id); + rc = cib_missing; + } - rc = cib_conn->cmds->modify( - cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options); - free_xml(msg_data); - - } else if(rsc_cmd == 'g') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = dump_resource_attr(rsc_id, prop_name, &data_set); - - } else if(rsc_cmd == 'p') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - if(prop_value == NULL || strlen(prop_value) == 0) { - CMD_ERR("You need to supply a value with the -v option\n"); - rc = CIBRES_MISSING_FIELD; - goto bail; - } - rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name, - prop_value, cib_conn, &data_set); - - } else if(rsc_cmd == 'd') { - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; - } - rc = delete_resource_attr(rsc_id, prop_set, prop_id, prop_name, - cib_conn, &data_set); - - } else if(rsc_cmd == 'P') { - xmlNode *cmd = NULL; + } else if(rsc_cmd == 'G') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = dump_resource_prop(rsc_id, prop_name, &data_set); + + } else if(rsc_cmd == 'S') { + xmlNode *msg_data = NULL; + if(prop_value == NULL || strlen(prop_value) == 0) { + CMD_ERR("You need to supply a value with the -v option\n"); + rc = CIBRES_MISSING_FIELD; + goto bail; + + } else if(cib_conn == NULL) { + rc = cib_connection; + goto bail; + } + + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + CRM_LOG_ASSERT(rsc_type != NULL); + CRM_LOG_ASSERT(prop_name != NULL); + CRM_LOG_ASSERT(prop_value != NULL); + + msg_data = create_xml_node(NULL, rsc_type); + crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); + crm_xml_add(msg_data, prop_name, prop_value); - cmd = create_request(CRM_OP_REPROBE, NULL, host_uname, - CRM_SYSTEM_CRMD, crm_system_name, our_pid); - if(send_ipc_message(crmd_channel, cmd)) { - start_mainloop(); - } - - free_xml(cmd); - - } else if(rsc_cmd == 'R') { - rc = refresh_lrm(crmd_channel, host_uname); - if(rc == cib_ok) { - start_mainloop(); - } - - } else if(rsc_cmd == 'D') { - xmlNode *msg_data = NULL; + rc = cib_conn->cmds->modify( + cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options); + free_xml(msg_data); + + } else if(rsc_cmd == 'g') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = dump_resource_attr(rsc_id, prop_name, &data_set); + + } else if(rsc_cmd == 'p') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + if(prop_value == NULL || strlen(prop_value) == 0) { + CMD_ERR("You need to supply a value with the -v option\n"); + rc = CIBRES_MISSING_FIELD; + goto bail; + } + rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name, + prop_value, cib_conn, &data_set); + + } else if(rsc_cmd == 'd') { + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; + } + rc = delete_resource_attr(rsc_id, prop_set, prop_id, prop_name, + cib_conn, &data_set); + + } else if(rsc_cmd == 'P') { + xmlNode *cmd = NULL; - if(rsc_id == NULL) { - CMD_ERR("Must supply a resource id with -r\n"); - rc = cib_NOTEXISTS; - goto bail; + cmd = create_request(CRM_OP_REPROBE, NULL, host_uname, + CRM_SYSTEM_CRMD, crm_system_name, our_pid); + if(send_ipc_message(crmd_channel, cmd)) { + start_mainloop(); + } - } - if(rsc_type == NULL) { - CMD_ERR("You need to specify a resource type with -t"); - rc = cib_NOTEXISTS; - goto bail; + free_xml(cmd); - } else if(cib_conn == NULL) { - rc = cib_connection; - goto bail; - } + } else if(rsc_cmd == 'R') { + rc = refresh_lrm(crmd_channel, host_uname); + if(rc == cib_ok) { + start_mainloop(); + } - msg_data = create_xml_node(NULL, rsc_type); - crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); + } else if(rsc_cmd == 'D') { + xmlNode *msg_data = NULL; + + if(rsc_id == NULL) { + CMD_ERR("Must supply a resource id with -r\n"); + rc = cib_NOTEXISTS; + goto bail; - rc = cib_conn->cmds->delete( - cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options); - free_xml(msg_data); + } + if(rsc_type == NULL) { + CMD_ERR("You need to specify a resource type with -t"); + rc = cib_NOTEXISTS; + goto bail; - } else { - CMD_ERR("Unknown command: %c\n", rsc_cmd); + } else if(cib_conn == NULL) { + rc = cib_connection; + goto bail; } + msg_data = create_xml_node(NULL, rsc_type); + crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); + + rc = cib_conn->cmds->delete( + cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options); + free_xml(msg_data); + + } else { + CMD_ERR("Unknown command: %c\n", rsc_cmd); + } + bail: - if(cib_conn != NULL) { - cleanup_alloc_calculations(&data_set); - cib_conn->cmds->signoff(cib_conn); - cib_delete(cib_conn); - } + if(cib_conn != NULL) { + cleanup_alloc_calculations(&data_set); + cib_conn->cmds->signoff(cib_conn); + cib_delete(cib_conn); + } - crm_xml_cleanup(); + crm_xml_cleanup(); - if(rc == cib_no_quorum) { - CMD_ERR("Error performing operation: %s\n", - cib_error2string(rc)); - CMD_ERR("Try using -f\n"); - - } else if(rc != cib_ok) { - CMD_ERR("Error performing operation: %s\n", - cib_error2string(rc)); - } + if(rc == cib_no_quorum) { + CMD_ERR("Error performing operation: %s\n", + cib_error2string(rc)); + CMD_ERR("Try using -f\n"); + + } else if(rc != cib_ok) { + CMD_ERR("Error performing operation: %s\n", + cib_error2string(rc)); + } - return rc; + return rc; } diff --git a/tools/pingd.c b/tools/pingd.c index eed37b6d3c..8cb73ae587 100644 --- a/tools/pingd.c +++ b/tools/pingd.c @@ -1,1404 +1,1404 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SOCKET_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ON_LINUX #include #include # ifndef ICMP_FILTER # define ICMP_FILTER 1 struct icmp_filter { uint32_t data; }; # endif #endif #include #include #include #if SUPPORT_HEARTBEAT # include ll_cluster_t *pingd_cluster = NULL; void do_node_walk(ll_cluster_t *hb_cluster); #endif /* GMainLoop *mainloop = NULL; */ GListPtr ping_list = NULL; GMainLoop* mainloop = NULL; GHashTable *ping_nodes = NULL; const char *pingd_attr = "pingd"; gboolean do_filter = FALSE; gboolean need_shutdown = FALSE; gboolean stand_alone = FALSE; gboolean do_updates = TRUE; const char *attr_set = NULL; const char *attr_section = NULL; int attr_dampen = 5000; /* 5s */ int attr_multiplier = 1; int pings_per_host = 2; int ping_timeout = 2; int re_ping_interval = 1000; /* 1s */ int ident; /* our pid */ unsigned char cmsgbuf[4096]; int cmsglen = 0; typedef struct ping_node_s { int fd; /* ping socket */ uint16_t iseq; /* sequence number */ gboolean type; gboolean extra_filters; union { struct sockaddr raw; struct sockaddr_in v4; /* ipv4 ping addr */ struct sockaddr_in6 v6; /* ipv6 ping addr */ } addr; char dest[256]; char *host; } ping_node; void pingd_nstatus_callback( const char *node, const char *status, void *private_data); void pingd_lstatus_callback( const char *node, const char *link, const char *status, void *private_data); void send_update(int active); int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto); int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto); /* * in_cksum -- * Checksum routine for Internet Protocol family headers (C Version) * This function taken from Mike Muuss' ping program. */ static int in_cksum (u_short *addr, size_t len) { size_t nleft = len; u_short * w = addr; int sum = 0; u_short answer = 0; /* * The IP checksum algorithm is simple: using a 32 bit accumulator (sum) * add sequential 16 bit words to it, and at the end, folding back all * the carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* Mop up an odd byte, if necessary */ if (nleft == 1) { sum += *(u_char*)w; } /* Add back carry bits from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return answer; } static const char *ping_desc(gboolean family, uint8_t type, uint8_t code) { if(family == AF_INET6) { switch(type) { case ICMP6_DST_UNREACH: switch(code) { case ICMP6_DST_UNREACH_NOROUTE: return "No Route to Destination"; case ICMP6_DST_UNREACH_ADMIN: return "Destination Administratively Unreachable"; #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE case ICMP6_DST_UNREACH_BEYONDSCOPE: return "Destination Unreachable Beyond Scope"; #endif case ICMP6_DST_UNREACH_ADDR: return "Destination Address Unreachable"; case ICMP6_DST_UNREACH_NOPORT: return "Destination Port Unreachable"; default: crm_err("Unreachable: Unknown subtype: %d", code); return "Unreachable: Unknown Subtype"; } case ICMP6_PACKET_TOO_BIG: return "Packet too big"; case ICMP6_TIME_EXCEEDED: switch(code) { case ICMP6_TIME_EXCEED_TRANSIT: return "Time to live exceeded"; case ICMP6_TIME_EXCEED_REASSEMBLY: return "Frag reassembly time exceeded"; default: crm_err("Timeout: Unknown subtype: %d", code); return "Timeout: Unknown Subtype"; } case ICMP6_PARAM_PROB: switch(code) { case ICMP6_PARAMPROB_HEADER: return "Parameter problem: Erroneous Header"; case ICMP6_PARAMPROB_NEXTHEADER: return "Parameter problem: Unknown Nextheader"; case ICMP6_PARAMPROB_OPTION: return "Parameter problem: Unrecognized Option"; default: crm_err("Invalid header: Unknown subtype: %d", code); return "Invalid header: Unknown Subtype"; } case ICMP6_ECHO_REQUEST: return "Echo Request"; case ICMP6_ECHO_REPLY: return "Echo Reply"; #ifdef MLD_LISTENER_QUERY case MLD_LISTENER_QUERY: return "Multicast Listener Query"; #endif #ifdef MLD_LISTENER_REPORT case MLD_LISTENER_REPORT: return "Multicast Listener Report"; #endif #ifdef MLD_LISTENER_REDUCTION case MLD_LISTENER_REDUCTION: return "Multicast Listener Done"; #endif case ND_ROUTER_SOLICIT: return "Router Solicitation"; case ND_ROUTER_ADVERT: return "Router Advertisement"; case ND_NEIGHBOR_SOLICIT: return "Neighbor Solicitation"; case ND_NEIGHBOR_ADVERT: return "Neighbor Advertisement"; case ND_REDIRECT: return "Redirect"; #ifdef ICMP6_ROUTER_RENUMBERING case ICMP6_ROUTER_RENUMBERING: return "Router renumbering"; #endif default: crm_err("Unknown type: %d", type); return "Unknown type"; } } else { switch(type) { case ICMP_ECHOREPLY: return "Echo Reply"; case ICMP_ECHO: return "Echo Request"; case ICMP_PARAMPROB: return "Bad Parameter"; case ICMP_SOURCEQUENCH: return "Packet lost, slow down"; case ICMP_TSTAMP: return "Timestamp Request"; case ICMP_TSTAMPREPLY: return "Timestamp Reply"; case ICMP_IREQ: return "Information Request"; case ICMP_IREQREPLY: return "Information Reply"; case ICMP_UNREACH: switch(code) { case ICMP_UNREACH_NET: return "Unreachable Network"; case ICMP_UNREACH_HOST: return "Unreachable Host"; case ICMP_UNREACH_PROTOCOL: return "Unreachable Protocol"; case ICMP_UNREACH_PORT: return "Unreachable Port"; case ICMP_UNREACH_NEEDFRAG: return "Unreachable: Fragmentation needed"; case ICMP_UNREACH_SRCFAIL: return "Unreachable Source Route"; case ICMP_UNREACH_NET_UNKNOWN: return "Unknown Network"; case ICMP_UNREACH_HOST_UNKNOWN: return "Unknown Host"; case ICMP_UNREACH_ISOLATED: return "Unreachable: Isolated"; case ICMP_UNREACH_NET_PROHIB: return "Prohibited network"; case ICMP_UNREACH_HOST_PROHIB: return "Prohibited host"; case ICMP_UNREACH_FILTER_PROHIB: return "Unreachable: Prohibited filter"; case ICMP_UNREACH_TOSNET: return "Unreachable: Type of Service and Network"; case ICMP_UNREACH_TOSHOST: return "Unreachable: Type of Service and Host"; case ICMP_UNREACH_HOST_PRECEDENCE: return "Unreachable: Prec vio"; case ICMP_UNREACH_PRECEDENCE_CUTOFF: return "Unreachable: Prec cutoff"; default: crm_err("Unreachable: Unknown subtype: %d", code); return "Unreachable: Unknown Subtype"; } break; case ICMP_REDIRECT: switch(code) { case ICMP_REDIRECT_NET: return "Redirect: Network"; case ICMP_REDIRECT_HOST: return "Redirect: Host"; case ICMP_REDIRECT_TOSNET: return "Redirect: Type of Service and Network"; case ICMP_REDIRECT_TOSHOST: return "Redirect: Type of Service and Host"; default: crm_err("Redirect: Unknown subtype: %d", code); return "Redirect: Unknown Subtype"; } case ICMP_TIMXCEED: switch(code) { case ICMP_TIMXCEED_INTRANS: return "Timeout: TTL"; case ICMP_TIMXCEED_REASS: return "Timeout: Fragmentation reassembly"; default: crm_err("Timeout: Unknown subtype: %d", code); return "Timeout: Unknown Subtype"; } break; default: crm_err("Unknown type: %d", type); return "Unknown type"; } } } #ifdef ON_LINUX # define MAX_HOST 1024 int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto) { int rc = 0; char buf[512]; struct iovec iov; struct msghdr msg; struct icmp6_hdr icmph; struct sockaddr_in6 target; struct cmsghdr *cmsg = NULL; struct sock_extended_err *s_err = NULL; iov.iov_base = &icmph; iov.iov_len = sizeof(icmph); msg.msg_name = (void*)⌖ msg.msg_namelen = sizeof(target); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buf; msg.msg_controllen = sizeof(buf); rc = recvmsg(node->fd, &msg, MSG_ERRQUEUE|MSG_DONTWAIT); if (rc < 0 || rc < sizeof(icmph)) { crm_perror(LOG_DEBUG, "No error message: %d", rc); return 0; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR) { s_err = (struct sock_extended_err *)CMSG_DATA(cmsg); } } CRM_ASSERT(s_err != NULL); if (s_err->ee_origin == SO_EE_ORIGIN_LOCAL) { if (s_err->ee_errno == EMSGSIZE) { crm_info("local error: Message too long, mtu=%u", s_err->ee_info); } else { crm_info("local error: %s", strerror(s_err->ee_errno)); } return 0; } else if (s_err->ee_origin == SO_EE_ORIGIN_ICMP6) { struct sockaddr_in6 *sin = (struct sockaddr_in6*)(s_err+1); const char *ping_result = ping_desc(node->type, s_err->ee_type, s_err->ee_code); static char target_s[64], whereto_s[64], ping_host_s[64]; inet_ntop(AF_INET6, (struct in6_addr *)&(target.sin6_addr), target_s, sizeof(target_s)); inet_ntop(AF_INET6, (struct in6_addr *)&(whereto->sin6_addr), whereto_s, sizeof(whereto_s)); if (ntohs(icmph.icmp6_id) != ident) { /* Result was not for us */ crm_debug("Not our error (ident): %d %d", ntohs(icmph.icmp6_id), ident); return -1; } else if (memcmp(&target.sin6_addr, &whereto->sin6_addr, 16)) { /* Result was not for us */ crm_debug("Not our error (addr): %s %s", target_s, whereto_s); return -1; } else if (icmph.icmp6_type != ICMP6_ECHO_REQUEST) { /* Not an error */ crm_info("Not an error: %d", icmph.icmp6_type); return -1; } inet_ntop(AF_INET6, (struct in6_addr *)&(sin->sin6_addr), ping_host_s, sizeof(ping_host_s)); crm_debug("From %s icmp_seq=%u %s", ping_host_s, ntohs(icmph.icmp6_seq), ping_result); } else { crm_debug("else: %d", s_err->ee_origin); } return 0; } int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto) { int rc = 0; char buf[512]; struct iovec iov; struct msghdr msg; struct icmphdr icmph; struct sockaddr_in target; struct cmsghdr *cmsg = NULL; struct sock_extended_err *s_err = NULL; iov.iov_base = &icmph; iov.iov_len = sizeof(icmph); msg.msg_name = (void*)⌖ msg.msg_namelen = sizeof(target); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buf; msg.msg_controllen = sizeof(buf); rc = recvmsg(node->fd, &msg, MSG_ERRQUEUE|MSG_DONTWAIT); if (rc < 0 || rc < sizeof(icmph)) { crm_perror(LOG_DEBUG, "No error message: %d", rc); return 0; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { s_err = (struct sock_extended_err *)CMSG_DATA(cmsg); } } CRM_ASSERT(s_err != NULL); if (s_err->ee_origin == SO_EE_ORIGIN_LOCAL) { if (s_err->ee_errno == EMSGSIZE) { crm_info("local error: Message too long, mtu=%u", s_err->ee_info); } else { crm_info("local error: %s", strerror(s_err->ee_errno)); } return 0; } else if (s_err->ee_origin == SO_EE_ORIGIN_ICMP) { char ping_host[MAX_HOST]; struct sockaddr_in *sin = (struct sockaddr_in*)(s_err+1); const char *ping_result = ping_desc(node->type, s_err->ee_type, s_err->ee_code); char *target_s = inet_ntoa(*(struct in_addr *)&(target.sin_addr.s_addr)); char *whereto_s = inet_ntoa(*(struct in_addr *)&(whereto->sin_addr.s_addr)); if (ntohs(icmph.un.echo.id) != ident) { /* Result was not for us */ crm_debug("Not our error (ident): %d %d", ntohs(icmph.un.echo.id), ident); return -1; } else if (safe_str_neq(target_s, whereto_s)) { /* Result was not for us */ crm_debug("Not our error (addr): %s %s", target_s, whereto_s); return -1; } else if (icmph.type != ICMP_ECHO) { /* Not an error */ crm_info("Not an error: %d", icmph.type); return -1; } /* snprintf(ping_host, MAX_HOST, "%s", inet_ntoa(*(struct in_addr *)&(sin->sin_addr.s_addr))); */ snprintf(ping_host, MAX_HOST, "%s", inet_ntoa(sin->sin_addr)); if (node->extra_filters == FALSE) { /* Now that we got some sort of reply, add extra filters to * ensure we keep getting the _right_ replies for dead hosts */ struct icmp_filter filt; crm_debug("Installing additional ICMP filters"); node->extra_filters = TRUE; /* only try once */ filt.data = ~((1<fd, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) { crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP filters for %s", ping_host); } } crm_debug("From %s icmp_seq=%u %s", ping_host, ntohs(icmph.un.echo.sequence), ping_result); } else { crm_debug("else: %d", s_err->ee_origin); } return 0; } #else int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto) { /* dummy function */ return 0; } int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto) { /* dummy function */ return 0; } #endif static ping_node *ping_new(const char *host) { ping_node *node; crm_malloc0(node, sizeof(ping_node)); if(strstr(host, ":")) { node->type = AF_INET6; } else { node->type = AF_INET; } node->host = crm_strdup(host); return node; } static gboolean ping_open(ping_node *node) { int ret_ga = 0; char *hostname = NULL; struct addrinfo *res = NULL; struct addrinfo hints; char *addr = NULL; char *cp = NULL; /* getaddrinfo */ bzero(&hints, sizeof(struct addrinfo)); hints.ai_flags = AI_CANONNAME; hints.ai_family = node->type; hints.ai_socktype = SOCK_RAW; if(node->type == AF_INET6) { hints.ai_protocol = IPPROTO_ICMPV6; } else { hints.ai_protocol = IPPROTO_ICMP; } addr = crm_strdup(node->host); if ((cp = strchr(addr, '%'))) { *cp = 0; } crm_debug("node->host[%s], addr[%s]", node->host, addr); ret_ga = getaddrinfo(addr, NULL, &hints, &res); crm_free(addr); if (ret_ga) { crm_warn("getaddrinfo: %s", gai_strerror(ret_ga)); goto bail; } if (res->ai_canonname) { hostname = res->ai_canonname; } else { hostname = node->host; } crm_debug_2("Got address %s for %s", hostname, node->host); if(!res->ai_addr) { crm_warn("getaddrinfo failed: no address"); goto bail; } memcpy(&(node->addr.raw), res->ai_addr, res->ai_addrlen); node->fd = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); /* node->fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); */ if(node->fd < 0) { crm_perror(LOG_WARNING, "Can't open socket to %s", hostname); goto bail; } if(node->type == AF_INET6) { int sockopt; inet_ntop(node->type, &node->addr.v6.sin6_addr, node->dest, sizeof(node->dest)); /* set recv buf for broadcast pings */ sockopt = 48 * 1024; setsockopt(node->fd, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt)); } else { inet_ntop(node->type, &node->addr.v4.sin_addr, node->dest, sizeof(node->dest)); } if(ping_timeout > 0) { struct timeval timeout_opt; timeout_opt.tv_sec = ping_timeout; timeout_opt.tv_usec = 0; setsockopt(node->fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout_opt, sizeof(timeout_opt)); } #ifdef ON_LINUX { int dummy = 1; memset(&cmsgbuf, 0, sizeof(cmsgbuf)); cmsglen = 0; if(node->type == AF_INET6) { struct icmp6_filter filt; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); if (setsockopt(node->fd, IPPROTO_ICMPV6, ICMP6_FILTER, (char*)&filt, sizeof(filt)) == -1) { crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP6 filters for %s", node->dest); } setsockopt(node->fd, SOL_IPV6, IPV6_RECVERR, (char *)&dummy, sizeof(dummy)); if ((cp = strchr(node->host, '%'))) { struct ifreq ifr; struct cmsghdr *cmsg; struct in6_pktinfo *ipi; memset(&ifr, 0, sizeof(ifr)); cp++; crm_debug("set interface: [%s]", cp); strncpy(ifr.ifr_name, cp, IFNAMSIZ-1); if (ioctl(node->fd, SIOCGIFINDEX, &ifr) >= 0) { cmsg = (struct cmsghdr*)cmsgbuf; cmsglen = CMSG_SPACE(sizeof(*ipi)); cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); cmsg->cmsg_level = SOL_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; ipi = (struct in6_pktinfo*)CMSG_DATA(cmsg); memset(ipi, 0, sizeof(*ipi)); ipi->ipi6_ifindex = ifr.ifr_ifindex; } else { crm_warn("unknown interface %s specified", cp); } } } else { struct icmp_filter filt; filt.data = ~((1<fd, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) { crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP filters for %s", node->dest); } setsockopt(node->fd, SOL_IP, IP_RECVERR, (char *)&dummy, sizeof(dummy)); if ((cp = strchr(node->host, '%'))) { struct ifreq ifr; struct cmsghdr *cmsg; struct in_pktinfo *ipi; memset(&ifr, 0, sizeof(ifr)); cp++; crm_debug("set interface: [%s]", cp); strncpy(ifr.ifr_name, cp, IFNAMSIZ-1); if (ioctl(node->fd, SIOCGIFINDEX, &ifr) >= 0) { cmsg = (struct cmsghdr*)cmsgbuf; cmsglen = CMSG_SPACE(sizeof(*ipi)); cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; ipi = (struct in_pktinfo*)CMSG_DATA(cmsg); memset(ipi, 0, sizeof(*ipi)); ipi->ipi_ifindex = ifr.ifr_ifindex; } else { crm_warn("unknown interface %s specified", cp); } } } } #endif crm_debug_2("Opened connection to %s", node->dest); freeaddrinfo(res); return TRUE; bail: if(res) { freeaddrinfo(res); } return FALSE; } static gboolean ping_close(ping_node *node) { int tmp_fd = node->fd; node->fd = -1; if (tmp_fd >= 0) { if(close(tmp_fd) < 0) { crm_perror(LOG_ERR,"Could not close ping socket"); } else { tmp_fd = -1; crm_debug_2("Closed connection to %s", node->dest); } } return (tmp_fd == -1); } #define MAXPACKETLEN 131072 #define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ #define ICMP6ECHOTMLEN 20 #define DEFDATALEN ICMP6ECHOTMLEN #define EXTRA 256 /* for AH and various other headers. weird. */ #define IP6LEN 40 static int dump_v6_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr) { int rc = -1; /* Try again */ int fromlen; char from_host[1024]; struct icmp6_hdr *icp; struct sockaddr *from; if (!hdr || !hdr->msg_name || hdr->msg_namelen != sizeof(struct sockaddr_in6) || ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET6) { crm_warn("Invalid echo peer"); return rc; } fromlen = hdr->msg_namelen; from = (struct sockaddr *)hdr->msg_name; getnameinfo(from, fromlen, from_host, sizeof(from_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if (bytes < (int)sizeof(struct icmp6_hdr)) { crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, from_host); return rc; } icp = (struct icmp6_hdr *)buf; if (icp->icmp6_type == ICMP6_ECHO_REPLY) { if (ident == ntohs(icp->icmp6_id) && node->iseq == ntohs(icp->icmp6_seq)) { rc = 1; /* Alive */ } } else if(icp->icmp6_type != ICMP6_ECHO_REQUEST) { rc = process_icmp6_error(node, (struct sockaddr_in6*)&(node->addr)); } do_crm_log(LOG_DEBUG_2, "Echo from %s (exp=%d, seq=%d, id=%d, dest=%s, data=%s): %s", from_host, node->iseq, ntohs(icp->icmp6_seq), ntohs(icp->icmp6_id), node->dest, (char*)(buf + ICMP6ECHOLEN), ping_desc(node->type, icp->icmp6_type, icp->icmp6_code)); return rc; } static int dump_v4_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr) { int rc = -1; /* Try again */ int iplen, fromlen; char from_host[1024]; struct ip *ip; struct icmp *icp; struct sockaddr *from; if (hdr == NULL || !hdr->msg_name || hdr->msg_namelen != sizeof(struct sockaddr_in) || ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET) { crm_warn("Invalid echo peer"); return rc; } fromlen = hdr->msg_namelen; from = (struct sockaddr *)hdr->msg_name; getnameinfo(from, fromlen, from_host, sizeof(from_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); ip = (struct ip*)buf; iplen = ip->ip_hl * 4; if (bytes < (iplen + sizeof(struct icmp))) { crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, from_host); return rc; } /* Check the IP header */ icp = (struct icmp*)(buf + iplen); if (icp->icmp_type == ICMP_ECHOREPLY) { if (ident == ntohs(icp->icmp_id) && node->iseq == ntohs(icp->icmp_seq)) { rc = 1; /* Alive */ } } else if(icp->icmp_type != ICMP_ECHO) { rc = process_icmp4_error(node, (struct sockaddr_in*)from); } /* TODO: Stop logging icmp_id once we're sure everything works */ do_crm_log(LOG_DEBUG_2, "Echo from %s (exp=%d, seq=%d, id=%d, dest=%s, data=%s): %s", from_host, node->iseq, ntohs(icp->icmp_seq), ntohs(icp->icmp_id), node->dest, icp->icmp_data, ping_desc(node->type, icp->icmp_type, icp->icmp_code)); return rc; } static int ping_read(ping_node *node, int *lenp) { int bytes; char fromaddr[128]; struct msghdr m; struct cmsghdr *cm; u_char buf[1024]; struct iovec iov[2]; int saved_errno = 0; struct timeval recv_start_time; struct timeval recv_time; int packlen; u_char *packet; gettimeofday(&recv_start_time, NULL); packlen = DEFDATALEN + IP6LEN + ICMP6ECHOLEN + EXTRA; crm_malloc0(packet, packlen); retry: m.msg_name = &fromaddr; m.msg_namelen = sizeof(fromaddr); memset(&iov, 0, sizeof(iov)); iov[0].iov_base = (caddr_t)packet; iov[0].iov_len = packlen; m.msg_iov = iov; m.msg_iovlen = 1; cm = (struct cmsghdr *)buf; m.msg_control = (caddr_t)buf; m.msg_controllen = sizeof(buf); bytes = recvmsg(node->fd, &m, 0); saved_errno = errno; crm_debug_2("Got %d bytes", bytes); if(bytes < 0) { crm_perror(LOG_DEBUG, "Read failed"); if (saved_errno != EAGAIN && saved_errno != EINTR) { int rc = 0; if(node->type == AF_INET6) { rc = process_icmp6_error(node, (struct sockaddr_in6*)&(node->addr)); } else { rc = process_icmp4_error(node, (struct sockaddr_in*)&fromaddr); } if(rc < 0) { crm_info("Retrying..."); goto retry; } } } else if (bytes > 0) { int rc = 0; if(node->type == AF_INET6) { rc = dump_v6_echo(node, packet, bytes, &m); } else { rc = dump_v4_echo(node, packet, bytes, &m); } gettimeofday(&recv_time, NULL); if ((recv_start_time.tv_sec + ping_timeout) < recv_time.tv_sec) { crm_warn("failed to receive for timeout."); crm_free(packet); return FALSE; } if(rc < 0) { crm_info("Retrying..."); goto retry; } else if(rc > 0) { crm_free(packet); return TRUE; } } else { crm_err("Unexpected reply"); } crm_free(packet); return FALSE; } static int ping_write(ping_node *node, const char *data, size_t size) { struct iovec iov; int rc, bytes, namelen; /* static int ntransmitted = 9; */ struct msghdr smsghdr; u_char outpack[MAXPACKETLEN]; memset(outpack, 0, MAXPACKETLEN); node->iseq++; if(node->type == AF_INET6) { struct icmp6_hdr *icp; namelen = sizeof(struct sockaddr_in6); bytes = ICMP6ECHOLEN + DEFDATALEN; icp = (struct icmp6_hdr *)outpack; icp->icmp6_code = 0; icp->icmp6_cksum = 0; icp->icmp6_type = ICMP6_ECHO_REQUEST; icp->icmp6_id = htons(ident); icp->icmp6_seq = htons(node->iseq); /* Sanity check */ if(ntohs(icp->icmp6_seq) != node->iseq) { crm_debug("Wrapping at %u", node->iseq); node->iseq = ntohs(icp->icmp6_seq); } memcpy(&outpack[ICMP6ECHOLEN], "pingd-v6", 8); } else { struct icmp *icp; namelen = sizeof(struct sockaddr_in); bytes = sizeof(struct icmp) + 11; icp = (struct icmp *)outpack; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_type = ICMP_ECHO; icp->icmp_id = htons(ident); icp->icmp_seq = htons(node->iseq); /* Sanity check */ if(ntohs(icp->icmp_seq) != node->iseq) { crm_debug("Wrapping at %u", node->iseq); node->iseq = ntohs(icp->icmp_seq); } memcpy(icp->icmp_data, "pingd-v4", 8); icp->icmp_cksum = in_cksum((u_short *)icp, bytes); } memset(&iov, 0, sizeof(struct iovec)); memset(&smsghdr, 0, sizeof(struct msghdr)); smsghdr.msg_name = (caddr_t)&(node->addr); smsghdr.msg_namelen = namelen; iov.iov_base = (caddr_t)outpack; iov.iov_len = bytes; smsghdr.msg_iov = &iov; smsghdr.msg_iovlen = 1; smsghdr.msg_control = cmsgbuf; smsghdr.msg_controllen = cmsglen; rc = sendmsg(node->fd, &smsghdr, 0); if (rc < 0 || rc != bytes) { crm_perror(LOG_WARNING, "Wrote %d of %d chars", rc, bytes); return FALSE; } crm_debug_2("Sent %d bytes to %s", rc, node->dest); return TRUE; } static void pingd_shutdown(int nsig) { need_shutdown = TRUE; send_update(0); g_hash_table_destroy(ping_nodes); slist_destroy(ping_node, p, ping_list, crm_free(p->host); crm_free(p); ); exit(0); } #if SUPPORT_HEARTBEAT static gboolean pingd_ha_dispatch(IPC_Channel *channel, gpointer user_data) { gboolean stay_connected = TRUE; crm_debug_2("Invoked"); while(pingd_cluster != NULL && IPC_ISRCONN(channel)) { if(pingd_cluster->llc_ops->msgready(pingd_cluster) == 0) { crm_debug_2("no message ready yet"); break; } /* invoke the callbacks but dont block */ pingd_cluster->llc_ops->rcvmsg(pingd_cluster, 0); } if (pingd_cluster == NULL || channel->ch_status != IPC_CONNECT) { if(need_shutdown == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } stay_connected = FALSE; } return stay_connected; } static void pingd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(need_shutdown) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); } static gboolean register_with_ha(void) { if(pingd_cluster == NULL) { pingd_cluster = ll_cluster_new("heartbeat"); } if(pingd_cluster == NULL) { crm_err("Cannot create heartbeat object"); return FALSE; } crm_debug("Signing in with Heartbeat"); if (pingd_cluster->llc_ops->signon( pingd_cluster, crm_system_name) != HA_OK) { crm_err("Cannot sign on with heartbeat: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } do_node_walk(pingd_cluster); crm_debug_3("Be informed of Node Status changes"); if (HA_OK != pingd_cluster->llc_ops->set_nstatus_callback( pingd_cluster, pingd_nstatus_callback, NULL)) { crm_err("Cannot set nstatus callback: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } if (pingd_cluster->llc_ops->set_ifstatus_callback( pingd_cluster, pingd_lstatus_callback, NULL) != HA_OK) { crm_err("Cannot set if status callback: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, pingd_cluster->llc_ops->ipcchan( pingd_cluster), FALSE, pingd_ha_dispatch, pingd_cluster, pingd_ha_connection_destroy); return TRUE; } void do_node_walk(ll_cluster_t *hb_cluster) { const char *ha_node = NULL; /* Async get client status information in the cluster */ crm_debug_2("Invoked"); crm_debug_3("Requesting an initial dump of CRMD client_status"); hb_cluster->llc_ops->client_status( hb_cluster, NULL, CRM_SYSTEM_CRMD, -1); crm_info("Requesting the list of configured nodes"); hb_cluster->llc_ops->init_nodewalk(hb_cluster); do { const char *ha_node_type = NULL; const char *ha_node_status = NULL; ha_node = hb_cluster->llc_ops->nextnode(hb_cluster); if(ha_node == NULL) { continue; } ha_node_type = hb_cluster->llc_ops->node_type( hb_cluster, ha_node); if(safe_str_neq("ping", ha_node_type)) { crm_debug("Node %s: skipping '%s'", ha_node, ha_node_type); continue; } if(do_filter && g_hash_table_lookup(ping_nodes, ha_node) == NULL) { crm_debug("Filtering: %s", ha_node); continue; } ha_node_status = hb_cluster->llc_ops->node_status( hb_cluster, ha_node); crm_debug("Adding: %s=%s", ha_node, ha_node_status); g_hash_table_replace(ping_nodes, crm_strdup(ha_node), crm_strdup(ha_node_status)); } while(ha_node != NULL); hb_cluster->llc_ops->end_nodewalk(hb_cluster); crm_debug_2("Complete"); send_update(-1); } #endif static gboolean stand_alone_ping(gpointer data) { int num_active = 0; + GListPtr num = NULL; crm_debug_2("Checking connectivity"); - slist_iter( - ping, ping_node, ping_list, num, - + for(num = ping_list; num != NULL; num = num->next) { + ping_node *ping = (ping_node*)num->data; if(ping_open(ping)) { int lpc = 0; for(;lpc < pings_per_host; lpc++) { int len = 0; if(ping_write(ping, "test", 4) == FALSE) { crm_info("Node %s is unreachable (write)", ping->host); } else if(ping_read(ping, &len)) { crm_debug("Node %s is alive", ping->host); num_active++; break; } else { crm_info("Node %s is unreachable (read)", ping->host); } sleep(1); } } ping_close(ping); - ); + } send_update(num_active); return TRUE; } static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "This text"}, {"version", 0, 0, '$', "Version information" }, {"verbose", 0, 0, 'V', "Increase debug output\n"}, {"daemonize", 0, 0, 'D', "\t\tRun in daemon mode"}, {"pid-file", 1, 0, 'p', "\tFile in which to store the process' PID\n"}, {"node", 1, 0, 'N', "\tDNS name or IP address of a host to check (can be specified more than once\n"}, {"attr-name", 1, 0, 'a', "\tName of the node attribute to set"}, {"attr-dampen", 1, 0, 'd', "How long to wait for no further changes to occur before updating the CIB with a changed attribute"}, {"attr-section", 1, 0, 'S', "(Advanced) Which part of the CIB to put the attribute in"}, {"attr-set", 1, 0, 's', "\t(Advanced) Name of the set in which to put the attribute\n"}, {"ping-interval", 1, 0, 'i', "How often, in seconds, to check for node liveliness (default=1)"}, {"ping-attempts", 1, 0, 'n', "Number of ping attempts, per host, before declaring it dead (default=2)"}, {"ping-timeout", 1, 0, 't', "How long, in seconds, to wait before declaring a ping lost (default=2)"}, {"ping-multiplier", 1, 0, 'm', "For every connected node, add to the value set in the CIB"}, {"no-updates", 0, 0, 'U', NULL, 1}, /* Legacy */ {"ping-host", 1, 0, 'h', NULL, 1}, {"value-multiplier", 1, 0, 'm', NULL, 1}, {"interval", 1, 0, 'i', NULL, 1}, {0, 0, 0, 0} }; int main(int argc, char **argv) { int argerr = 0; int flag; const char *pid_file = NULL; gboolean daemonize = FALSE; ping_node *p = NULL; int option_index = 0; pid_file = "/tmp/pingd.pid"; mainloop_add_signal(SIGTERM, pingd_shutdown); ping_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv); crm_set_options("V?$p:a:d:s:S:h:Dm:N:Ui:t:n:", NULL, long_options, "Daemon for checking external connectivity and making the results available to the cluster"); while (1) { flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'p': pid_file = optarg; break; case 'a': pingd_attr = optarg; break; case 'N': case 'h': stand_alone = TRUE; crm_debug("Adding ping host %s", optarg); p = ping_new(optarg); ping_list = g_list_append(ping_list, p); break; case 's': attr_set = crm_strdup(optarg); break; case 'm': attr_multiplier = crm_parse_int(optarg, "1"); break; case 'S': attr_section = crm_strdup(optarg); break; case 'd': attr_dampen = crm_get_msec(optarg); break; case 'i': re_ping_interval = crm_get_msec(optarg); break; case 'n': pings_per_host = crm_atoi(optarg, NULL); break; case 't': ping_timeout = crm_atoi(optarg, NULL); break; case 'D': daemonize = TRUE; break; case 'U': cl_log_enable_stderr(TRUE); do_updates = FALSE; break; case '$': case '?': crm_help(flag, LSB_EXIT_OK); break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); crm_err("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { crm_err("non-option ARGV-elements: "); printf("non-option ARGV-elements: "); while (optind < argc) { crm_err("%s ", argv[optind]); printf("%s ", argv[optind++]); } printf("\n"); } if (argerr) { crm_help(flag, LSB_EXIT_GENERIC); } crm_make_daemon(crm_system_name, daemonize, pid_file); ident = getpid(); if(do_updates == FALSE) { goto start_ping; } #if SUPPORT_COROSYNC if(is_openais_cluster()) { stand_alone = TRUE; } #endif #if SUPPORT_HEARTBEAT if(stand_alone == FALSE && register_with_ha() == FALSE) { crm_err("HA registration failed"); cl_flush_logs(); exit(LSB_EXIT_GENERIC); } #endif start_ping: if(stand_alone && ping_list == NULL) { crm_err("You must specify a list of hosts to monitor"); exit(LSB_EXIT_GENERIC); } crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); if(stand_alone) { stand_alone_ping(NULL); g_timeout_add(re_ping_interval, stand_alone_ping, NULL); } g_main_run(mainloop); crm_info("Exiting %s", crm_system_name); return 0; } static void count_ping_nodes(gpointer key, gpointer value, gpointer user_data) { int *num_active = user_data; CRM_CHECK(num_active != NULL, return); if(need_shutdown) { return; } if(safe_str_eq(value, "ping")) { (*num_active)++; } else if(safe_str_eq(value, "up")) { (*num_active)++; } } void send_update(int num_active) { char *value = NULL; char *damp = crm_itoa(attr_dampen/1000); if(num_active < 0) { num_active = 0; g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active); } value = crm_itoa(attr_multiplier*num_active); attrd_lazy_update('U', NULL, pingd_attr, value, attr_section, attr_set, damp); crm_free(value); crm_free(damp); } void pingd_nstatus_callback( const char *node, const char * status, void* private_data) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); if(g_hash_table_lookup(ping_nodes, node) != NULL) { g_hash_table_replace( ping_nodes, crm_strdup(node), crm_strdup(status)); send_update(-1); } } void pingd_lstatus_callback(const char *node, const char *lnk, const char *status, void *private) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); pingd_nstatus_callback(node, status, private); }