diff --git a/pengine/clone.c b/pengine/clone.c index 8e37989f82..459d6af0ab 100644 --- a/pengine/clone.c +++ b/pengine/clone.c @@ -1,1462 +1,1503 @@ /* * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #define VARIANT_CLONE 1 #include gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set); static void append_parent_colocation(resource_t *rsc, resource_t *child, gboolean all); 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; } static gboolean did_fail(const resource_t *rsc) { GListPtr gIter = rsc->children; if(is_set(rsc->flags, pe_rsc_failed)) { return TRUE; } 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 rc = 0; int level = LOG_DEBUG_3; node_t *node1 = NULL; node_t *node2 = NULL; gboolean can1 = TRUE; gboolean can2 = 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 */ 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; } } 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(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(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 != 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; } 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->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; } - /* Current score */ - node1 = g_list_nth_data(resource1->running_on, 0); - node1 = g_hash_table_lookup(resource1->allowed_nodes, node1->details->id); - - node2 = g_list_nth_data(resource2->running_on, 0); - node2 = g_hash_table_lookup(resource2->allowed_nodes, node2->details->id); - - if(node1->weight < node2->weight) { - do_crm_log_unlikely(level, "%s < %s: current score", resource1->id, resource2->id); - return 1; - - } else if(node1->weight > node2->weight) { - do_crm_log_unlikely(level, "%s > %s: current score", 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 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(resource2->running_on->data); g_hash_table_insert(hash2, (gpointer)n->details->id, n); - /* Possibly a replacement for the with_scores block above */ - + for(gIter = resource1->parent->rsc_cons; 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_rh, resource1->id, hash1, + constraint->node_attribute, + constraint->score/INFINITY, FALSE, FALSE); + } + 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); } + for(gIter = resource2->parent->rsc_cons; 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_rh, resource2->id, hash2, + constraint->node_attribute, + constraint->score/INFINITY, FALSE, FALSE); + } + 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); } + /* Current location score */ + node1 = g_list_nth_data(resource1->running_on, 0); + node1 = g_hash_table_lookup(hash1, node1->details->id); + + node2 = g_list_nth_data(resource2->running_on, 0); + node2 = g_hash_table_lookup(hash2, node2->details->id); + + if(node1->weight < node2->weight) { + if(node1->weight < 0) { + do_crm_log_unlikely(level, "%s > %s: current score", resource1->id, resource2->id); + return -1; + } else { + do_crm_log_unlikely(level, "%s < %s: current score", resource1->id, resource2->id); + return 1; + } + + } else if(node1->weight > node2->weight) { + do_crm_log_unlikely(level, "%s > %s: current score", resource1->id, resource2->id); + return -1; + } + + /* All location scores */ 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); } 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; } else if(node1->weight > node2->weight) { do_crm_log_unlikely(level, "%s > %s: colocated score", resource1->id, resource2->id); rc = -1; break; } } /* Order by reverse uname - same as sort_node_weight() does? */ 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; } } rc = strcmp(resource1->id, resource2->id); do_crm_log_unlikely(level, "%s %c %s: default", resource1->id, rc<0?'<':'>', resource2->id); return rc; } 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; } 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); 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) { crm_trace("%s can run on %s: %d", rsc->id, node->details->uname, local_node->count); return local_node; } else { crm_debug_2("%s cannot run on %s: node full (%d >= %d)", rsc->id, node->details->uname, local_node->count, clone_data->clone_node_max); } bail: if(node) { common_update_score(rsc, node->details->id, -INFINITY); } return NULL; } static node_t * color_instance(resource_t *rsc, node_t *prefer, gboolean all_coloc, pe_working_set_t *data_set) { node_t *chosen = NULL; node_t *local_node = NULL; crm_debug_2("Processing %s", rsc->id); 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; } /* Only include positive colocation preferences of dependant resources * if not every node will get a copy of the clone */ append_parent_colocation(rsc->parent, rsc, all_coloc); if(prefer) { node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id); if(local_prefer == NULL || local_prefer->weight < 0) { crm_trace("Not pre-allocating %s to %s - unavailable", rsc->id, prefer->details->uname); 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); } } chosen = rsc->cmds->allocate(rsc, prefer, data_set); if(chosen) { local_node = pe_hash_table_lookup( rsc->parent->allowed_nodes, chosen->details->id); - if(local_node) { + if(prefer && chosen && chosen->details != prefer->details) { + crm_err("Pre-allocation failed: got %s instead of %s", + chosen->details->uname, prefer->details->uname); + native_deallocate(rsc); + chosen = NULL; + + } else 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; } static void append_parent_colocation(resource_t *rsc, resource_t *child, gboolean all) { 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, node_t *prefer, pe_working_set_t *data_set) { 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; } 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); /* this information is used by sort_clone_instance() when deciding in which * order to allocate clone instances */ + gIter = rsc->rsc_cons; + for(; gIter != NULL; gIter = gIter->next) { + rsc_colocation_t *constraint = (rsc_colocation_t*)gIter->data; + crm_trace("%s: Coloring %s first", rsc->id, constraint->rsc_rh->id); + constraint->rsc_rh->cmds->allocate(constraint->rsc_rh, prefer, data_set); + } + 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); } 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; if(can_run_resources(node)) { available_nodes++; } } rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set); /* Pre-allocate as many instances as we can to their current location */ g_hash_table_iter_init (&iter, rsc->allowed_nodes); while (available_nodes && available_nodes <= clone_data->clone_max && g_hash_table_iter_next (&iter, NULL, (void**)&node)) { int lpc; int loop_max = clone_data->clone_max / available_nodes; if(loop_max < 1) { loop_max = 1; } if(can_run_resources(node) == FALSE || node->weight < 0) { + crm_trace("Not Pre-allocatiing %s", node->details->uname); continue; } crm_trace("Pre-allocatiing %s", node->details->uname); for(lpc = 0; allocated < clone_data->clone_max && node->count < clone_data->clone_node_max && lpc < clone_data->clone_node_max && lpc < loop_max; lpc++) { for(gIter = rsc->children; gIter != NULL; gIter = gIter->next) { resource_t *child = (resource_t*)gIter->data; if(child->running_on && is_set(child->flags, pe_rsc_provisional) && is_not_set(child->flags, pe_rsc_failed)) { node_t *child_node = child->running_on->data; if(child_node->details == node->details && color_instance(child, node, clone_data->clone_max < available_nodes, data_set)) { crm_trace("Pre-allocated %s to %s", child->id, node->details->uname); allocated++; break; } } } } } crm_trace("Done pre-allocating"); 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 == NULL) { crm_err("%s is running on %s which isn't allowed", child->id, child_node->details->uname); } } if(is_not_set(child->flags, pe_rsc_provisional)) { } else 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(color_instance(child, NULL, clone_data->clone_max < available_nodes, data_set)) { allocated++; } } 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); return NULL; } static void clone_update_pseudo_status( resource_t *rsc, gboolean *stopping, gboolean *starting, gboolean *active) { 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); if(rsc->running_on) { *active = 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) { 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; } 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; action_t *stop = NULL; action_t *stopped = NULL; action_t *start = NULL; action_t *started = 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); crm_debug_2("Creating actions for %s", rsc->id); 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; } } /* 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; 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); } /* 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; 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); 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); } for(; gIter != NULL; gIter = gIter->next) { resource_t *child_rsc = (resource_t*)gIter->data; 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_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; } } static void assign_node(resource_t *rsc, node_t *node, gboolean force) { if(rsc->children) { 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; 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; } crm_trace("Looking for compatible child from %s for %s on %s", local_child->id, rsc->id, local_node->details->uname); 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); 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(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 { 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; } resource_t* find_compatible_child( resource_t *local_child, resource_t *rsc, enum rsc_role_e filter, gboolean current) { 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); } scratch = g_hash_table_get_values(local_child->allowed_nodes); scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL); 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; } } crm_debug("Can't pair %s with %s", local_child->id, rsc->id); done: g_list_free(scratch); return pair; } void clone_rsc_colocation_lh( 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 */ 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); 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); } return; } void clone_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { 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); 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; } } 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(do_interleave) { resource_t *rh_child = NULL; 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); } 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); } 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); } } 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); } } 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")) { /* 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); 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 { 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; } 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 || is_set(first_child->flags, pe_rsc_orphan), crm_err("No action found for %s in %s (first)", first_task, first_child->id)); if(then_action == NULL && is_not_set(then_child->flags, pe_rsc_orphan) && crm_str_eq(then->task, RSC_STOP, TRUE) == FALSE && crm_str_eq(then->task, RSC_DEMOTED, TRUE) == FALSE) { crm_err("Internal error: 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); 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) { GListPtr gIter = rsc->children; crm_debug_3("Processing location constraint %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); } } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { GListPtr gIter = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); 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->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 */ 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; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); 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) { 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) { 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) { 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) { 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; } 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 */ 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); 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); } 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; } } 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/native.c b/pengine/native.c index b49d122819..bc3b1c6d79 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -1,2527 +1,2528 @@ /* * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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); 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); 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, }, }; 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, }, }; 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; 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; } } static gboolean have_enough_capacity(node_t *node, resource_t *rsc) { struct capacity_data data; data.node = node; data.rsc = rsc; data.is_enough = TRUE; g_hash_table_foreach(rsc->utilization, check_capacity, &data); return data.is_enough; } static gboolean native_choose_node(resource_t *rsc, node_t *prefer, 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")) { 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); if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to?TRUE:FALSE; } if(prefer) { chosen = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id); if(chosen && chosen->weight >= 0 && can_run_resources(chosen)) { crm_trace("Using preferred node %s for %s instead of choosing from %d candidates", chosen->details->uname, rsc->id, length); } else if(chosen && chosen->weight < 0) { crm_trace("Preferred node %s for %s was unavailable", chosen->details->uname, rsc->id); chosen = NULL; } else if(chosen && can_run_resources(chosen)) { crm_trace("Preferred node %s for %s was unsuitable", chosen->details->uname, rsc->id); chosen = NULL; } else { crm_trace("Preferred node %s for %s was unknown", prefer->details->uname, rsc->id); } } if(chosen == NULL && 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); crm_trace("Chose node %s for %s from %d candidates", chosen?chosen->details->uname:"", rsc->id, length); 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 && running; lpc++) { node_t *tmp = g_list_nth_data(nodes, lpc); if(tmp->weight == chosen->weight) { multiple++; if(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); } 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; } } } 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); } 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)) { 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); } } g_hash_table_destroy(nodes); /* TODO: Free memory */ clear_bit(rsc->flags, pe_rsc_merging); return work; } node_t * native_color(resource_t *rsc, node_t *prefer, pe_working_set_t *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, prefer, 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); 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, NULL, 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); 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); } 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, prefer, 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); 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; xmlNode *operation = NULL; for(operation = __xml_first_child(rsc->ops_xml); operation != NULL; operation = __xml_next(operation)) { if(crm_str_eq((const char *)operation->name, "op", TRUE)) { 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; 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)); if(node != NULL) { node_uname = node->details->uname; } interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); interval_ms = crm_get_interval(interval); if(interval_ms == 0) { 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; } 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; } /* 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); } 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); } 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; } 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); } 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)); } 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, 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); } } } void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { if(is_not_set(data_set->flags, pe_flag_maintenance_mode)) { xmlNode *operation = NULL; for(operation = __xml_first_child(rsc->ops_xml); operation != NULL; operation = __xml_next(operation)) { if(crm_str_eq((const char *)operation->name, "op", TRUE)) { 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; 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)); 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; } get_rsc_attributes(rsc->parameters, rsc, chosen, data_set); 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); 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) { const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); pe_proc_err("Resource %s (%s::%s) is active on %d nodes %s", rsc->id, class, type, g_list_length(rsc->running_on), recovery2text(rsc->recovery_type)); cl_log(LOG_WARNING, "See %s for more information.", "http://clusterlabs.org/wiki/FAQ#Resource_is_Too_Active"); if(rsc->recovery_type == recovery_stop_start) { 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); GListPtr gIter = NULL; for(gIter = possible_matches; gIter != NULL; gIter = gIter->next) { action_t *action = (action_t*)gIter->data; 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; 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); } } 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 */ 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); 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); } 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; GListPtr gIter = NULL; crm_trace("Creating utilization constraints for %s - strategy: %s", rsc->id, data_set->placement_strategy); 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); } 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( 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) { if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } crm_debug_2("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id); rsc_rh->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) { 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", role2text(constraint->role_rh)); 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", role2text(constraint->role_rh)); 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", role2text(constraint->role_rh)); 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", role2text(constraint->role_rh)); return FALSE; } return TRUE; } static void colocation_match( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { const char *tmp = NULL; const char *value = NULL; const char *attribute = "#id"; GHashTable *work = NULL; gboolean do_check = FALSE; GHashTableIter iter; node_t *node = NULL; 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; } else if(constraint->score < 0) { /* nothing to do: * anti-colocation with something thats not running */ return; } 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); } } 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(work) { g_hash_table_destroy(work); } } void native_rsc_colocation_rh( 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); if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { 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; } 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"); } return; } 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_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) because of %s", then->uuid, then->node?then->node->details->uname:"[none]", then->flags, then_flags, first->uuid); } if(first_flags != first->flags) { changed |= pe_graph_updated_first; crm_trace("Flags for %s on %s are now 0x%.6x (were 0x%.6x) because of %s", first->uuid, first->node?first->node->details->uname:"[none]", first->flags, first_flags, then->uuid); } return changed; } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { 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); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } 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); 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); } } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { GListPtr gIter = NULL; crm_debug_3("Processing actions from %s", rsc->id); 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); } 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); } } void + LogActions(resource_t *rsc, pe_working_set_t *data_set) { node_t *next = NULL; node_t *current = NULL; action_t *stop = NULL; action_t *start = NULL; char *key = NULL; gboolean moving = FALSE; GListPtr possible_matches = NULL; if(rsc->children) { 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 %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; } key = stop_key(rsc); possible_matches = find_actions(rsc->actions, key, next); crm_free(key); if(possible_matches) { stop = possible_matches->data; g_list_free(possible_matches); } key = start_key(rsc); possible_matches = find_actions(rsc->actions, key, next); crm_free(key); if(possible_matches) { start = possible_matches->data; g_list_free(possible_matches); } if(rsc->role == rsc->next_role) { 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 %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 %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else if(moving && current) { crm_notice("Move %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 %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 %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else { crm_notice("Restart %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(stop != NULL && is_not_set(stop->flags, pe_action_optional) && rsc->next_role > RSC_ROLE_STOPPED) { if(is_set(rsc->flags, pe_rsc_failed)) { crm_notice("Recover %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else { crm_notice("Restart %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } } } } else if(rsc->next_role == RSC_ROLE_STOPPED) { GListPtr gIter = NULL; CRM_CHECK(current != NULL,); for(gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) { node_t *node = (node_t*)gIter->data; crm_notice("Stop %s\t(%s)", rsc->id, node->details->uname); } } if(moving) { crm_notice("Move %s\t(%s %s -> %s)", rsc->id, role2text(rsc->next_role), current->details->uname, next->details->uname); } if(rsc->role == RSC_ROLE_STOPPED) { 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,); if(stop != NULL && is_not_set(stop->flags, pe_action_optional) && rsc->role > RSC_ROLE_STOPPED) { if(is_set(rsc->flags, pe_rsc_failed)) { crm_notice("Recover %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else { crm_notice("Restart %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } } 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) { 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)); if(current == NULL || next == NULL) { return; } 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); } 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); } 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) { 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); } 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); } } return TRUE; } gboolean StartRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { 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; } gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { char *key = NULL; GListPtr gIter = 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); CRM_CHECK(next != NULL, return FALSE); key = start_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); 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; } 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); 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; } gboolean DemoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { GListPtr gIter = NULL; crm_debug_2("Executing: %s", rsc->id); /* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */ 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; } 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; } gboolean DeleteRsc(resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set) { action_t *delete = NULL; #if DELETE_THEN_REFRESH 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; } 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; } crm_notice("Removing %s from %s", rsc->id, node->details->uname); 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_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); add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); order_actions(delete, refresh, pe_order_optional); #endif 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); 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); } 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) { GListPtr gIter = NULL; gboolean any_created = FALSE; 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; } return any_created; } 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); } } 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); /* * We need to know if it's running_on (not just known_on) this node * to correctly determine the target rc. */ running = pe_find_node_id(rsc->running_on, node->details->id); 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); } 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; } static void native_start_constraints( 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; 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); } 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); } } } } static void native_stop_constraints( resource_t *rsc, action_t *stonith_op, gboolean is_stonith, pe_working_set_t *data_set) { 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); /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ 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); } /* 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); 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); } /* 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); * 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); key = demote_key(rsc); action_list = find_actions(rsc->actions, key, stonith_op->node); crm_free(key); 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); } void rsc_stonith_ordering( 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); 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(stonith_op != NULL && safe_str_eq(class, "stonith")) { is_stonith = TRUE; } /* Start constraints */ native_start_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) { 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; 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) ## Resource Activity During Move N1 N2 N3 --- --- --- t0 A.stop t1 B.stop B.stop t2 B.start B.start t3 A.start ## 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 Node 1: Rewritten to be a migrate-to operation Node 2: Rewritten to be a migrate-from operation # Constraints 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 c) A.stop -> B.stop - ok d) B.start -> A.start - ok 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 */ /* 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); 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; } } } 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; 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; 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); 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); } 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); 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); 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); 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); 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; } 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); } } 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 */ 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); /* 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); add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->uname); add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->uname); add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->uname); add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->uname); /* Create the correct ordering ajustments based on find_clone_activity_on(); */ 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 0 crm_debug("Creating %s.start -> %s.stop ordering", rsc->id, target->id); order_actions(from, clone_stop, pe_order_optional); #endif 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) { #if 0 crm_debug("Creating %s.started -> %s.stop ordering", target->id, rsc->id); order_actions(clone_start, to, pe_order_optional); #endif 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 */ /* 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 */ 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 */ 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; 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); } } 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/test10/bug-1765.scores b/pengine/test10/bug-1765.scores index 440bfeaa29..20bfa5d40c 100644 --- a/pengine/test10/bug-1765.scores +++ b/pengine/test10/bug-1765.scores @@ -1,33 +1,36 @@ Allocation scores: clone_color: drbd0:0 allocation score on sles236: 76 clone_color: drbd0:0 allocation score on sles238: 0 clone_color: drbd0:1 allocation score on sles236: 0 clone_color: drbd0:1 allocation score on sles238: 0 clone_color: drbd1:0 allocation score on sles236: 76 clone_color: drbd1:0 allocation score on sles238: 0 clone_color: drbd1:1 allocation score on sles236: 0 clone_color: drbd1:1 allocation score on sles238: 76 clone_color: ms-drbd0 allocation score on sles236: 0 clone_color: ms-drbd0 allocation score on sles238: 0 clone_color: ms-drbd1 allocation score on sles236: 0 clone_color: ms-drbd1 allocation score on sles238: 0 drbd0:0 promotion score on sles236: INFINITY drbd0:1 promotion score on sles238: -INFINITY drbd0:2 promotion score on none: 0 drbd1:0 promotion score on sles236: 75 drbd1:0 promotion score on sles236: INFINITY drbd1:0 promotion score on sles236: INFINITY +drbd1:0 promotion score on sles236: INFINITY +drbd1:1 promotion score on sles238: -INFINITY drbd1:1 promotion score on sles238: -INFINITY drbd1:1 promotion score on sles238: -INFINITY drbd1:1 promotion score on sles238: 75 drbd1:2 promotion score on none: 0 drbd1:2 promotion score on none: 0 drbd1:2 promotion score on none: 0 +drbd1:2 promotion score on none: 0 native_color: drbd0:0 allocation score on sles236: 76 native_color: drbd0:0 allocation score on sles238: 0 native_color: drbd0:1 allocation score on sles236: -INFINITY native_color: drbd0:1 allocation score on sles238: 0 native_color: drbd1:0 allocation score on sles236: 76 native_color: drbd1:0 allocation score on sles238: -INFINITY native_color: drbd1:1 allocation score on sles236: 0 native_color: drbd1:1 allocation score on sles238: 76 diff --git a/pengine/test10/bug-lf-2358.scores b/pengine/test10/bug-lf-2358.scores index bdad3e6905..4e74fcaba5 100644 --- a/pengine/test10/bug-lf-2358.scores +++ b/pengine/test10/bug-lf-2358.scores @@ -1,89 +1,91 @@ Allocation scores: clone_color: ms_drbd_mysql1 allocation score on alice.demo: 0 clone_color: ms_drbd_mysql1 allocation score on bob.demo: 0 clone_color: ms_drbd_mysql2 allocation score on alice.demo: 0 clone_color: ms_drbd_mysql2 allocation score on bob.demo: 0 clone_color: ms_drbd_nfsexport allocation score on alice.demo: 0 clone_color: ms_drbd_nfsexport allocation score on bob.demo: 0 clone_color: res_drbd_mysql1:0 allocation score on alice.demo: 0 clone_color: res_drbd_mysql1:0 allocation score on bob.demo: 10001 clone_color: res_drbd_mysql1:1 allocation score on alice.demo: 0 clone_color: res_drbd_mysql1:1 allocation score on bob.demo: 0 clone_color: res_drbd_mysql2:0 allocation score on alice.demo: 10001 clone_color: res_drbd_mysql2:0 allocation score on bob.demo: 0 clone_color: res_drbd_mysql2:1 allocation score on alice.demo: 0 clone_color: res_drbd_mysql2:1 allocation score on bob.demo: 10001 clone_color: res_drbd_nfsexport:0 allocation score on alice.demo: 0 clone_color: res_drbd_nfsexport:0 allocation score on bob.demo: 0 clone_color: res_drbd_nfsexport:1 allocation score on alice.demo: 0 clone_color: res_drbd_nfsexport:1 allocation score on bob.demo: 0 group_color: res_fs_mysql1 allocation score on alice.demo: 0 group_color: res_fs_mysql1 allocation score on bob.demo: 0 group_color: res_fs_mysql2 allocation score on alice.demo: 0 group_color: res_fs_mysql2 allocation score on bob.demo: 0 group_color: res_fs_nfsexport allocation score on alice.demo: 0 group_color: res_fs_nfsexport allocation score on bob.demo: 0 group_color: res_ip_mysql1 allocation score on alice.demo: 0 group_color: res_ip_mysql1 allocation score on bob.demo: 0 group_color: res_ip_mysql2 allocation score on alice.demo: 0 group_color: res_ip_mysql2 allocation score on bob.demo: 0 group_color: res_ip_nfs allocation score on alice.demo: 0 group_color: res_ip_nfs allocation score on bob.demo: 0 group_color: res_mysql1 allocation score on alice.demo: 0 group_color: res_mysql1 allocation score on bob.demo: 0 group_color: res_mysql2 allocation score on alice.demo: 0 group_color: res_mysql2 allocation score on bob.demo: 0 group_color: res_nfs allocation score on alice.demo: 0 group_color: res_nfs allocation score on bob.demo: 0 group_color: rg_mysql1 allocation score on alice.demo: 0 group_color: rg_mysql1 allocation score on bob.demo: 0 group_color: rg_mysql2 allocation score on alice.demo: 0 group_color: rg_mysql2 allocation score on bob.demo: 0 group_color: rg_nfs allocation score on alice.demo: 0 group_color: rg_nfs allocation score on bob.demo: 0 native_color: res_drbd_mysql1:0 allocation score on alice.demo: -INFINITY native_color: res_drbd_mysql1:0 allocation score on bob.demo: 10001 native_color: res_drbd_mysql1:1 allocation score on alice.demo: 0 native_color: res_drbd_mysql1:1 allocation score on bob.demo: -INFINITY native_color: res_drbd_mysql2:0 allocation score on alice.demo: 10001 native_color: res_drbd_mysql2:0 allocation score on bob.demo: 0 native_color: res_drbd_mysql2:1 allocation score on alice.demo: -INFINITY native_color: res_drbd_mysql2:1 allocation score on bob.demo: 10001 native_color: res_drbd_nfsexport:0 allocation score on alice.demo: -INFINITY native_color: res_drbd_nfsexport:0 allocation score on bob.demo: -INFINITY native_color: res_drbd_nfsexport:1 allocation score on alice.demo: -INFINITY native_color: res_drbd_nfsexport:1 allocation score on bob.demo: -INFINITY native_color: res_fs_mysql1 allocation score on alice.demo: -INFINITY native_color: res_fs_mysql1 allocation score on bob.demo: 10001 native_color: res_fs_mysql2 allocation score on alice.demo: 10001 native_color: res_fs_mysql2 allocation score on bob.demo: -INFINITY native_color: res_fs_nfsexport allocation score on alice.demo: -INFINITY native_color: res_fs_nfsexport allocation score on bob.demo: -INFINITY native_color: res_ip_mysql1 allocation score on alice.demo: -INFINITY native_color: res_ip_mysql1 allocation score on bob.demo: 0 native_color: res_ip_mysql2 allocation score on alice.demo: 0 native_color: res_ip_mysql2 allocation score on bob.demo: -INFINITY native_color: res_ip_nfs allocation score on alice.demo: -INFINITY native_color: res_ip_nfs allocation score on bob.demo: -INFINITY native_color: res_mysql1 allocation score on alice.demo: -INFINITY native_color: res_mysql1 allocation score on bob.demo: 0 native_color: res_mysql2 allocation score on alice.demo: 0 native_color: res_mysql2 allocation score on bob.demo: -INFINITY native_color: res_nfs allocation score on alice.demo: -INFINITY native_color: res_nfs allocation score on bob.demo: -INFINITY res_drbd_mysql1:0 promotion score on bob.demo: 0 res_drbd_mysql1:0 promotion score on bob.demo: INFINITY res_drbd_mysql1:1 promotion score on alice.demo: -INFINITY res_drbd_mysql1:1 promotion score on alice.demo: -INFINITY res_drbd_mysql2:0 promotion score on alice.demo: 10000 res_drbd_mysql2:0 promotion score on alice.demo: INFINITY res_drbd_mysql2:0 promotion score on alice.demo: INFINITY res_drbd_mysql2:0 promotion score on alice.demo: INFINITY +res_drbd_mysql2:0 promotion score on alice.demo: INFINITY +res_drbd_mysql2:1 promotion score on bob.demo: -INFINITY res_drbd_mysql2:1 promotion score on bob.demo: -INFINITY res_drbd_mysql2:1 promotion score on bob.demo: -INFINITY res_drbd_mysql2:1 promotion score on bob.demo: -INFINITY res_drbd_mysql2:1 promotion score on bob.demo: 10000 res_drbd_nfsexport:0 promotion score on none: 0 res_drbd_nfsexport:0 promotion score on none: 0 res_drbd_nfsexport:1 promotion score on none: 0 res_drbd_nfsexport:1 promotion score on none: 0 diff --git a/pengine/test10/coloc-clone-stays-active.scores b/pengine/test10/coloc-clone-stays-active.scores index a29d2f2862..4d588a23b1 100644 --- a/pengine/test10/coloc-clone-stays-active.scores +++ b/pengine/test10/coloc-clone-stays-active.scores @@ -1,531 +1,541 @@ Allocation scores: clone_color: cl-clvmd allocation score on s01-0: 0 clone_color: cl-clvmd allocation score on s01-1: 0 clone_color: cl-dhcpd allocation score on s01-0: 0 clone_color: cl-dhcpd allocation score on s01-1: 0 clone_color: cl-dlm allocation score on s01-0: 0 clone_color: cl-dlm allocation score on s01-1: 0 clone_color: cl-drbdlinks-s01-service allocation score on s01-0: 0 clone_color: cl-drbdlinks-s01-service allocation score on s01-1: 0 clone_color: cl-gfs2 allocation score on s01-0: 0 clone_color: cl-gfs2 allocation score on s01-1: 0 clone_color: cl-ietd allocation score on s01-0: 1000 clone_color: cl-ietd allocation score on s01-1: 1000 clone_color: cl-libvirtd allocation score on s01-0: 0 clone_color: cl-libvirtd allocation score on s01-1: 0 clone_color: cl-o2cb allocation score on s01-0: 0 clone_color: cl-o2cb allocation score on s01-1: 0 clone_color: cl-ospf-routing allocation score on s01-0: 0 clone_color: cl-ospf-routing allocation score on s01-1: 0 clone_color: cl-s01-logs-fs allocation score on s01-0: 0 clone_color: cl-s01-logs-fs allocation score on s01-1: 0 clone_color: cl-s01-service-fs allocation score on s01-0: 0 clone_color: cl-s01-service-fs allocation score on s01-1: 0 clone_color: cl-s01-vm-data-metadata-fs allocation score on s01-0: 0 clone_color: cl-s01-vm-data-metadata-fs allocation score on s01-1: 0 clone_color: cl-s01-vm-data-storage-pool allocation score on s01-0: 0 clone_color: cl-s01-vm-data-storage-pool allocation score on s01-1: 0 clone_color: cl-vds-http-fs allocation score on s01-0: 0 clone_color: cl-vds-http-fs allocation score on s01-1: 0 clone_color: cl-vds-tftpboot-fs allocation score on s01-0: 0 clone_color: cl-vds-tftpboot-fs allocation score on s01-1: 0 clone_color: cl-vg-s01-vm-data allocation score on s01-0: 0 clone_color: cl-vg-s01-vm-data allocation score on s01-1: 0 clone_color: cl-xinetd allocation score on s01-0: 0 clone_color: cl-xinetd allocation score on s01-1: 0 clone_color: clvmd:0 allocation score on s01-0: 0 clone_color: clvmd:0 allocation score on s01-1: 1 clone_color: clvmd:1 allocation score on s01-0: 1 clone_color: clvmd:1 allocation score on s01-1: 0 clone_color: connected-outer allocation score on s01-0: 0 clone_color: connected-outer allocation score on s01-1: 0 clone_color: dhcpd:0 allocation score on s01-0: 0 clone_color: dhcpd:0 allocation score on s01-1: 0 clone_color: dhcpd:1 allocation score on s01-0: 0 clone_color: dhcpd:1 allocation score on s01-1: 0 clone_color: dlm:0 allocation score on s01-0: 1 clone_color: dlm:0 allocation score on s01-1: 0 clone_color: dlm:1 allocation score on s01-0: 0 clone_color: dlm:1 allocation score on s01-1: 1 clone_color: drbd-pool-0:0 allocation score on s01-0: 10001 clone_color: drbd-pool-0:0 allocation score on s01-1: 0 clone_color: drbd-pool-0:1 allocation score on s01-0: 0 clone_color: drbd-pool-0:1 allocation score on s01-1: 10001 clone_color: drbd-pool-1:0 allocation score on s01-0: 10001 clone_color: drbd-pool-1:0 allocation score on s01-1: 0 clone_color: drbd-pool-1:1 allocation score on s01-0: 0 clone_color: drbd-pool-1:1 allocation score on s01-1: 10001 clone_color: drbd-s01-logs:0 allocation score on s01-0: 0 clone_color: drbd-s01-logs:0 allocation score on s01-1: 10001 clone_color: drbd-s01-logs:1 allocation score on s01-0: 10001 clone_color: drbd-s01-logs:1 allocation score on s01-1: 0 clone_color: drbd-s01-service:0 allocation score on s01-0: 0 clone_color: drbd-s01-service:0 allocation score on s01-1: 10001 clone_color: drbd-s01-service:1 allocation score on s01-0: 10001 clone_color: drbd-s01-service:1 allocation score on s01-1: 0 clone_color: drbd-s01-vm-data:0 allocation score on s01-0: 0 clone_color: drbd-s01-vm-data:0 allocation score on s01-1: 10001 clone_color: drbd-s01-vm-data:1 allocation score on s01-0: 10001 clone_color: drbd-s01-vm-data:1 allocation score on s01-1: 0 clone_color: drbd-vds-dom0-stateless-0:0 allocation score on s01-0: 0 clone_color: drbd-vds-dom0-stateless-0:0 allocation score on s01-1: 10001 clone_color: drbd-vds-dom0-stateless-0:1 allocation score on s01-0: 10001 clone_color: drbd-vds-dom0-stateless-0:1 allocation score on s01-1: 0 clone_color: drbd-vds-http:0 allocation score on s01-0: 0 clone_color: drbd-vds-http:0 allocation score on s01-1: 10001 clone_color: drbd-vds-http:1 allocation score on s01-0: 10001 clone_color: drbd-vds-http:1 allocation score on s01-1: 0 clone_color: drbd-vds-tftpboot:0 allocation score on s01-0: 0 clone_color: drbd-vds-tftpboot:0 allocation score on s01-1: 10001 clone_color: drbd-vds-tftpboot:1 allocation score on s01-0: 10001 clone_color: drbd-vds-tftpboot:1 allocation score on s01-1: 0 clone_color: drbdlinks-s01-service:0 allocation score on s01-0: 0 clone_color: drbdlinks-s01-service:0 allocation score on s01-1: 1 clone_color: drbdlinks-s01-service:1 allocation score on s01-0: 1 clone_color: drbdlinks-s01-service:1 allocation score on s01-1: 0 clone_color: gfs2:0 allocation score on s01-0: 1 clone_color: gfs2:0 allocation score on s01-1: 0 clone_color: gfs2:1 allocation score on s01-0: 0 clone_color: gfs2:1 allocation score on s01-1: 1 clone_color: ietd:0 allocation score on s01-0: 1 clone_color: ietd:0 allocation score on s01-1: 0 clone_color: ietd:1 allocation score on s01-0: 0 clone_color: ietd:1 allocation score on s01-1: 1 clone_color: iscsi-pool-0-vips-fw:0 allocation score on s01-0: 2000 clone_color: iscsi-pool-0-vips-fw:0 allocation score on s01-1: 0 clone_color: iscsi-pool-0-vips-fw:1 allocation score on s01-0: 0 clone_color: iscsi-pool-0-vips-fw:1 allocation score on s01-1: 2000 clone_color: iscsi-pool-1-vips-fw:0 allocation score on s01-0: 2000 clone_color: iscsi-pool-1-vips-fw:0 allocation score on s01-1: 0 clone_color: iscsi-pool-1-vips-fw:1 allocation score on s01-0: 0 clone_color: iscsi-pool-1-vips-fw:1 allocation score on s01-1: 2000 clone_color: iscsi-vds-dom0-stateless-0-vips-fw:0 allocation score on s01-0: 2000 clone_color: iscsi-vds-dom0-stateless-0-vips-fw:0 allocation score on s01-1: 0 clone_color: iscsi-vds-dom0-stateless-0-vips-fw:1 allocation score on s01-0: 0 clone_color: iscsi-vds-dom0-stateless-0-vips-fw:1 allocation score on s01-1: 2000 clone_color: libvirtd:0 allocation score on s01-0: 0 clone_color: libvirtd:0 allocation score on s01-1: 1 clone_color: libvirtd:1 allocation score on s01-0: 1 clone_color: libvirtd:1 allocation score on s01-1: 0 clone_color: ms-drbd-pool-0 allocation score on s01-0: 1000 clone_color: ms-drbd-pool-0 allocation score on s01-1: 0 clone_color: ms-drbd-pool-1 allocation score on s01-0: 0 clone_color: ms-drbd-pool-1 allocation score on s01-1: 1000 clone_color: ms-drbd-s01-logs allocation score on s01-0: 0 clone_color: ms-drbd-s01-logs allocation score on s01-1: 0 clone_color: ms-drbd-s01-service allocation score on s01-0: 0 clone_color: ms-drbd-s01-service allocation score on s01-1: 0 clone_color: ms-drbd-s01-vm-data allocation score on s01-0: 0 clone_color: ms-drbd-s01-vm-data allocation score on s01-1: 0 clone_color: ms-drbd-vds-dom0-stateless-0 allocation score on s01-0: 0 clone_color: ms-drbd-vds-dom0-stateless-0 allocation score on s01-1: 0 clone_color: ms-drbd-vds-http allocation score on s01-0: 0 clone_color: ms-drbd-vds-http allocation score on s01-1: 0 clone_color: ms-drbd-vds-tftpboot allocation score on s01-0: 0 clone_color: ms-drbd-vds-tftpboot allocation score on s01-1: 0 clone_color: ms-iscsi-pool-0-vips-fw allocation score on s01-0: 0 clone_color: ms-iscsi-pool-0-vips-fw allocation score on s01-1: 0 clone_color: ms-iscsi-pool-1-vips-fw allocation score on s01-0: 0 clone_color: ms-iscsi-pool-1-vips-fw allocation score on s01-1: 0 clone_color: ms-iscsi-vds-dom0-stateless-0-vips-fw allocation score on s01-0: 0 clone_color: ms-iscsi-vds-dom0-stateless-0-vips-fw allocation score on s01-1: 0 clone_color: o2cb:0 allocation score on s01-0: 0 clone_color: o2cb:0 allocation score on s01-1: 0 clone_color: o2cb:1 allocation score on s01-0: 0 clone_color: o2cb:1 allocation score on s01-1: 0 clone_color: ospf-routing:0 allocation score on s01-0: 0 clone_color: ospf-routing:0 allocation score on s01-1: 0 clone_color: ospf-routing:1 allocation score on s01-0: 0 clone_color: ospf-routing:1 allocation score on s01-1: 0 clone_color: ospfd:0 allocation score on s01-0: 1 clone_color: ospfd:0 allocation score on s01-1: 0 clone_color: ospfd:1 allocation score on s01-0: 0 clone_color: ospfd:1 allocation score on s01-1: 1 clone_color: ping-bmc-and-switch:0 allocation score on s01-0: 1 clone_color: ping-bmc-and-switch:0 allocation score on s01-1: 0 clone_color: ping-bmc-and-switch:1 allocation score on s01-0: 0 clone_color: ping-bmc-and-switch:1 allocation score on s01-1: 1 clone_color: s01-logs-fs:0 allocation score on s01-0: 1 clone_color: s01-logs-fs:0 allocation score on s01-1: 0 clone_color: s01-logs-fs:1 allocation score on s01-0: 0 clone_color: s01-logs-fs:1 allocation score on s01-1: 1 clone_color: s01-service-fs:0 allocation score on s01-0: 0 clone_color: s01-service-fs:0 allocation score on s01-1: 1 clone_color: s01-service-fs:1 allocation score on s01-0: 1 clone_color: s01-service-fs:1 allocation score on s01-1: 0 clone_color: s01-vm-data-metadata-fs:0 allocation score on s01-0: 0 clone_color: s01-vm-data-metadata-fs:0 allocation score on s01-1: 1 clone_color: s01-vm-data-metadata-fs:1 allocation score on s01-0: 1 clone_color: s01-vm-data-metadata-fs:1 allocation score on s01-1: 0 clone_color: s01-vm-data-storage-pool:0 allocation score on s01-0: 0 clone_color: s01-vm-data-storage-pool:0 allocation score on s01-1: 1 clone_color: s01-vm-data-storage-pool:1 allocation score on s01-0: 1 clone_color: s01-vm-data-storage-pool:1 allocation score on s01-1: 0 clone_color: vds-http-fs:0 allocation score on s01-0: 0 clone_color: vds-http-fs:0 allocation score on s01-1: 1 clone_color: vds-http-fs:1 allocation score on s01-0: 1 clone_color: vds-http-fs:1 allocation score on s01-1: 0 clone_color: vds-tftpboot-fs:0 allocation score on s01-0: 0 clone_color: vds-tftpboot-fs:0 allocation score on s01-1: 0 clone_color: vds-tftpboot-fs:1 allocation score on s01-0: 0 clone_color: vds-tftpboot-fs:1 allocation score on s01-1: 0 clone_color: vg-s01-vm-data:0 allocation score on s01-0: 0 clone_color: vg-s01-vm-data:0 allocation score on s01-1: 1 clone_color: vg-s01-vm-data:1 allocation score on s01-0: 1 clone_color: vg-s01-vm-data:1 allocation score on s01-1: 0 clone_color: vip-227-fw:0 allocation score on s01-0: 1 clone_color: vip-227-fw:0 allocation score on s01-1: 0 clone_color: vip-227-fw:1 allocation score on s01-0: 0 clone_color: vip-227-fw:1 allocation score on s01-1: 1 clone_color: vip-228-fw:0 allocation score on s01-0: 1 clone_color: vip-228-fw:0 allocation score on s01-1: 0 clone_color: vip-228-fw:1 allocation score on s01-0: 0 clone_color: vip-228-fw:1 allocation score on s01-1: 1 clone_color: vip-235-fw:0 allocation score on s01-0: 1 clone_color: vip-235-fw:0 allocation score on s01-1: 0 clone_color: vip-235-fw:1 allocation score on s01-0: 0 clone_color: vip-235-fw:1 allocation score on s01-1: 1 clone_color: vip-236-fw:0 allocation score on s01-0: 1 clone_color: vip-236-fw:0 allocation score on s01-1: 0 clone_color: vip-236-fw:1 allocation score on s01-0: 0 clone_color: vip-236-fw:1 allocation score on s01-1: 1 clone_color: vip-237-fw:0 allocation score on s01-0: 1 clone_color: vip-237-fw:0 allocation score on s01-1: 0 clone_color: vip-237-fw:1 allocation score on s01-0: 0 clone_color: vip-237-fw:1 allocation score on s01-1: 1 clone_color: vip-238-fw:0 allocation score on s01-0: 1 clone_color: vip-238-fw:0 allocation score on s01-1: 0 clone_color: vip-238-fw:1 allocation score on s01-0: 0 clone_color: vip-238-fw:1 allocation score on s01-1: 1 clone_color: xinetd:0 allocation score on s01-0: 1 clone_color: xinetd:0 allocation score on s01-1: 0 clone_color: xinetd:1 allocation score on s01-0: 0 clone_color: xinetd:1 allocation score on s01-1: 1 clone_color: zebra:0 allocation score on s01-0: 1 clone_color: zebra:0 allocation score on s01-1: 0 clone_color: zebra:1 allocation score on s01-0: 0 clone_color: zebra:1 allocation score on s01-1: 1 drbd-pool-0:0 promotion score on s01-0: 12000 drbd-pool-0:0 promotion score on s01-0: INFINITY drbd-pool-0:1 promotion score on s01-1: -INFINITY drbd-pool-0:1 promotion score on s01-1: 10000 drbd-pool-1:0 promotion score on s01-0: -INFINITY drbd-pool-1:0 promotion score on s01-0: 10000 drbd-pool-1:1 promotion score on s01-1: 12000 drbd-pool-1:1 promotion score on s01-1: INFINITY drbd-s01-logs:0 promotion score on s01-1: 10000 drbd-s01-logs:0 promotion score on s01-1: INFINITY drbd-s01-logs:0 promotion score on s01-1: INFINITY +drbd-s01-logs:0 promotion score on s01-1: INFINITY drbd-s01-logs:1 promotion score on s01-0: 10000 drbd-s01-logs:1 promotion score on s01-0: INFINITY drbd-s01-logs:1 promotion score on s01-0: INFINITY +drbd-s01-logs:1 promotion score on s01-0: INFINITY drbd-s01-service:0 promotion score on s01-1: 10000 drbd-s01-service:0 promotion score on s01-1: INFINITY drbd-s01-service:0 promotion score on s01-1: INFINITY +drbd-s01-service:0 promotion score on s01-1: INFINITY drbd-s01-service:1 promotion score on s01-0: 10000 drbd-s01-service:1 promotion score on s01-0: INFINITY drbd-s01-service:1 promotion score on s01-0: INFINITY +drbd-s01-service:1 promotion score on s01-0: INFINITY drbd-s01-vm-data:0 promotion score on s01-1: 10000 drbd-s01-vm-data:0 promotion score on s01-1: INFINITY drbd-s01-vm-data:0 promotion score on s01-1: INFINITY +drbd-s01-vm-data:0 promotion score on s01-1: INFINITY drbd-s01-vm-data:1 promotion score on s01-0: 1 drbd-s01-vm-data:1 promotion score on s01-0: INFINITY drbd-s01-vm-data:1 promotion score on s01-0: INFINITY +drbd-s01-vm-data:1 promotion score on s01-0: INFINITY drbd-vds-dom0-stateless-0:0 promotion score on s01-1: -INFINITY drbd-vds-dom0-stateless-0:0 promotion score on s01-1: 10000 drbd-vds-dom0-stateless-0:1 promotion score on s01-0: 10000 drbd-vds-dom0-stateless-0:1 promotion score on s01-0: INFINITY drbd-vds-http:0 promotion score on s01-1: 10000 drbd-vds-http:0 promotion score on s01-1: INFINITY drbd-vds-http:0 promotion score on s01-1: INFINITY +drbd-vds-http:0 promotion score on s01-1: INFINITY drbd-vds-http:1 promotion score on s01-0: 10000 drbd-vds-http:1 promotion score on s01-0: INFINITY drbd-vds-http:1 promotion score on s01-0: INFINITY +drbd-vds-http:1 promotion score on s01-0: INFINITY drbd-vds-tftpboot:0 promotion score on s01-1: 10000 drbd-vds-tftpboot:0 promotion score on s01-1: INFINITY drbd-vds-tftpboot:0 promotion score on s01-1: INFINITY +drbd-vds-tftpboot:0 promotion score on s01-1: INFINITY drbd-vds-tftpboot:1 promotion score on s01-0: 10000 drbd-vds-tftpboot:1 promotion score on s01-0: INFINITY drbd-vds-tftpboot:1 promotion score on s01-0: INFINITY +drbd-vds-tftpboot:1 promotion score on s01-0: INFINITY group_color: http-server allocation score on s01-0: 0 group_color: http-server allocation score on s01-1: 0 group_color: iscsi-pool-0-lun-1 allocation score on s01-0: 0 group_color: iscsi-pool-0-lun-1 allocation score on s01-1: 0 group_color: iscsi-pool-0-target allocation score on s01-0: 1000 group_color: iscsi-pool-0-target allocation score on s01-1: 0 group_color: iscsi-pool-0-target-all allocation score on s01-0: 1000 group_color: iscsi-pool-0-target-all allocation score on s01-1: 0 group_color: iscsi-pool-0-vips allocation score on s01-0: 0 group_color: iscsi-pool-0-vips allocation score on s01-1: 0 group_color: iscsi-pool-0-vips-fw:0 allocation score on s01-0: 2000 group_color: iscsi-pool-0-vips-fw:0 allocation score on s01-1: 0 group_color: iscsi-pool-0-vips-fw:1 allocation score on s01-0: -INFINITY group_color: iscsi-pool-0-vips-fw:1 allocation score on s01-1: 2000 group_color: iscsi-pool-1-lun-1 allocation score on s01-0: 0 group_color: iscsi-pool-1-lun-1 allocation score on s01-1: 0 group_color: iscsi-pool-1-target allocation score on s01-0: 0 group_color: iscsi-pool-1-target allocation score on s01-1: 1000 group_color: iscsi-pool-1-target-all allocation score on s01-0: 0 group_color: iscsi-pool-1-target-all allocation score on s01-1: 1000 group_color: iscsi-pool-1-vips allocation score on s01-0: 0 group_color: iscsi-pool-1-vips allocation score on s01-1: 0 group_color: iscsi-pool-1-vips-fw:0 allocation score on s01-0: 2000 group_color: iscsi-pool-1-vips-fw:0 allocation score on s01-1: 0 group_color: iscsi-pool-1-vips-fw:1 allocation score on s01-0: -INFINITY group_color: iscsi-pool-1-vips-fw:1 allocation score on s01-1: 2000 group_color: iscsi-vds-dom0-stateless-0-lun-1 allocation score on s01-0: 0 group_color: iscsi-vds-dom0-stateless-0-lun-1 allocation score on s01-1: 0 group_color: iscsi-vds-dom0-stateless-0-target allocation score on s01-0: 0 group_color: iscsi-vds-dom0-stateless-0-target allocation score on s01-1: 0 group_color: iscsi-vds-dom0-stateless-0-target-all allocation score on s01-0: 0 group_color: iscsi-vds-dom0-stateless-0-target-all allocation score on s01-1: 0 group_color: iscsi-vds-dom0-stateless-0-vips allocation score on s01-0: 0 group_color: iscsi-vds-dom0-stateless-0-vips allocation score on s01-1: 0 group_color: iscsi-vds-dom0-stateless-0-vips-fw:0 allocation score on s01-0: 2000 group_color: iscsi-vds-dom0-stateless-0-vips-fw:0 allocation score on s01-1: 0 group_color: iscsi-vds-dom0-stateless-0-vips-fw:1 allocation score on s01-0: -INFINITY group_color: iscsi-vds-dom0-stateless-0-vips-fw:1 allocation score on s01-1: 2000 group_color: nginx allocation score on s01-0: 0 group_color: nginx allocation score on s01-1: 0 group_color: ospf-routing:0 allocation score on s01-0: 0 group_color: ospf-routing:0 allocation score on s01-1: 0 group_color: ospf-routing:1 allocation score on s01-0: -INFINITY group_color: ospf-routing:1 allocation score on s01-1: 0 group_color: ospfd:0 allocation score on s01-0: 1 group_color: ospfd:0 allocation score on s01-1: 0 group_color: ospfd:1 allocation score on s01-0: -INFINITY group_color: ospfd:1 allocation score on s01-1: 1 group_color: syslog-ng allocation score on s01-0: 0 group_color: syslog-ng allocation score on s01-1: 0 group_color: syslog-server allocation score on s01-0: 0 group_color: syslog-server allocation score on s01-1: 0 group_color: tftp-server allocation score on s01-0: 0 group_color: tftp-server allocation score on s01-1: 0 group_color: tftpd allocation score on s01-0: 0 group_color: tftpd allocation score on s01-1: 0 group_color: vip-227 allocation score on s01-0: 0 group_color: vip-227 allocation score on s01-1: 0 group_color: vip-227-fw:0 allocation score on s01-0: 1 group_color: vip-227-fw:0 allocation score on s01-1: 0 group_color: vip-227-fw:1 allocation score on s01-0: -INFINITY group_color: vip-227-fw:1 allocation score on s01-1: 1 group_color: vip-228 allocation score on s01-0: 0 group_color: vip-228 allocation score on s01-1: 0 group_color: vip-228-fw:0 allocation score on s01-0: 1 group_color: vip-228-fw:0 allocation score on s01-1: 0 group_color: vip-228-fw:1 allocation score on s01-0: -INFINITY group_color: vip-228-fw:1 allocation score on s01-1: 1 group_color: vip-232 allocation score on s01-0: 0 group_color: vip-232 allocation score on s01-1: 0 group_color: vip-233 allocation score on s01-0: 0 group_color: vip-233 allocation score on s01-1: 0 group_color: vip-234 allocation score on s01-0: 0 group_color: vip-234 allocation score on s01-1: 0 group_color: vip-235 allocation score on s01-0: 0 group_color: vip-235 allocation score on s01-1: 0 group_color: vip-235-fw:0 allocation score on s01-0: 1 group_color: vip-235-fw:0 allocation score on s01-1: 0 group_color: vip-235-fw:1 allocation score on s01-0: -INFINITY group_color: vip-235-fw:1 allocation score on s01-1: 1 group_color: vip-236 allocation score on s01-0: 0 group_color: vip-236 allocation score on s01-1: 0 group_color: vip-236-fw:0 allocation score on s01-0: 1 group_color: vip-236-fw:0 allocation score on s01-1: 0 group_color: vip-236-fw:1 allocation score on s01-0: -INFINITY group_color: vip-236-fw:1 allocation score on s01-1: 1 group_color: vip-237 allocation score on s01-0: 0 group_color: vip-237 allocation score on s01-1: 0 group_color: vip-237-fw:0 allocation score on s01-0: 1 group_color: vip-237-fw:0 allocation score on s01-1: 0 group_color: vip-237-fw:1 allocation score on s01-0: -INFINITY group_color: vip-237-fw:1 allocation score on s01-1: 1 group_color: vip-238 allocation score on s01-0: 0 group_color: vip-238 allocation score on s01-1: 0 group_color: vip-238-fw:0 allocation score on s01-0: 1 group_color: vip-238-fw:0 allocation score on s01-1: 0 group_color: vip-238-fw:1 allocation score on s01-0: -INFINITY group_color: vip-238-fw:1 allocation score on s01-1: 1 group_color: zebra:0 allocation score on s01-0: 1 group_color: zebra:0 allocation score on s01-1: 0 group_color: zebra:1 allocation score on s01-0: -INFINITY group_color: zebra:1 allocation score on s01-1: 1 iscsi-pool-0-vips-fw:0 promotion score on s01-0: 2000 iscsi-pool-0-vips-fw:1 promotion score on s01-1: -INFINITY iscsi-pool-1-vips-fw:0 promotion score on s01-0: -INFINITY iscsi-pool-1-vips-fw:1 promotion score on s01-1: 2000 iscsi-vds-dom0-stateless-0-vips-fw:0 promotion score on s01-0: -INFINITY iscsi-vds-dom0-stateless-0-vips-fw:1 promotion score on s01-1: -INFINITY native_color: clvmd:0 allocation score on s01-0: -INFINITY native_color: clvmd:0 allocation score on s01-1: 1 native_color: clvmd:1 allocation score on s01-0: 1 native_color: clvmd:1 allocation score on s01-1: -INFINITY native_color: dhcpd:0 allocation score on s01-0: -INFINITY native_color: dhcpd:0 allocation score on s01-1: -INFINITY native_color: dhcpd:1 allocation score on s01-0: -INFINITY native_color: dhcpd:1 allocation score on s01-1: -INFINITY native_color: dlm:0 allocation score on s01-0: 1 native_color: dlm:0 allocation score on s01-1: 0 native_color: dlm:1 allocation score on s01-0: -INFINITY native_color: dlm:1 allocation score on s01-1: 1 native_color: drbd-pool-0:0 allocation score on s01-0: 10001 native_color: drbd-pool-0:0 allocation score on s01-1: 0 native_color: drbd-pool-0:1 allocation score on s01-0: -INFINITY native_color: drbd-pool-0:1 allocation score on s01-1: 10001 native_color: drbd-pool-1:0 allocation score on s01-0: 10001 native_color: drbd-pool-1:0 allocation score on s01-1: 0 native_color: drbd-pool-1:1 allocation score on s01-0: -INFINITY native_color: drbd-pool-1:1 allocation score on s01-1: 10001 native_color: drbd-s01-logs:0 allocation score on s01-0: -INFINITY native_color: drbd-s01-logs:0 allocation score on s01-1: 10001 native_color: drbd-s01-logs:1 allocation score on s01-0: 10001 native_color: drbd-s01-logs:1 allocation score on s01-1: 0 native_color: drbd-s01-service:0 allocation score on s01-0: -INFINITY native_color: drbd-s01-service:0 allocation score on s01-1: 10001 native_color: drbd-s01-service:1 allocation score on s01-0: 10001 native_color: drbd-s01-service:1 allocation score on s01-1: 0 native_color: drbd-s01-vm-data:0 allocation score on s01-0: -INFINITY native_color: drbd-s01-vm-data:0 allocation score on s01-1: 10001 native_color: drbd-s01-vm-data:1 allocation score on s01-0: 10001 native_color: drbd-s01-vm-data:1 allocation score on s01-1: 0 native_color: drbd-vds-dom0-stateless-0:0 allocation score on s01-0: -INFINITY native_color: drbd-vds-dom0-stateless-0:0 allocation score on s01-1: 10001 native_color: drbd-vds-dom0-stateless-0:1 allocation score on s01-0: 10001 native_color: drbd-vds-dom0-stateless-0:1 allocation score on s01-1: 0 native_color: drbd-vds-http:0 allocation score on s01-0: -INFINITY native_color: drbd-vds-http:0 allocation score on s01-1: 10001 native_color: drbd-vds-http:1 allocation score on s01-0: 10001 native_color: drbd-vds-http:1 allocation score on s01-1: 0 native_color: drbd-vds-tftpboot:0 allocation score on s01-0: -INFINITY native_color: drbd-vds-tftpboot:0 allocation score on s01-1: 10001 native_color: drbd-vds-tftpboot:1 allocation score on s01-0: 10001 native_color: drbd-vds-tftpboot:1 allocation score on s01-1: 0 native_color: drbdlinks-s01-service:0 allocation score on s01-0: -INFINITY native_color: drbdlinks-s01-service:0 allocation score on s01-1: 1 native_color: drbdlinks-s01-service:1 allocation score on s01-0: 1 native_color: drbdlinks-s01-service:1 allocation score on s01-1: -INFINITY native_color: gfs2:0 allocation score on s01-0: 1 native_color: gfs2:0 allocation score on s01-1: -INFINITY native_color: gfs2:1 allocation score on s01-0: -INFINITY native_color: gfs2:1 allocation score on s01-1: 1 native_color: ietd:0 allocation score on s01-0: 1 native_color: ietd:0 allocation score on s01-1: 0 native_color: ietd:1 allocation score on s01-0: -INFINITY native_color: ietd:1 allocation score on s01-1: 1 native_color: iscsi-pool-0-lun-1 allocation score on s01-0: 0 native_color: iscsi-pool-0-lun-1 allocation score on s01-1: -INFINITY native_color: iscsi-pool-0-target allocation score on s01-0: 11001 native_color: iscsi-pool-0-target allocation score on s01-1: -INFINITY native_color: iscsi-pool-1-lun-1 allocation score on s01-0: -INFINITY native_color: iscsi-pool-1-lun-1 allocation score on s01-1: 0 native_color: iscsi-pool-1-target allocation score on s01-0: -INFINITY native_color: iscsi-pool-1-target allocation score on s01-1: 11001 native_color: iscsi-vds-dom0-stateless-0-lun-1 allocation score on s01-0: -INFINITY native_color: iscsi-vds-dom0-stateless-0-lun-1 allocation score on s01-1: -INFINITY native_color: iscsi-vds-dom0-stateless-0-target allocation score on s01-0: -INFINITY native_color: iscsi-vds-dom0-stateless-0-target allocation score on s01-1: -INFINITY native_color: libvirtd:0 allocation score on s01-0: -INFINITY native_color: libvirtd:0 allocation score on s01-1: 1 native_color: libvirtd:1 allocation score on s01-0: 1 native_color: libvirtd:1 allocation score on s01-1: 0 native_color: mgmt-vm allocation score on s01-0: -INFINITY native_color: mgmt-vm allocation score on s01-1: 0 native_color: nginx allocation score on s01-0: -INFINITY native_color: nginx allocation score on s01-1: -INFINITY native_color: o2cb:0 allocation score on s01-0: -INFINITY native_color: o2cb:0 allocation score on s01-1: -INFINITY native_color: o2cb:1 allocation score on s01-0: -INFINITY native_color: o2cb:1 allocation score on s01-1: -INFINITY native_color: ospfd:0 allocation score on s01-0: 1 native_color: ospfd:0 allocation score on s01-1: -INFINITY native_color: ospfd:1 allocation score on s01-0: -INFINITY native_color: ospfd:1 allocation score on s01-1: 1 native_color: ping-bmc-and-switch:0 allocation score on s01-0: 1 native_color: ping-bmc-and-switch:0 allocation score on s01-1: 0 native_color: ping-bmc-and-switch:1 allocation score on s01-0: -INFINITY native_color: ping-bmc-and-switch:1 allocation score on s01-1: 1 native_color: s01-logs-fs:0 allocation score on s01-0: 10002 native_color: s01-logs-fs:0 allocation score on s01-1: -INFINITY native_color: s01-logs-fs:1 allocation score on s01-0: -INFINITY native_color: s01-logs-fs:1 allocation score on s01-1: 10002 native_color: s01-service-fs:0 allocation score on s01-0: -INFINITY native_color: s01-service-fs:0 allocation score on s01-1: 10002 native_color: s01-service-fs:1 allocation score on s01-0: 10002 native_color: s01-service-fs:1 allocation score on s01-1: -INFINITY native_color: s01-vm-data-metadata-fs:0 allocation score on s01-0: -INFINITY native_color: s01-vm-data-metadata-fs:0 allocation score on s01-1: 1 native_color: s01-vm-data-metadata-fs:1 allocation score on s01-0: 1 native_color: s01-vm-data-metadata-fs:1 allocation score on s01-1: -INFINITY native_color: s01-vm-data-storage-pool:0 allocation score on s01-0: -INFINITY native_color: s01-vm-data-storage-pool:0 allocation score on s01-1: 1 native_color: s01-vm-data-storage-pool:1 allocation score on s01-0: 1 native_color: s01-vm-data-storage-pool:1 allocation score on s01-1: -INFINITY native_color: stonith-s01-0 allocation score on s01-0: -INFINITY native_color: stonith-s01-0 allocation score on s01-1: 0 native_color: stonith-s01-1 allocation score on s01-0: 0 native_color: stonith-s01-1 allocation score on s01-1: -INFINITY native_color: syslog-ng allocation score on s01-0: -INFINITY native_color: syslog-ng allocation score on s01-1: 0 native_color: tftpd allocation score on s01-0: -INFINITY native_color: tftpd allocation score on s01-1: -INFINITY native_color: vds-http-fs:0 allocation score on s01-0: -INFINITY native_color: vds-http-fs:0 allocation score on s01-1: 10002 native_color: vds-http-fs:1 allocation score on s01-0: 10002 native_color: vds-http-fs:1 allocation score on s01-1: -INFINITY native_color: vds-tftpboot-fs:0 allocation score on s01-0: -INFINITY native_color: vds-tftpboot-fs:0 allocation score on s01-1: -INFINITY native_color: vds-tftpboot-fs:1 allocation score on s01-0: -INFINITY native_color: vds-tftpboot-fs:1 allocation score on s01-1: -INFINITY native_color: vg-s01-vm-data:0 allocation score on s01-0: -INFINITY native_color: vg-s01-vm-data:0 allocation score on s01-1: 10002 native_color: vg-s01-vm-data:1 allocation score on s01-0: 10002 native_color: vg-s01-vm-data:1 allocation score on s01-1: -INFINITY native_color: vip-227 allocation score on s01-0: -INFINITY native_color: vip-227 allocation score on s01-1: -INFINITY native_color: vip-227-fw:0 allocation score on s01-0: 2 native_color: vip-227-fw:0 allocation score on s01-1: 0 native_color: vip-227-fw:1 allocation score on s01-0: -INFINITY native_color: vip-227-fw:1 allocation score on s01-1: 2 native_color: vip-228 allocation score on s01-0: -INFINITY native_color: vip-228 allocation score on s01-1: -INFINITY native_color: vip-228-fw:0 allocation score on s01-0: 1 native_color: vip-228-fw:0 allocation score on s01-1: -INFINITY native_color: vip-228-fw:1 allocation score on s01-0: -INFINITY native_color: vip-228-fw:1 allocation score on s01-1: 1 native_color: vip-232 allocation score on s01-0: -INFINITY native_color: vip-232 allocation score on s01-1: -INFINITY native_color: vip-233 allocation score on s01-0: 0 native_color: vip-233 allocation score on s01-1: 0 native_color: vip-234 allocation score on s01-0: 0 native_color: vip-234 allocation score on s01-1: 0 native_color: vip-235 allocation score on s01-0: 0 native_color: vip-235 allocation score on s01-1: -INFINITY native_color: vip-235-fw:0 allocation score on s01-0: 2 native_color: vip-235-fw:0 allocation score on s01-1: 0 native_color: vip-235-fw:1 allocation score on s01-0: -INFINITY native_color: vip-235-fw:1 allocation score on s01-1: 2 native_color: vip-236 allocation score on s01-0: 0 native_color: vip-236 allocation score on s01-1: -INFINITY native_color: vip-236-fw:0 allocation score on s01-0: 1 native_color: vip-236-fw:0 allocation score on s01-1: -INFINITY native_color: vip-236-fw:1 allocation score on s01-0: -INFINITY native_color: vip-236-fw:1 allocation score on s01-1: 1 native_color: vip-237 allocation score on s01-0: -INFINITY native_color: vip-237 allocation score on s01-1: 0 native_color: vip-237-fw:0 allocation score on s01-0: 2 native_color: vip-237-fw:0 allocation score on s01-1: 0 native_color: vip-237-fw:1 allocation score on s01-0: -INFINITY native_color: vip-237-fw:1 allocation score on s01-1: 2 native_color: vip-238 allocation score on s01-0: -INFINITY native_color: vip-238 allocation score on s01-1: 0 native_color: vip-238-fw:0 allocation score on s01-0: 1 native_color: vip-238-fw:0 allocation score on s01-1: -INFINITY native_color: vip-238-fw:1 allocation score on s01-0: -INFINITY native_color: vip-238-fw:1 allocation score on s01-1: 1 native_color: xinetd:0 allocation score on s01-0: 1 native_color: xinetd:0 allocation score on s01-1: 0 native_color: xinetd:1 allocation score on s01-0: -INFINITY native_color: xinetd:1 allocation score on s01-1: 1 native_color: zebra:0 allocation score on s01-0: 2 native_color: zebra:0 allocation score on s01-1: 0 native_color: zebra:1 allocation score on s01-0: -INFINITY native_color: zebra:1 allocation score on s01-1: 2 diff --git a/pengine/test10/master-depend.scores b/pengine/test10/master-depend.scores index c73ef1f64e..3af849a752 100644 --- a/pengine/test10/master-depend.scores +++ b/pengine/test10/master-depend.scores @@ -1,45 +1,47 @@ Allocation scores: clone_color: clvmd:0 allocation score on vbox3: 0 clone_color: clvmd:0 allocation score on vbox4: 0 clone_color: clvmd:1 allocation score on vbox3: 0 clone_color: clvmd:1 allocation score on vbox4: 0 clone_color: clvmd_clone allocation score on vbox3: 0 clone_color: clvmd_clone allocation score on vbox4: 0 clone_color: cman:0 allocation score on vbox3: 0 clone_color: cman:0 allocation score on vbox4: 0 clone_color: cman:1 allocation score on vbox3: 0 clone_color: cman:1 allocation score on vbox4: 0 clone_color: cman_clone allocation score on vbox3: 0 clone_color: cman_clone allocation score on vbox4: 0 clone_color: drbd allocation score on vbox3: 1 clone_color: drbd allocation score on vbox4: 0 clone_color: drbd0:0 allocation score on vbox3: 1 clone_color: drbd0:0 allocation score on vbox4: 0 clone_color: drbd0:1 allocation score on vbox3: 1 clone_color: drbd0:1 allocation score on vbox4: 0 drbd0:0 promotion score on vbox4: -1 drbd0:0 promotion score on vbox4: -INFINITY drbd0:0 promotion score on vbox4: -INFINITY +drbd0:0 promotion score on vbox4: -INFINITY +drbd0:1 promotion score on none: 0 drbd0:1 promotion score on none: 0 drbd0:1 promotion score on none: 0 drbd0:1 promotion score on none: 0 native_color: clvmd:0 allocation score on vbox3: -INFINITY native_color: clvmd:0 allocation score on vbox4: -INFINITY native_color: clvmd:1 allocation score on vbox3: -INFINITY native_color: clvmd:1 allocation score on vbox4: -INFINITY native_color: cman:0 allocation score on vbox3: -INFINITY native_color: cman:0 allocation score on vbox4: 0 native_color: cman:1 allocation score on vbox3: -INFINITY native_color: cman:1 allocation score on vbox4: -INFINITY native_color: drbd0:0 allocation score on vbox3: -INFINITY native_color: drbd0:0 allocation score on vbox4: 0 native_color: drbd0:1 allocation score on vbox3: -INFINITY native_color: drbd0:1 allocation score on vbox4: -INFINITY native_color: vmnci36 allocation score on vbox3: -INFINITY native_color: vmnci36 allocation score on vbox4: -INFINITY native_color: vmnci37 allocation score on vbox3: -INFINITY native_color: vmnci37 allocation score on vbox4: -INFINITY native_color: vmnci38 allocation score on vbox3: -INFINITY native_color: vmnci38 allocation score on vbox4: -INFINITY native_color: vmnci55 allocation score on vbox3: -INFINITY native_color: vmnci55 allocation score on vbox4: -INFINITY diff --git a/pengine/test10/master-ordering.scores b/pengine/test10/master-ordering.scores index 26a8a912ad..495cb5a2ab 100644 --- a/pengine/test10/master-ordering.scores +++ b/pengine/test10/master-ordering.scores @@ -1,93 +1,95 @@ Allocation scores: clone_color: apache2:0 allocation score on webcluster01: 0 clone_color: apache2:0 allocation score on webcluster02: 0 clone_color: apache2:1 allocation score on webcluster01: 0 clone_color: apache2:1 allocation score on webcluster02: 0 clone_color: clone_ocfs2_www allocation score on webcluster01: 0 clone_color: clone_ocfs2_www allocation score on webcluster02: 0 clone_color: clone_webservice allocation score on webcluster01: 0 clone_color: clone_webservice allocation score on webcluster02: 0 clone_color: drbd_mysql:0 allocation score on webcluster01: 0 clone_color: drbd_mysql:0 allocation score on webcluster02: 0 clone_color: drbd_mysql:1 allocation score on webcluster01: 0 clone_color: drbd_mysql:1 allocation score on webcluster02: 0 clone_color: drbd_www:0 allocation score on webcluster01: 0 clone_color: drbd_www:0 allocation score on webcluster02: 0 clone_color: drbd_www:1 allocation score on webcluster01: 0 clone_color: drbd_www:1 allocation score on webcluster02: 0 clone_color: group_webservice:0 allocation score on webcluster01: 0 clone_color: group_webservice:0 allocation score on webcluster02: 0 clone_color: group_webservice:1 allocation score on webcluster01: 0 clone_color: group_webservice:1 allocation score on webcluster02: 0 clone_color: ms_drbd_mysql allocation score on webcluster01: 100 clone_color: ms_drbd_mysql allocation score on webcluster02: 0 clone_color: ms_drbd_www allocation score on webcluster01: 0 clone_color: ms_drbd_www allocation score on webcluster02: 0 clone_color: mysql-proxy:0 allocation score on webcluster01: 0 clone_color: mysql-proxy:0 allocation score on webcluster02: 0 clone_color: mysql-proxy:1 allocation score on webcluster01: 0 clone_color: mysql-proxy:1 allocation score on webcluster02: 0 clone_color: ocfs2_www:0 allocation score on webcluster01: 0 clone_color: ocfs2_www:0 allocation score on webcluster02: 0 clone_color: ocfs2_www:1 allocation score on webcluster01: 0 clone_color: ocfs2_www:1 allocation score on webcluster02: 0 drbd_mysql:0 promotion score on webcluster01: -1 drbd_mysql:0 promotion score on webcluster01: -INFINITY drbd_mysql:1 promotion score on none: 0 drbd_mysql:1 promotion score on none: 0 drbd_www:0 promotion score on webcluster01: -1 drbd_www:0 promotion score on webcluster01: -INFINITY drbd_www:0 promotion score on webcluster01: -INFINITY +drbd_www:0 promotion score on webcluster01: -INFINITY +drbd_www:1 promotion score on none: 0 drbd_www:1 promotion score on none: 0 drbd_www:1 promotion score on none: 0 drbd_www:1 promotion score on none: 0 group_color: apache2:0 allocation score on webcluster01: 0 group_color: apache2:0 allocation score on webcluster02: -INFINITY group_color: apache2:1 allocation score on webcluster01: 0 group_color: apache2:1 allocation score on webcluster02: -INFINITY group_color: group_main allocation score on webcluster01: 100 group_color: group_main allocation score on webcluster02: 0 group_color: group_webservice:0 allocation score on webcluster01: 0 group_color: group_webservice:0 allocation score on webcluster02: -INFINITY group_color: group_webservice:1 allocation score on webcluster01: 0 group_color: group_webservice:1 allocation score on webcluster02: -INFINITY group_color: intip_0_main allocation score on webcluster01: 100 group_color: intip_0_main allocation score on webcluster02: 0 group_color: mysql-proxy:0 allocation score on webcluster01: 0 group_color: mysql-proxy:0 allocation score on webcluster02: -INFINITY group_color: mysql-proxy:1 allocation score on webcluster01: 0 group_color: mysql-proxy:1 allocation score on webcluster02: -INFINITY native_color: apache2:0 allocation score on webcluster01: -INFINITY native_color: apache2:0 allocation score on webcluster02: -INFINITY native_color: apache2:1 allocation score on webcluster01: -INFINITY native_color: apache2:1 allocation score on webcluster02: -INFINITY native_color: drbd_mysql:0 allocation score on webcluster01: 0 native_color: drbd_mysql:0 allocation score on webcluster02: -INFINITY native_color: drbd_mysql:1 allocation score on webcluster01: -INFINITY native_color: drbd_mysql:1 allocation score on webcluster02: -INFINITY native_color: drbd_www:0 allocation score on webcluster01: 0 native_color: drbd_www:0 allocation score on webcluster02: -INFINITY native_color: drbd_www:1 allocation score on webcluster01: -INFINITY native_color: drbd_www:1 allocation score on webcluster02: -INFINITY native_color: extip_1 allocation score on webcluster01: 100 native_color: extip_1 allocation score on webcluster02: 0 native_color: extip_2 allocation score on webcluster01: 0 native_color: extip_2 allocation score on webcluster02: 100 native_color: fs_mysql allocation score on webcluster01: -INFINITY native_color: fs_mysql allocation score on webcluster02: -INFINITY native_color: intip_0_main allocation score on webcluster01: -INFINITY native_color: intip_0_main allocation score on webcluster02: -INFINITY native_color: intip_1_master allocation score on webcluster01: 200 native_color: intip_1_master allocation score on webcluster02: 0 native_color: intip_2_slave allocation score on webcluster01: 0 native_color: intip_2_slave allocation score on webcluster02: 100 native_color: mysql-proxy:0 allocation score on webcluster01: -INFINITY native_color: mysql-proxy:0 allocation score on webcluster02: -INFINITY native_color: mysql-proxy:1 allocation score on webcluster01: -INFINITY native_color: mysql-proxy:1 allocation score on webcluster02: -INFINITY native_color: mysql-server allocation score on webcluster01: -INFINITY native_color: mysql-server allocation score on webcluster02: -INFINITY native_color: ocfs2_www:0 allocation score on webcluster01: -INFINITY native_color: ocfs2_www:0 allocation score on webcluster02: -INFINITY native_color: ocfs2_www:1 allocation score on webcluster01: -INFINITY native_color: ocfs2_www:1 allocation score on webcluster02: -INFINITY diff --git a/pengine/test10/migrate-stop-start-complex.scores b/pengine/test10/migrate-stop-start-complex.scores index 7021ff9ba6..fa5e8c417f 100644 --- a/pengine/test10/migrate-stop-start-complex.scores +++ b/pengine/test10/migrate-stop-start-complex.scores @@ -1,37 +1,37 @@ Allocation scores: clone_color: bottom:0 allocation score on dom0-01: 0 clone_color: bottom:0 allocation score on dom0-02: 1 clone_color: bottom:1 allocation score on dom0-01: 0 clone_color: bottom:1 allocation score on dom0-02: 0 -clone_color: clone-bottom allocation score on dom0-01: 10000 +clone_color: clone-bottom allocation score on dom0-01: 5000 clone_color: clone-bottom allocation score on dom0-02: 0 clone_color: clone-dom0-iscsi1 allocation score on dom0-01: 5000 clone_color: clone-dom0-iscsi1 allocation score on dom0-02: 0 clone_color: dom0-iscsi1-cnx1:0 allocation score on dom0-01: 0 clone_color: dom0-iscsi1-cnx1:0 allocation score on dom0-02: 1 clone_color: dom0-iscsi1-cnx1:1 allocation score on dom0-01: 1 clone_color: dom0-iscsi1-cnx1:1 allocation score on dom0-02: 0 clone_color: dom0-iscsi1:0 allocation score on dom0-01: 0 clone_color: dom0-iscsi1:0 allocation score on dom0-02: 0 clone_color: dom0-iscsi1:1 allocation score on dom0-01: 0 clone_color: dom0-iscsi1:1 allocation score on dom0-02: 0 group_color: dom0-iscsi1-cnx1:0 allocation score on dom0-01: -INFINITY group_color: dom0-iscsi1-cnx1:0 allocation score on dom0-02: -INFINITY group_color: dom0-iscsi1-cnx1:1 allocation score on dom0-01: 1 group_color: dom0-iscsi1-cnx1:1 allocation score on dom0-02: -INFINITY group_color: dom0-iscsi1:0 allocation score on dom0-01: -INFINITY group_color: dom0-iscsi1:0 allocation score on dom0-02: -INFINITY group_color: dom0-iscsi1:1 allocation score on dom0-01: 0 group_color: dom0-iscsi1:1 allocation score on dom0-02: -INFINITY native_color: bottom:0 allocation score on dom0-01: 0 native_color: bottom:0 allocation score on dom0-02: -INFINITY native_color: bottom:1 allocation score on dom0-01: -INFINITY native_color: bottom:1 allocation score on dom0-02: -INFINITY native_color: dom0-iscsi1-cnx1:0 allocation score on dom0-01: -INFINITY native_color: dom0-iscsi1-cnx1:0 allocation score on dom0-02: -INFINITY native_color: dom0-iscsi1-cnx1:1 allocation score on dom0-01: 1 native_color: dom0-iscsi1-cnx1:1 allocation score on dom0-02: -INFINITY native_color: domU-test01 allocation score on dom0-01: 5000 native_color: domU-test01 allocation score on dom0-02: -INFINITY native_color: top allocation score on dom0-01: 5000 native_color: top allocation score on dom0-02: -INFINITY diff --git a/pengine/test10/order-clone.dot b/pengine/test10/order-clone.dot index db2f62f374..ef7836f02a 100644 --- a/pengine/test10/order-clone.dot +++ b/pengine/test10/order-clone.dot @@ -1,117 +1,105 @@ digraph "g" { "clvm-clone_running_0" -> "vg1-clone_start_0" [ style = dashed] "clvm-clone_running_0" [ style=dashed color="red" fontcolor="orange" ] "clvm-clone_start_0" -> "clvm-clone_running_0" [ style = dashed] "clvm-clone_start_0" -> "clvm:0_start_0 hex-7" [ style = dashed] "clvm-clone_start_0" -> "clvm:1_start_0 hex-8" [ style = dashed] "clvm-clone_start_0" -> "clvm:2_start_0 hex-9" [ style = dashed] "clvm-clone_start_0" -> "clvm:3_start_0 hex-0" [ style = dashed] "clvm-clone_start_0" [ style=dashed color="red" fontcolor="orange" ] "clvm:0_start_0 hex-7" -> "clvm-clone_running_0" [ style = dashed] "clvm:0_start_0 hex-7" -> "clvm:1_start_0 hex-8" [ style = dashed] -"clvm:0_start_0 hex-7" -> "vg1:0_start_0 hex-7" [ style = dashed] "clvm:0_start_0 hex-7" [ style=dashed color="red" fontcolor="black" ] "clvm:1_start_0 hex-8" -> "clvm-clone_running_0" [ style = dashed] "clvm:1_start_0 hex-8" -> "clvm:2_start_0 hex-9" [ style = dashed] -"clvm:1_start_0 hex-8" -> "vg1:1_start_0 hex-8" [ style = dashed] "clvm:1_start_0 hex-8" [ style=dashed color="red" fontcolor="black" ] "clvm:2_start_0 hex-9" -> "clvm-clone_running_0" [ style = dashed] "clvm:2_start_0 hex-9" -> "clvm:3_start_0 hex-0" [ style = dashed] -"clvm:2_start_0 hex-9" -> "vg1:2_start_0 hex-9" [ style = dashed] "clvm:2_start_0 hex-9" [ style=dashed color="red" fontcolor="black" ] "clvm:3_start_0 hex-0" -> "clvm-clone_running_0" [ style = dashed] -"clvm:3_start_0 hex-0" -> "vg1:3_start_0 hex-0" [ style = dashed] "clvm:3_start_0 hex-0" [ style=dashed color="red" fontcolor="black" ] "fencing-sbd_start_0 hex-0" [ style=bold color="green" fontcolor="black" ] "fs1-clone_running_0" -> "fs2-clone_start_0" [ style = dashed] "fs1-clone_running_0" [ style=dashed color="red" fontcolor="orange" ] "fs1-clone_start_0" -> "fs1-clone_running_0" [ style = dashed] "fs1-clone_start_0" -> "ocfs2-1:0_start_0 hex-7" [ style = dashed] "fs1-clone_start_0" -> "ocfs2-1:1_start_0 hex-8" [ style = dashed] "fs1-clone_start_0" -> "ocfs2-1:2_start_0 hex-9" [ style = dashed] "fs1-clone_start_0" -> "ocfs2-1:3_start_0 hex-0" [ style = dashed] "fs1-clone_start_0" [ style=dashed color="red" fontcolor="orange" ] "fs2-clone_running_0" [ style=dashed color="red" fontcolor="orange" ] "fs2-clone_start_0" -> "fs2-clone_running_0" [ style = dashed] "fs2-clone_start_0" -> "ocfs2-2:0_start_0 hex-7" [ style = dashed] "fs2-clone_start_0" -> "ocfs2-2:1_start_0 hex-8" [ style = dashed] "fs2-clone_start_0" -> "ocfs2-2:2_start_0 hex-9" [ style = dashed] "fs2-clone_start_0" -> "ocfs2-2:3_start_0 hex-0" [ style = dashed] "fs2-clone_start_0" [ style=dashed color="red" fontcolor="orange" ] "o2cb-clone_running_0" -> "vg1-clone_start_0" [ style = dashed] "o2cb-clone_running_0" [ style=dashed color="red" fontcolor="orange" ] "o2cb-clone_start_0" -> "o2cb-clone_running_0" [ style = dashed] "o2cb-clone_start_0" -> "o2cb:0_start_0 hex-7" [ style = dashed] "o2cb-clone_start_0" -> "o2cb:1_start_0 hex-8" [ style = dashed] "o2cb-clone_start_0" -> "o2cb:2_start_0 hex-9" [ style = dashed] "o2cb-clone_start_0" -> "o2cb:3_start_0 hex-0" [ style = dashed] "o2cb-clone_start_0" [ style=dashed color="red" fontcolor="orange" ] "o2cb:0_start_0 hex-7" -> "o2cb-clone_running_0" [ style = dashed] "o2cb:0_start_0 hex-7" -> "vg1:0_start_0 hex-7" [ style = dashed] "o2cb:0_start_0 hex-7" [ style=dashed color="red" fontcolor="black" ] "o2cb:1_start_0 hex-8" -> "o2cb-clone_running_0" [ style = dashed] "o2cb:1_start_0 hex-8" -> "vg1:1_start_0 hex-8" [ style = dashed] "o2cb:1_start_0 hex-8" [ style=dashed color="red" fontcolor="black" ] "o2cb:2_start_0 hex-9" -> "o2cb-clone_running_0" [ style = dashed] "o2cb:2_start_0 hex-9" -> "vg1:2_start_0 hex-9" [ style = dashed] "o2cb:2_start_0 hex-9" [ style=dashed color="red" fontcolor="black" ] "o2cb:3_start_0 hex-0" -> "o2cb-clone_running_0" [ style = dashed] "o2cb:3_start_0 hex-0" -> "vg1:3_start_0 hex-0" [ style = dashed] "o2cb:3_start_0 hex-0" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:0_monitor_20000 hex-7" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:0_start_0 hex-7" -> "fs1-clone_running_0" [ style = dashed] "ocfs2-1:0_start_0 hex-7" -> "ocfs2-1:0_monitor_20000 hex-7" [ style = dashed] -"ocfs2-1:0_start_0 hex-7" -> "ocfs2-2:0_start_0 hex-7" [ style = dashed] "ocfs2-1:0_start_0 hex-7" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:1_monitor_20000 hex-8" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:1_start_0 hex-8" -> "fs1-clone_running_0" [ style = dashed] "ocfs2-1:1_start_0 hex-8" -> "ocfs2-1:1_monitor_20000 hex-8" [ style = dashed] -"ocfs2-1:1_start_0 hex-8" -> "ocfs2-2:1_start_0 hex-8" [ style = dashed] "ocfs2-1:1_start_0 hex-8" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:2_monitor_20000 hex-9" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:2_start_0 hex-9" -> "fs1-clone_running_0" [ style = dashed] "ocfs2-1:2_start_0 hex-9" -> "ocfs2-1:2_monitor_20000 hex-9" [ style = dashed] -"ocfs2-1:2_start_0 hex-9" -> "ocfs2-2:2_start_0 hex-9" [ style = dashed] "ocfs2-1:2_start_0 hex-9" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:3_monitor_20000 hex-0" [ style=dashed color="red" fontcolor="black" ] "ocfs2-1:3_start_0 hex-0" -> "fs1-clone_running_0" [ style = dashed] "ocfs2-1:3_start_0 hex-0" -> "ocfs2-1:3_monitor_20000 hex-0" [ style = dashed] -"ocfs2-1:3_start_0 hex-0" -> "ocfs2-2:3_start_0 hex-0" [ style = dashed] "ocfs2-1:3_start_0 hex-0" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:0_monitor_20000 hex-7" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:0_start_0 hex-7" -> "fs2-clone_running_0" [ style = dashed] "ocfs2-2:0_start_0 hex-7" -> "ocfs2-2:0_monitor_20000 hex-7" [ style = dashed] "ocfs2-2:0_start_0 hex-7" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:1_monitor_20000 hex-8" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:1_start_0 hex-8" -> "fs2-clone_running_0" [ style = dashed] "ocfs2-2:1_start_0 hex-8" -> "ocfs2-2:1_monitor_20000 hex-8" [ style = dashed] "ocfs2-2:1_start_0 hex-8" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:2_monitor_20000 hex-9" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:2_start_0 hex-9" -> "fs2-clone_running_0" [ style = dashed] "ocfs2-2:2_start_0 hex-9" -> "ocfs2-2:2_monitor_20000 hex-9" [ style = dashed] "ocfs2-2:2_start_0 hex-9" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:3_monitor_20000 hex-0" [ style=dashed color="red" fontcolor="black" ] "ocfs2-2:3_start_0 hex-0" -> "fs2-clone_running_0" [ style = dashed] "ocfs2-2:3_start_0 hex-0" -> "ocfs2-2:3_monitor_20000 hex-0" [ style = dashed] "ocfs2-2:3_start_0 hex-0" [ style=dashed color="red" fontcolor="black" ] "vg1-clone_running_0" -> "fs1-clone_start_0" [ style = dashed] "vg1-clone_running_0" [ style=dashed color="red" fontcolor="orange" ] "vg1-clone_start_0" -> "vg1-clone_running_0" [ style = dashed] "vg1-clone_start_0" -> "vg1:0_start_0 hex-7" [ style = dashed] "vg1-clone_start_0" -> "vg1:1_start_0 hex-8" [ style = dashed] "vg1-clone_start_0" -> "vg1:2_start_0 hex-9" [ style = dashed] "vg1-clone_start_0" -> "vg1:3_start_0 hex-0" [ style = dashed] "vg1-clone_start_0" [ style=dashed color="red" fontcolor="orange" ] -"vg1:0_start_0 hex-7" -> "ocfs2-1:0_start_0 hex-7" [ style = dashed] "vg1:0_start_0 hex-7" -> "vg1-clone_running_0" [ style = dashed] "vg1:0_start_0 hex-7" [ style=dashed color="red" fontcolor="black" ] -"vg1:1_start_0 hex-8" -> "ocfs2-1:1_start_0 hex-8" [ style = dashed] "vg1:1_start_0 hex-8" -> "vg1-clone_running_0" [ style = dashed] "vg1:1_start_0 hex-8" [ style=dashed color="red" fontcolor="black" ] -"vg1:2_start_0 hex-9" -> "ocfs2-1:2_start_0 hex-9" [ style = dashed] "vg1:2_start_0 hex-9" -> "vg1-clone_running_0" [ style = dashed] "vg1:2_start_0 hex-9" [ style=dashed color="red" fontcolor="black" ] -"vg1:3_start_0 hex-0" -> "ocfs2-1:3_start_0 hex-0" [ style = dashed] "vg1:3_start_0 hex-0" -> "vg1-clone_running_0" [ style = dashed] "vg1:3_start_0 hex-0" [ style=dashed color="red" fontcolor="black" ] } diff --git a/pengine/utils.c b/pengine/utils.c index 0c4e5f7836..e03b3fcc46 100644 --- a/pengine/utils.c +++ b/pengine/utils.c @@ -1,743 +1,752 @@ /* * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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:", 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; slist_basic_destroy(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; 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); } 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); } 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; } 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"; } else if(type & pe_order_runnable_left) { result = "runnable"; /* } else { */ /* crm_err("Unknown ordering type: %.3x", type); */ } return result; } gboolean can_run_resources(const node_t *node) { if(node == NULL) { return FALSE; } #if 0 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; } 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; 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++; } } 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; if (g_hash_table_lookup_extended(data->node1->details->utilization, key, NULL, NULL)) { return; } 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++; } } /* 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; 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); 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 node1_weight = 0; int node2_weight = 0; int result = 0; if(a == NULL) { return 1; } if(b == NULL) { return -1; } 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(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; } 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, "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", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); return -1; } 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; } 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); } } /* 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; data.node = node; data.allocate = allocate; g_hash_table_foreach(rsc->utilization, do_calculate_utilization, &data); if (allocate) { dump_rsc_utilization(show_utilization?0:utilization_log_level, __FUNCTION__, rsc, node); } } +void +native_deallocate(resource_t *rsc) +{ + if(rsc->allocated_to) { + node_t *old = rsc->allocated_to; + + crm_info("Deallocating %s from %s", rsc->id, old->details->uname); + set_bit_inplace(rsc->flags, pe_rsc_provisional); + rsc->allocated_to = NULL; + + old->details->allocated_rsc = g_list_remove( + old->details->allocated_rsc, rsc); + old->details->num_resources--; + old->count--; + calculate_utilization(old, rsc, FALSE); + } +} + gboolean native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen, gboolean force) { CRM_ASSERT(rsc->variant == pe_native); - - 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; } /* 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); - } + native_deallocate(rsc); + clear_bit(rsc->flags, pe_rsc_provisional); 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; key = generate_op_key(rsc->id, CRMD_ACTION_STOP, 0); possible_matches = find_actions(rsc->actions, key, NULL); for(gIter = possible_matches; 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); key = generate_op_key(rsc->id, CRMD_ACTION_START, 0); possible_matches = find_actions(rsc->actions, key, NULL); for(gIter = possible_matches; 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); return FALSE; } 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; } 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) { GListPtr gIter = NULL; action_wrapper_t *wrapper = NULL; GListPtr list = NULL; static int load_stopped_strlen = 0; 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; } } 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 */ 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_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; 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; } void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) { const char *node_uname = NULL; const char *node_uuid = NULL; if(action == NULL) { 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; } 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?")":""); break; } if(details) { GListPtr gIter = NULL; 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; } 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; } diff --git a/pengine/utils.h b/pengine/utils.h index ac3a93f6d7..e6e167cf0c 100644 --- a/pengine/utils.h +++ b/pengine/utils.h @@ -1,71 +1,72 @@ /* * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PENGINE_AUTILS__H #define PENGINE_AUTILS__H /* Constraint helper functions */ extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint); extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint); extern void print_rsc_to_node( const char *pre_text, rsc_to_node_t *cons, gboolean details); extern void print_rsc_colocation( const char *pre_text, rsc_colocation_t *cons, gboolean details); extern rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, int weight, node_t *node, pe_working_set_t *data_set); extern void pe_free_rsc_to_node(GListPtr constraints); extern void pe_free_ordering(GListPtr constraints); extern const char *ordering_type2text(enum pe_ordering type); extern 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); extern rsc_to_node_t *generate_location_rule( resource_t *rsc, xmlNode *location_rule, pe_working_set_t *data_set); extern gint sort_node_weight(gconstpointer a, gconstpointer b, gpointer data_set); extern gboolean can_run_resources(const node_t *node); extern gboolean native_assign_node(resource_t *rsc, GListPtr candidates, node_t *chosen, gboolean force); +void native_deallocate(resource_t *rsc); extern char *convert_non_atomic_uuid(char *old_uuid, resource_t *rsc, gboolean allow_notify, gboolean free_original); extern gboolean order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order); extern void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details); extern action_t *get_pseudo_op(const char *name, pe_working_set_t *data_set); extern gboolean can_run_any(GHashTable *nodes); extern resource_t *find_compatible_child( resource_t *local_child, resource_t *rsc, enum rsc_role_e filter, gboolean current); #define STONITH_UP "stonith_up" #define STONITH_DONE "stonith_complete" #define ALL_STOPPED "all_stopped" #define LOAD_STOPPED "load_stopped" #endif