diff --git a/lib/crm/pengine/complex.c b/lib/crm/pengine/complex.c index 79d4a54b1c..d5d81f92ac 100644 --- a/lib/crm/pengine/complex.c +++ b/lib/crm/pengine/complex.c @@ -1,437 +1,434 @@ /* * 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 populate_hash(crm_data_t *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_child, native_children, native_parameter, native_print, native_active, native_resource_state, native_location, native_free }, { group_unpack, native_find_child, native_children, native_parameter, group_print, group_active, group_resource_state, native_location, group_free }, { clone_unpack, native_find_child, native_children, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free }, { master_unpack, native_find_child, native_children, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free } }; int 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; } 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(rsc->xml, XML_TAG_META_SETS, node_hash, meta_hash, NULL, data_set->now); /* populate from the regular attributes until the GUI can create * meta attributes */ unpack_instance_attributes(rsc->xml, XML_TAG_ATTR_SETS, node_hash, meta_hash, NULL, 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); } } gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set) { const char *value = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); 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)); if(*rsc == NULL) { return FALSE; } (*rsc)->xml = xml_obj; (*rsc)->parent = parent; (*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE); (*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); 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); if(parent != NULL) { g_hash_table_foreach( parent->parameters, dup_attr, (*rsc)->parameters); } (*rsc)->flags = 0; set_bit((*rsc)->flags, pe_rsc_runnable); set_bit((*rsc)->flags, pe_rsc_provisional); if(data_set->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)->fail_stickiness = data_set->default_resource_fail_stickiness; 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, "is_managed"); if(value != NULL && safe_str_neq("default", value)) { gboolean bool_value = TRUE; cl_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); } } crm_debug_2("Options for %s", (*rsc)->id); value = g_hash_table_lookup((*rsc)->meta, "globally_unique"); if(value == NULL || crm_is_true(value)) { 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("\tDependancy restart handling: restart"); } else { (*rsc)->restart_type = pe_restart_ignore; crm_debug_2("\tDependancy restart handling: ignore"); } value = g_hash_table_lookup((*rsc)->meta, "multiple_active"); 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, "resource_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) { (*rsc)->fail_stickiness = char2score(value); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_TARGET_ROLE); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->next_role = text2role(value); if((*rsc)->next_role == RSC_ROLE_UNKNOWN) { crm_config_err("%s: Unknown value for " XML_RSC_ATTR_TARGET_ROLE": %s", (*rsc)->id, value); } } 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_not_set((*rsc)->flags, pe_rsc_managed)) { crm_warn("Resource %s is currently not managed", (*rsc)->id); } else if(data_set->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"); /* 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_find_node_id(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, common_update_score(child_rsc, id, score); ); } } resource_t *uber_parent(resource_t *rsc) { resource_t *parent = rsc; while(parent != NULL && parent->parent != NULL) { parent = parent->parent; } return parent; } void common_apply_stickiness(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { int fail_count = 0; char *fail_attr = NULL; const char *value = NULL; GHashTable *meta_hash = NULL; if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, common_apply_stickiness(child_rsc, node, data_set); ); return; } meta_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); get_meta_attributes(meta_hash, rsc, node, data_set); /* update resource preferences that relate to the current node */ value = g_hash_table_lookup(meta_hash, "resource_stickiness"); if(value != NULL && safe_str_neq("default", value)) { rsc->stickiness = char2score(value); } else { rsc->stickiness = data_set->default_resource_stickiness; } value = g_hash_table_lookup(meta_hash, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { rsc->fail_stickiness = char2score(value); } else { rsc->fail_stickiness = data_set->default_resource_fail_stickiness; } /* process failure stickiness */ fail_attr = crm_concat("fail-count", rsc->id, '-'); value = g_hash_table_lookup(node->details->attrs, fail_attr); if(value != NULL) { crm_debug("%s: %s", fail_attr, value); fail_count = char2score(value); } crm_free(fail_attr); if(fail_count > 0 && rsc->fail_stickiness != 0) { resource_t *failed = rsc; int score = fail_count * rsc->fail_stickiness; if(is_not_set(rsc->flags, pe_rsc_unique)) { failed = uber_parent(rsc); - - } else if(rsc->parent && rsc->parent->variant == pe_group) { - failed = rsc->parent; } /* detect and prevent score underflows */ if(rsc->fail_stickiness < 0 && (score > 0 || score < -INFINITY)) { score = -INFINITY; } resource_location(failed, node, score, "fail_stickiness", data_set); crm_info("Setting failure stickiness for %s on %s: %d", failed->id, node->details->uname, score); } g_hash_table_destroy(meta_hash); } 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); if(rsc->parameters != NULL) { g_hash_table_destroy(rsc->parameters); } if(rsc->meta != NULL) { g_hash_table_destroy(rsc->meta); } if(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_list_free(rsc->known_on); rsc->known_on = NULL; } if(rsc->actions) { g_list_free(rsc->actions); rsc->actions = NULL; } pe_free_shallow_adv(rsc->rsc_location, FALSE); pe_free_shallow_adv(rsc->allowed_nodes, TRUE); 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/pengine/group.c b/pengine/group.c index f6f5951df1..8f7f65902c 100644 --- a/pengine/group.c +++ b/pengine/group.c @@ -1,539 +1,582 @@ /* * 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_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); 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("Dependancy 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; } 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; dump_node_scores(scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); slist_iter( child_rsc, resource_t, rsc->children, lpc, node = child_rsc->cmds->color(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); 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); 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 */); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, started_key(rsc), CRMD_ACTION_STARTED, NULL, TRUE/* !group_data->child_starting */, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = stop_action(rsc, NULL, TRUE/* !group_data->child_stopping */); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, TRUE/* !group_data->child_stopping */, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; value = g_hash_table_lookup(rsc->parameters, crm_meta_name("stateful")); if(crm_is_true(value)) { op = custom_action(rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; } rsc->actions = rsc->actions; /* rsc->actions = NULL; */ } void group_update_pseudo_status(resource_t *parent, resource_t *child) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, parent); if(group_data->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; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task) && action->runnable) { group_data->child_stopping = TRUE; crm_debug_3("Based on %s the group is stopping", action->uuid); } else if(safe_str_eq(CRMD_ACTION_START, action->task) && 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) { const char *value = NULL; gboolean stateful = FALSE; resource_t *last_rsc = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); native_internal_constraints(rsc, data_set); value = g_hash_table_lookup(rsc->parameters, crm_meta_name("stateful")); stateful = crm_is_true(value); custom_action_order( rsc, stopped_key(rsc), NULL, rsc, start_key(rsc), NULL, pe_order_optional, data_set); custom_action_order( rsc, stop_key(rsc), NULL, rsc, stopped_key(rsc), NULL, pe_order_runnable_left|pe_order_implies_right|pe_order_implies_left, data_set); custom_action_order( rsc, start_key(rsc), NULL, rsc, started_key(rsc), NULL, pe_order_runnable_left, data_set); slist_iter( child_rsc, resource_t, rsc->children, lpc, int stop = pe_order_shutdown|pe_order_implies_right; int stopped = pe_order_implies_right_printed; int start = pe_order_implies_right|pe_order_runnable_left; int started = pe_order_runnable_left|pe_order_implies_right|pe_order_implies_right_printed; child_rsc->cmds->internal_constraints(child_rsc, data_set); if(last_rsc == NULL) { stop |= pe_order_implies_left; stopped = pe_order_implies_right; } else if(group_data->colocated) { rsc_colocation_new( "group:internal_colocation", NULL, INFINITY, child_rsc, last_rsc, NULL, NULL, data_set); } if(stateful) { custom_action_order(rsc, demote_key(rsc), NULL, child_rsc, demote_key(child_rsc), NULL, stop|pe_order_implies_left_printed, data_set); custom_action_order(child_rsc, demote_key(child_rsc), NULL, rsc, demoted_key(rsc), NULL, stopped, data_set); custom_action_order(child_rsc, promote_key(child_rsc), NULL, rsc, promoted_key(rsc), NULL, started, data_set); custom_action_order(rsc, promote_key(rsc), NULL, child_rsc, promote_key(child_rsc), NULL, pe_order_implies_left_printed, data_set); } order_start_start(rsc, child_rsc, pe_order_implies_left_printed); order_stop_stop(rsc, child_rsc, stop|pe_order_implies_left_printed); custom_action_order(child_rsc, stop_key(child_rsc), NULL, rsc, stopped_key(rsc), NULL, stopped, data_set); custom_action_order(child_rsc, start_key(child_rsc), NULL, rsc, started_key(rsc), NULL, started, data_set); if(group_data->ordered == FALSE) { order_start_start(rsc, child_rsc, start|pe_order_implies_left_printed); if(stateful) { custom_action_order(rsc, promote_key(rsc), NULL, child_rsc, promote_key(child_rsc), NULL, start|pe_order_implies_left_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_implies_left); if(stateful) { custom_action_order(last_rsc, promote_key(last_rsc), NULL, child_rsc, promote_key(child_rsc), NULL, start, data_set); custom_action_order(child_rsc, demote_key(child_rsc), NULL, last_rsc, demote_key(last_rsc), NULL, pe_order_implies_left, data_set); } } else { /* If anyone in the group is starting, then * pe_order_implies_right 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_implies_left|pe_order_implies_right|pe_order_runnable_right|pe_order_runnable_left; order_start_start(rsc, child_rsc, flags); if(stateful) { custom_action_order(rsc, promote_key(rsc), NULL, child_rsc, promote_key(child_rsc), NULL, flags, data_set); } } last_rsc = child_rsc; ); if(group_data->ordered && last_rsc != NULL) { int stop_stop_flags = pe_order_implies_right; int stop_stopped_flags = pe_order_implies_left; order_stop_stop(rsc, last_rsc, stop_stop_flags); custom_action_order(last_rsc, stop_key(last_rsc), NULL, rsc, stopped_key(rsc), NULL, stop_stopped_flags, data_set); if(stateful) { custom_action_order(rsc, demote_key(rsc), NULL, last_rsc, demote_key(last_rsc), NULL, stop_stop_flags, data_set); custom_action_order(last_rsc, demote_key(last_rsc), NULL, rsc, demoted_key(rsc), NULL, stop_stopped_flags, data_set); } } } void group_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { group_variant_data_t *group_data = NULL; 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; } 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); ); } void group_rsc_colocation_rh( 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); 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; } else if(group_data->colocated && group_data->first_child) { 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); ); } void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_4("%s->%s", order->lh_action_task, order->rh_action_task); if(order->rh_rsc != NULL && (rsc == order->rh_rsc || rsc == order->rh_rsc->parent)) { native_rsc_order_lh(rsc, order, data_set); return; } #if 0 if(order->type != pe_order_optional) { native_rsc_order_lh(rsc, order, data_set); } if(order->type & pe_order_implies_left) { native_rsc_order_lh(group_data->first_child, order, data_set); } #endif convert_non_atomic_task(rsc, order, TRUE); native_rsc_order_lh(rsc, order, data_set); } void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_4("%s->%s", lh_action->uuid, order->rh_action_task); if(rsc == NULL) { return; } if(safe_str_eq(CRM_OP_PROBED, lh_action->uuid)) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_order_rh(lh_action, child_rsc, order); ); if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED && rsc->fns->state(rsc, FALSE) > RSC_ROLE_STOPPED) { order->type |= pe_order_implies_right; } } else if(lh_action->rsc != NULL && lh_action->rsc != rsc && lh_action->rsc != rsc->parent && lh_action->rsc->parent != rsc) { char *tmp = NULL; char *task_s = NULL; int interval = 0; enum action_tasks task = 0; parse_op_key(order->lh_action_task, &tmp, &task_s, &interval); task = text2task(task_s); crm_free(task_s); crm_free(tmp); switch(task) { case no_action: case monitor_rsc: case action_notify: case action_notified: case shutdown_crm: case stonith_node: break; case stop_rsc: case stopped_rsc: case action_demote: case action_demoted: order->type |= pe_order_complex_left; break; case start_rsc: case started_rsc: case action_promote: case action_promoted: order->type |= pe_order_complex_right; break; } } native_rsc_order_rh(lh_action, rsc, order); } 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); 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); } void group_expand(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); 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); ); } +extern void node_list_update(GListPtr list1, GListPtr list2, int factor); + GListPtr group_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, int factor, gboolean allow_rollback) { + GListPtr archive = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(is_set(rsc->flags, pe_rsc_merging)) { crm_debug("Breaking dependancy loop with %s at %s", rsc->id, rhs); return nodes; } else if(is_not_set(rsc->flags, pe_rsc_provisional)) { return nodes; } set_bit(rsc->flags, pe_rsc_merging); +#if 0 + /* turn this back on once we switch to migration-threshold */ nodes = group_data->first_child->cmds->merge_weights( group_data->first_child, rhs, nodes, factor, allow_rollback); +#else + slist_iter(child, resource_t, rsc->children, lpc, + + if(allow_rollback) { + archive = node_list_dup(nodes, FALSE, FALSE); + } + + slist_iter( + node, node_t, child->allowed_nodes, lpc2, + if(node->weight < 0 && node->weight > -INFINITY) { + /* Once a child's score goes below zero, force the node score to -INFINITY + * + * This prevents the group from being partially active in scenarios + * where it could be fully active elsewhere + * + * If we don't do this, then the next child(ren)'s stickiness might bring + * the combined score above 0 again - which confuses the PE into thinking + * the whole group can run there but is pointless since the later children + * are not be able to run if the ones before them can't + */ + node->weight = -INFINITY; + } + ); + + node_list_update(nodes, child->allowed_nodes, factor); + + if(archive && can_run_any(nodes) == FALSE) { + crm_err("%s: Rolling back scores from %s", rhs, rsc->id); + pe_free_shallow_adv(nodes, TRUE); + nodes = archive; + goto bail; + } + + pe_free_shallow_adv(archive, TRUE); + ); +#endif + slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, nodes = native_merge_weights( constraint->rsc_lh, rsc->id, nodes, constraint->score/INFINITY, allow_rollback); ); + bail: clear_bit(rsc->flags, pe_rsc_merging); return nodes; }