diff --git a/pengine/clone.c b/pengine/clone.c index ea11771c91..b80cdb27d0 100644 --- a/pengine/clone.c +++ b/pengine/clone.c @@ -1,1452 +1,1680 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #define VARIANT_CLONE 1 #include gint sort_clone_instance(gconstpointer a, gconstpointer b); void child_stopping_constraints( clone_variant_data_t *clone_data, resource_t *self, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( clone_variant_data_t *clone_data, resource_t *self, resource_t *child, resource_t *last, pe_working_set_t *data_set); static node_t * parent_node_instance(const resource_t *rsc, node_t *node) { node_t *ret = NULL; if(node != NULL) { ret = pe_find_node_id( rsc->parent->allowed_nodes, node->details->id); } return ret; } static gboolean did_fail(const resource_t *rsc) { if(is_set(rsc->flags, pe_rsc_failed)) { return TRUE; } slist_iter( child_rsc, resource_t, rsc->children, lpc, if(did_fail(child_rsc)) { return TRUE; } ); return FALSE; } gint sort_clone_instance(gconstpointer a, gconstpointer b) { int level = LOG_DEBUG_3; node_t *node1 = NULL; node_t *node2 = NULL; gboolean can1 = TRUE; gboolean can2 = TRUE; gboolean with_scores = TRUE; const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); /* allocation order: * - active instances * - instances running on nodes with the least copies * - active instances on nodes that cant support them or are to be fenced * - failed instances * - inactive instances */ do_crm_log_unlikely(level+1, "%s ? %s", resource1->id, resource2->id); if(resource1->running_on && resource2->running_on) { if(g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) { do_crm_log_unlikely(level, "%s < %s: running_on", resource1->id, resource2->id); return -1; } 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_find_node_id(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_find_node_id(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; } if(with_scores) { int max = 0; int lpc = 0; GListPtr list1 = node_list_dup(resource1->allowed_nodes, FALSE, FALSE); GListPtr list2 = node_list_dup(resource2->allowed_nodes, FALSE, FALSE); list1 = g_list_sort(list1, sort_node_weight); list2 = g_list_sort(list2, sort_node_weight); max = g_list_length(list1); if(max < g_list_length(list2)) { max = g_list_length(list2); } for(;lpc < max; lpc++) { node1 = g_list_nth_data(list1, lpc); node2 = g_list_nth_data(list2, lpc); if(node1 == NULL) { do_crm_log_unlikely(level, "%s < %s: node score NULL", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return 1; } else if(node2 == NULL) { do_crm_log_unlikely(level, "%s > %s: node score NULL", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return -1; } if(node1->weight < node2->weight) { do_crm_log_unlikely(level, "%s < %s: node score", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return 1; } else if(node1->weight > node2->weight) { do_crm_log_unlikely(level, "%s > %s: node score", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return -1; } } pe_free_shallow(list1); pe_free_shallow(list2); } 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 max = 0; int lpc = 0; GListPtr list1 = g_list_append(NULL, node_copy(resource1->running_on->data)); GListPtr list2 = g_list_append(NULL, node_copy(resource2->running_on->data)); /* Possibly a replacement for the with_scores block above */ slist_iter( constraint, rsc_colocation_t, resource1->parent->rsc_cons_lhs, lpc, do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource1->id); list1 = native_merge_weights( constraint->rsc_lh, resource1->id, list1, constraint->node_attribute, constraint->score/INFINITY, FALSE); ); slist_iter( constraint, rsc_colocation_t, resource2->parent->rsc_cons_lhs, lpc, do_crm_log_unlikely(level+1, "Applying %s to %s", constraint->id, resource2->id); list2 = native_merge_weights( constraint->rsc_lh, resource2->id, list2, constraint->node_attribute, constraint->score/INFINITY, FALSE); ); list1 = g_list_sort(list1, sort_node_weight); list2 = g_list_sort(list2, sort_node_weight); 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); pe_free_shallow(list1); pe_free_shallow(list2); return 1; } else if(node2 == NULL) { do_crm_log_unlikely(level, "%s > %s: colocated score NULL", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return -1; } if(node1->weight < node2->weight) { do_crm_log_unlikely(level, "%s < %s: colocated score", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return 1; } else if(node1->weight > node2->weight) { do_crm_log_unlikely(level, "%s > %s: colocated score", resource1->id, resource2->id); pe_free_shallow(list1); pe_free_shallow(list2); return -1; } } pe_free_shallow(list1); pe_free_shallow(list2); } do_crm_log_unlikely(level, "%s == %s: default %d", resource1->id, resource2->id, node2->weight); return 0; } static node_t * can_run_instance(resource_t *rsc, node_t *node) { node_t *local_node = NULL; clone_variant_data_t *clone_data = NULL; if(can_run_resources(node) == FALSE) { goto bail; } 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) { return local_node; } else { crm_debug_2("%s cannot run on %s: node full", rsc->id, node->details->uname); } bail: if(node) { common_update_score(rsc, node->details->id, -INFINITY); } return NULL; } static node_t * color_instance(resource_t *rsc, 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("Dependancy loop detected involving %s", rsc->id); return NULL; } if(rsc->allowed_nodes) { slist_iter(try_node, node_t, rsc->allowed_nodes, lpc, can_run_instance(rsc, try_node); ); } chosen = rsc->cmds->color(rsc, data_set); if(chosen) { local_node = pe_find_node_id( rsc->parent->allowed_nodes, chosen->details->id); if(local_node) { local_node->count++; } else if(is_set(rsc->flags, pe_rsc_managed)) { /* what to do? we can't enforce per-node limits in this case */ crm_config_err("%s not found in %s (list=%d)", chosen->details->id, rsc->parent->id, g_list_length(rsc->parent->allowed_nodes)); } } return chosen; } static void append_parent_colocation(resource_t *rsc, resource_t *child, gboolean all) { slist_iter(cons, rsc_colocation_t, rsc->rsc_cons, lpc, if(all || cons->score < 0 || cons->score == INFINITY) { child->rsc_cons = g_list_append(child->rsc_cons, cons); } ); slist_iter(cons, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, if(all || cons->score < 0) { child->rsc_cons_lhs = g_list_append(child->rsc_cons_lhs, cons); } ); } node_t * clone_color(resource_t *rsc, pe_working_set_t *data_set) { int allocated = 0; 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("Dependancy 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 */ slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rsc->id, rsc->allowed_nodes, constraint->node_attribute, constraint->score/INFINITY, TRUE); ); dump_node_scores(show_scores?0:scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes); /* count now tracks the number of clones currently allocated */ slist_iter(node, node_t, rsc->allowed_nodes, lpc, node->count = 0; ); slist_iter(child, resource_t, rsc->children, lpc, if(g_list_length(child->running_on) > 0) { node_t *child_node = child->running_on->data; node_t *local_node = parent_node_instance( child, child->running_on->data); if(local_node) { local_node->count++; } else { crm_err("%s is running on %s which isn't allowed", child->id, child_node->details->uname); } } ); rsc->children = g_list_sort(rsc->children, sort_clone_instance); /* count now tracks the number of clones we have allocated */ slist_iter(node, node_t, rsc->allowed_nodes, lpc, node->count = 0; ); rsc->allowed_nodes = g_list_sort( rsc->allowed_nodes, sort_node_weight); slist_iter(node, node_t, rsc->allowed_nodes, lpc, if(can_run_resources(node)) { available_nodes++; } ); slist_iter(child, resource_t, rsc->children, lpc, if(allocated >= clone_data->clone_max) { crm_debug("Child %s not allocated - limit reached", child->id); resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set); } else if (clone_data->clone_max < available_nodes) { /* Only include positive colocation preferences of dependant resources * if not every node will get a copy of the clone */ append_parent_colocation(rsc, child, TRUE); } else { append_parent_colocation(rsc, child, FALSE); } if(color_instance(child, 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) { if(rsc->children) { slist_iter(child, resource_t, rsc->children, lpc, 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; } slist_iter( action, action_t, rsc->actions, lpc, if(*starting && *stopping) { return; } else if(action->optional) { crm_debug_3("Skipping optional: %s", action->uuid); continue; } else if(action->pseudo == FALSE && 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(action->runnable == FALSE) { crm_debug_3("Skipping pseudo-op: %s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); } else { crm_debug_2("Starting due to: %s", action->uuid); crm_debug_3("%s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); *starting = TRUE; } } ); } static action_t * find_rsc_action(resource_t *rsc, const char *key, gboolean active_only, GListPtr *list) { action_t *match = NULL; GListPtr possible = NULL; GListPtr active = NULL; possible = find_actions(rsc->actions, key, NULL); if(active_only) { slist_iter(op, action_t, possible, lpc, if(op->optional == FALSE) { active = g_list_append(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; gboolean active_only = TRUE; /* change to false to get the old behavior */ clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->ordered == FALSE) { return; } slist_iter( child, resource_t, rsc->children, lpc, 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_implies_left); } last_stop = stop; } if(start) { if(last_start) { /* child/child relative start */ order_actions(last_start, start, pe_order_implies_left); } 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; 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); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->create_actions(child_rsc, data_set); clone_update_pseudo_status( child_rsc, &child_stopping, &child_starting, &child_active); if(is_set(child_rsc->flags, pe_rsc_starting)) { last_start_rsc = child_rsc; } if(is_set(child_rsc->flags, pe_rsc_stopping)) { last_stop_rsc = child_rsc; } ); /* start */ start = start_action(rsc, NULL, !child_starting); started = custom_action(rsc, started_key(rsc), RSC_STARTED, NULL, !child_starting, TRUE, data_set); start->pseudo = TRUE; start->runnable = TRUE; started->pseudo = TRUE; started->priority = INFINITY; if(child_active || child_starting) { started->runnable = TRUE; } child_ordering_constraints(rsc, data_set); child_starting_constraints(clone_data, rsc, NULL, last_start_rsc, data_set); 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); stop->pseudo = TRUE; stop->runnable = TRUE; stopped->pseudo = TRUE; stopped->runnable = TRUE; stopped->priority = INFINITY; child_stopping_constraints(clone_data, rsc, NULL, last_stop_rsc, data_set); 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 child_starting_constraints( clone_variant_data_t *clone_data, resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(child == NULL && last == NULL) { crm_debug("%s has no active children", rsc->id); return; } if(child != NULL) { order_start_start( rsc, child, pe_order_runnable_left|pe_order_implies_left_printed); new_rsc_order(child, RSC_START, rsc, RSC_STARTED, pe_order_implies_right_printed, data_set); } if(FALSE && clone_data->ordered) { if(child == NULL) { /* last child start before global started */ new_rsc_order(last, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); } else if(last == NULL) { /* global start before first child start */ order_start_start( rsc, child, pe_order_implies_left); } else { /* child/child relative start */ order_start_start(last, child, pe_order_implies_left); } } } void child_stopping_constraints( clone_variant_data_t *clone_data, resource_t *rsc, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(child == NULL && last == NULL) { crm_debug("%s has no active children", rsc->id); return; } if(child != NULL) { order_stop_stop(rsc, child, pe_order_shutdown|pe_order_implies_left_printed); new_rsc_order(child, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_right_printed, data_set); } if(FALSE && clone_data->ordered) { if(last == NULL) { /* first child stop before global stopped */ new_rsc_order(child, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); } else if(child == NULL) { /* global stop before last child stop */ order_stop_stop( rsc, last, pe_order_implies_left); } else { /* child/child relative stop */ order_stop_stop(child, last, pe_order_implies_left); } } } void clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); native_internal_constraints(rsc, data_set); /* global stop before stopped */ new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set); /* global start before started */ new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); /* global stopped before start */ new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->internal_constraints(child_rsc, data_set); child_starting_constraints( clone_data, rsc, child_rsc, last_rsc, data_set); child_stopping_constraints( clone_data, rsc, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } resource_t* find_compatible_child( resource_t *local_child, resource_t *rsc, enum rsc_role_e filter, gboolean current) { node_t *local_node = NULL; node_t *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 == NULL) { crm_debug("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id); return NULL; } slist_iter( child_rsc, resource_t, rsc->children, lpc, 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_debug_2("Filtered %s", child_rsc->id); continue; } if(node && local_node && node->details == local_node->details) { crm_info("Colocating %s with %s on %s", local_child->id, child_rsc->id, node->details->uname); return child_rsc; } ); crm_debug("Can't colocate child %s with %s", local_child->id, rsc->id); return NULL; } void clone_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_interleave = FALSE; resource_t *rsc = constraint->rsc_lh; clone_variant_data_t *clone_data = NULL; clone_variant_data_t *clone_data_rh = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_clone_variant_data(clone_data, rsc); if(constraint->rsc_rh->variant == pe_clone || constraint->rsc_rh->variant == pe_master) { get_clone_variant_data( clone_data_rh, constraint->rsc_rh); if(clone_data->clone_node_max != clone_data_rh->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->interleave) { do_interleave = TRUE; } else if(constraint->score >= INFINITY) { GListPtr lhs = NULL, rhs = NULL; lhs = rsc_lh->allowed_nodes; slist_iter( child_rsc, resource_t, rsc_rh->children, lpc, node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); if(chosen != NULL) { rhs = g_list_append(rhs, chosen); } ); rsc_lh->allowed_nodes = node_list_exclude(lhs, rhs); pe_free_shallow_adv(rhs, FALSE); pe_free_shallow(lhs); return; } } else if(constraint->score >= INFINITY) { crm_config_err("Manditory co-location of clones (%s) with other" " non-clone (%s) resources is not supported", rsc_lh->id, rsc_rh->id); return; } if(do_interleave) { resource_t *rh_child = NULL; slist_iter(lh_child, resource_t, rsc->children, lpc, CRM_ASSERT(lh_child != NULL); rh_child = find_compatible_child( lh_child, rsc_rh, RSC_ROLE_UNKNOWN, FALSE); if(rh_child == NULL) { crm_debug_2("No match found for %s", lh_child->id); continue; } crm_debug("Interleaving %s with %s", lh_child->id, rh_child->id); lh_child->cmds->rsc_colocation_lh( lh_child, rh_child, constraint); ); return; } slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint); ); } void clone_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { clone_variant_data_t *clone_data = NULL; CRM_CHECK(rsc_lh != NULL, return); CRM_CHECK(rsc_lh->variant == pe_native, return); get_clone_variant_data(clone_data, rsc_rh); crm_debug_3("Processing constraint %s: %d", constraint->id, constraint->score); 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(constraint->score >= INFINITY) { GListPtr lhs = NULL, rhs = NULL; lhs = rsc_lh->allowed_nodes; slist_iter( child_rsc, resource_t, rsc_rh->children, lpc, node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE); if(chosen != NULL) { rhs = g_list_append(rhs, chosen); } ); rsc_lh->allowed_nodes = node_list_exclude(lhs, rhs); pe_free_shallow_adv(rhs, FALSE); pe_free_shallow(lhs); return; } slist_iter( child_rsc, resource_t, rsc_rh->children, lpc, child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); ); } +/* + + Clone <-> Clone ordering + + S : Start(ed) + S' : Stop(ped) + P : Promote(d) + D : Demote(d) + + Started == Demoted + + First A then B + A:0 B:0 + Old New Old New + + S' S' S S' + S' S' S' - + S' S S S+ + S' S S' S + S S' S S' + S S' S' - + S S S - + S S S' S + + S' S' P S' + S' S' S' - + S' P P P+ + S' P S' P + P S' P S' + P S' S' - + P P P - + P P S' P + + D D P D + D D D - + D P P P+ + D P D P + P D P D + P D D - + P P P - + P P D P + + Clone <-> Primitive ordering + + S : Start(ed) + S' : Stop(ped) + P : Promote(d) + D : Demote(d) + F : False + T : True + F' : A good idea? + + Started == Demoted + + First A then B + A:0 B + Old New Old Create Constraint + + S' S' S F + S' S' S' F' + S S' S T + S S' S' F + S' S S T + S' S S' T + S S S F' + S S S' T + + S' S' S F + S' S' S' F' + P S' S T + P S' S' F + S' P S T + S' P S' T + P P S F' + P P S' F + + S' S' S F + S' S' S' F' + D S' S T + D S' S' F + S' D S T + S' D S' T + D D S F' + D D S' T + +*/ +static gboolean detect_restart(resource_t *rsc) +{ + gboolean restart = FALSE; + + /* Look for restarts */ + action_t *start = NULL; + char *key = start_key(rsc); + GListPtr possible_matches = find_actions(rsc->actions, key, NULL); + crm_free(key); + + if(possible_matches) { + start = possible_matches->data; + g_list_free(possible_matches); + } + + if(start != NULL && start->optional == FALSE) { + restart = TRUE; + crm_debug_2("Detected a restart for %s", rsc->id); + } + +#if 1 + /* Shouldn't be required */ + + /* Otherwise, look for moves */ + if(restart == FALSE) { + GListPtr old_hosts = NULL; + GListPtr new_hosts = NULL; + GListPtr intersection = NULL; + + rsc->fns->location(rsc, &old_hosts, TRUE); + rsc->fns->location(rsc, &new_hosts, FALSE); + intersection = node_list_and(old_hosts, new_hosts, FALSE); + + if(intersection == NULL) { + restart = TRUE; /* Actually a move but the result is the same */ + crm_debug_2("Detected a move for %s", rsc->id); + } + + g_list_free(intersection); + g_list_free(old_hosts); + g_list_free(new_hosts); + } +#endif + return restart; +} + void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set) { resource_t *r1 = NULL; resource_t *r2 = NULL; gboolean do_interleave = FALSE; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_4("%s->%s", order->lh_action_task, order->rh_action_task); if(order->rh_rsc == NULL) { order->lh_action_task = convert_non_atomic_task(order->lh_action_task, FALSE, TRUE); native_rsc_order_lh(rsc, order, data_set); return; } r1 = uber_parent(rsc); r2 = uber_parent(order->rh_rsc); if(r1 == r2) { native_rsc_order_lh(rsc, order, data_set); return; } if(order->rh_rsc->variant > pe_group) { clone_variant_data_t *clone_data_rh = NULL; get_clone_variant_data(clone_data_rh, order->rh_rsc); if(clone_data->clone_node_max != clone_data_rh->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", rsc->id, order->rh_rsc->id); /* only the LHS side needs to be labeled as interleave */ } else if(clone_data->interleave) { do_interleave = TRUE; } } if(order->rh_rsc == NULL) { do_interleave = FALSE; } if(do_interleave) { resource_t *lh_child = NULL; resource_t *rh_saved = order->rh_rsc; gboolean current = FALSE; if(strstr(order->lh_action_task, "_stop_0") || strstr(order->lh_action_task, "_demote_0")) { current = TRUE; } slist_iter( rh_child, resource_t, rh_saved->children, lpc, CRM_ASSERT(rh_child != NULL); lh_child = find_compatible_child(rh_child, rsc, RSC_ROLE_UNKNOWN, current); if(lh_child == NULL) { crm_debug_2("No match found for %s", rh_child->id); continue; } crm_notice("Interleaving %s with %s", lh_child->id, rh_child->id); order->rh_rsc = rh_child; lh_child->cmds->rsc_order_lh(lh_child, order, data_set); order->rh_rsc = rh_saved; ); } else { #if 0 if(order->type != pe_order_optional) { crm_debug("Upgraded ordering constraint %d - 0x%.6x", order->id, order->type); native_rsc_order_lh(rsc, order, data_set); } #endif if(order->rh_rsc->variant < pe_clone) { GListPtr hosts = NULL; GListPtr rh_hosts = NULL; GListPtr intersection = NULL; + const char *reason = "unknown"; - gboolean down_stack = TRUE; - enum rsc_role_e lh_role = RSC_ROLE_STARTED; enum action_tasks task = start_rsc; + enum rsc_role_e lh_role = RSC_ROLE_STARTED; + + int any_ordered = 0; + gboolean down_stack = TRUE; crm_debug_2("Clone-to-* ordering: %s -> %s 0x%.6x", order->lh_action_task, order->rh_action_task, order->type); - if(strstr(order->rh_action_task, "_"RSC_STOP"_0") || strstr(order->rh_action_task, "_"RSC_STOPPED"_0")) { task = stop_rsc; - reason = "down activiity"; + reason = "down activity"; lh_role = RSC_ROLE_STOPPED; - order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, TRUE); + order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, down_stack); } else if(strstr(order->rh_action_task, "_"RSC_DEMOTE"_0") || strstr(order->rh_action_task, "_"RSC_DEMOTED"_0")) { task = action_demote; - reason = "demotion activiity"; + reason = "demotion activity"; lh_role = RSC_ROLE_SLAVE; - order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, TRUE); + order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, down_stack); - } else if(strstr(order->rh_action_task, "_"RSC_PROMOTE"_0") - || strstr(order->rh_action_task, "_"RSC_PROMOTED"_0")) { + } else if(strstr(order->lh_action_task, "_"RSC_PROMOTE"_0") + || strstr(order->lh_action_task, "_"RSC_PROMOTED"_0")) { task = action_promote; down_stack = FALSE; - reason = "promote activiity"; - order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, FALSE); + reason = "promote activity"; + order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, down_stack); lh_role = RSC_ROLE_MASTER; } else if(strstr(order->rh_action_task, "_"RSC_START"_0") || strstr(order->rh_action_task, "_"RSC_STARTED"_0")) { task = start_rsc; down_stack = FALSE; - reason = "up activiity"; - order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, FALSE); + reason = "up activity"; + order->rh_rsc->fns->location(order->rh_rsc, &rh_hosts, down_stack); /* if(order->rh_rsc->variant > pe_clone) { */ /* lh_role = RSC_ROLE_SLAVE; */ /* } */ } else { crm_err("WTF: %s", order->rh_action_task); } - /* slist_iter(h, node_t, rh_hosts, llpc, */ - /* crm_info("RHH: %s", h->details->uname)); */ + /* slist_iter(h, node_t, rh_hosts, llpc, crm_info("RHH: %s", h->details->uname)); */ slist_iter( child_rsc, resource_t, rsc->children, lpc, - + + gboolean create = FALSE; + gboolean restart = FALSE; + enum rsc_role_e lh_role_new = child_rsc->fns->state(child_rsc, FALSE); + enum rsc_role_e lh_role_old = child_rsc->fns->state(child_rsc, TRUE); enum rsc_role_e child_role = child_rsc->fns->state(child_rsc, down_stack); + crm_info("Testing %s->%s for %s: %s vs. %s %s", order->lh_action_task, order->rh_action_task, child_rsc->id, role2text(lh_role), role2text(child_role), order->lh_action_task); - - if(down_stack && child_role > lh_role) { - child_rsc->fns->location(child_rsc, &hosts, down_stack); - /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ - } else if(child_role > lh_role) { - child_rsc->fns->location(child_rsc, &hosts, down_stack); - /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ - } else { - reason = "role"; + if(rh_hosts == NULL) { + crm_info("Terminating search: %s.%d list is empty: no possible %s", order->rh_rsc->id, down_stack, reason); + break; } - /* slist_iter(h, node_t, hosts, llpc, */ - /* crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + if(lh_role_new == lh_role_old) { + /* TODO: Check for restarts */ + crm_info("Ignoring %s->%s for %s: no relevant %s (no role change)", + order->lh_action_task, order->rh_action_task, child_rsc->id, reason); + continue; + } + hosts = NULL; + child_rsc->fns->location(child_rsc, &hosts, down_stack); intersection = node_list_and(hosts, rh_hosts, FALSE); - if(intersection != NULL) { - crm_info("Enforcing %s->%s for %s on %s: found %s", - order->lh_action_task, order->rh_action_task, child_rsc->id, ((node_t*)intersection->data)->details->uname, reason); - native_rsc_order_lh(child_rsc, order, data_set); + /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + if(intersection == NULL) { + crm_info("Ignoring %s->%s for %s: no relevant %s", + order->lh_action_task, order->rh_action_task, child_rsc->id, reason); + g_list_free(hosts); + continue; + } + + if(restart) { + reason = "restart"; + create = TRUE; + + } else if(down_stack) { + if(lh_role_old > lh_role) { + create = TRUE; + } + } else if(down_stack == FALSE) { + if(lh_role_old < lh_role) { + create = TRUE; + } + } else { - crm_debug("Ignoring %s->%s for %s: no relevant %s", - order->lh_action_task, order->rh_action_task, child_rsc->id, reason); + any_ordered++; + reason = "role"; + crm_notice("Role: %s->%s for %s: %s vs. %s %s", + order->lh_action_task, order->rh_action_task, child_rsc->id, + role2text(lh_role_old), role2text(lh_role), order->lh_action_task); + + } + + if(create) { +#if 1 + native_rsc_order_lh(child_rsc, order, data_set); +#else + enum pe_ordering type = order->type; + child_rsc->cmds->rsc_order_lh(child_rsc, order, data_set); + order->type = pe_order_optional; + native_rsc_order_lh(rsc, order, data_set); + order->type = type; +#endif + any_ordered++; + crm_info("Enforced %s->%s for %s on %s: found %s", + order->lh_action_task, order->rh_action_task, child_rsc->id, + ((node_t*)intersection->data)->details->uname, reason); } + crm_info("Processed %s->%s for %s on %s: %s", + order->lh_action_task, order->rh_action_task, child_rsc->id, + ((node_t*)intersection->data)->details->uname, reason); + + /* slist_iter(h, node_t, hosts, llpc, */ + /* crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + g_list_free(intersection); - g_list_free(hosts); hosts = NULL; + g_list_free(hosts); + ); g_list_free(rh_hosts); - + if(any_ordered == 0 && down_stack == FALSE) { + crm_err("here"); + order->lh_action_task = convert_non_atomic_task(order->lh_action_task, FALSE, TRUE); + native_rsc_order_lh(rsc, order, data_set); + } + order->type = pe_order_optional; + } else if(order->type & pe_order_implies_left) { if(rsc->variant == order->rh_rsc->variant) { - crm_debug_2("Clone-to-clone ordering: %s -> %s 0x%.6x", + crm_debug_2("Clone-to-clone ordering: %s -> %s 0x%.6x", order->lh_action_task, order->rh_action_task, order->type); - /* stop instances on the same nodes as stopping RHS instances */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - native_rsc_order_lh(child_rsc, order, data_set); - ); + /* stop instances on the same nodes as stopping RHS instances */ + slist_iter( + child_rsc, resource_t, rsc->children, lpc, + native_rsc_order_lh(child_rsc, order, data_set); + ); } else { /* stop everything */ - slist_iter( - child_rsc, resource_t, rsc->children, lpc, - native_rsc_order_lh(child_rsc, order, data_set); - ); + slist_iter( + child_rsc, resource_t, rsc->children, lpc, + native_rsc_order_lh(child_rsc, order, data_set); + ); } } } - + if(do_interleave == FALSE || clone_data->ordered) { order->lh_action_task = convert_non_atomic_task(order->lh_action_task, FALSE, TRUE); native_rsc_order_lh(rsc, order, data_set); } if(is_set(rsc->flags, pe_rsc_notify)) { order->type = pe_order_optional; order->lh_action_task = convert_non_atomic_task(order->lh_action_task, TRUE, TRUE); native_rsc_order_lh(rsc, order, data_set); } } - + void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { enum pe_ordering type = order->type; clone_variant_data_t *clone_data = NULL; resource_t *lh_p = uber_parent(lh_action->rsc); get_clone_variant_data(clone_data, rsc); crm_debug_2("%s->%s", order->lh_action_task, order->rh_action_task); if(safe_str_eq(CRM_OP_PROBED, lh_action->uuid)) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_order_rh(lh_action, child_rsc, order); ); if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED && rsc->fns->state(rsc, FALSE) > RSC_ROLE_STOPPED) { order->type |= pe_order_implies_right; } } else if(lh_p && lh_p != rsc && lh_p->variant < pe_clone) { GListPtr hosts = NULL; GListPtr lh_hosts = NULL; GListPtr intersection = NULL; const char *reason = "unknown"; + + gboolean restart = FALSE; gboolean down_stack = TRUE; + enum rsc_role_e rh_role = RSC_ROLE_STARTED; enum action_tasks task = start_rsc; + + enum rsc_role_e lh_role_new = lh_p->fns->state(lh_p, FALSE); + enum rsc_role_e lh_role_old = lh_p->fns->state(lh_p, TRUE); if(strstr(order->rh_action_task, "_"RSC_STOP"_0") || strstr(order->rh_action_task, "_"RSC_STOPPED"_0")) { task = stop_rsc; - reason = "down activiity"; + reason = "down activity"; rh_role = RSC_ROLE_STOPPED; - lh_p->fns->location(lh_p, &lh_hosts, TRUE); + lh_p->fns->location(lh_p, &lh_hosts, down_stack); } else if(strstr(order->rh_action_task, "_"RSC_DEMOTE"_0") || strstr(order->rh_action_task, "_"RSC_DEMOTED"_0")) { task = action_demote; rh_role = RSC_ROLE_SLAVE; - reason = "demotion activiity"; - lh_p->fns->location(lh_p, &lh_hosts, TRUE); + reason = "demotion activity"; + lh_p->fns->location(lh_p, &lh_hosts, down_stack); } else if(strstr(order->rh_action_task, "_"RSC_PROMOTE"_0") || strstr(order->rh_action_task, "_"RSC_PROMOTED"_0")) { task = action_promote; down_stack = FALSE; - reason = "promote activiity"; - lh_p->fns->location(lh_p, &lh_hosts, FALSE); + reason = "promote activity"; + lh_p->fns->location(lh_p, &lh_hosts, down_stack); rh_role = RSC_ROLE_MASTER; } else if(strstr(order->rh_action_task, "_"RSC_START"_0") || strstr(order->rh_action_task, "_"RSC_STARTED"_0")) { task = start_rsc; down_stack = FALSE; - reason = "up activiity"; - lh_p->fns->location(lh_p, &lh_hosts, FALSE); + reason = "up activity"; + lh_p->fns->location(lh_p, &lh_hosts, down_stack); + } else { crm_err("WTF: %s", order->rh_action_task); } + + if(lh_role_new == lh_role_old) { + restart = detect_restart(lh_action->rsc); + + if(FALSE && restart == FALSE) { + crm_info("Ignoring %s->%s for %s: no relevant %s (no role change)", + lh_action->task, order->rh_action_task, lh_p->id, reason); + goto cleanup; + } + } /* slist_iter(h, node_t, lh_hosts, llpc, crm_info("LHH: %s", h->details->uname)); */ - slist_iter( child_rsc, resource_t, rsc->children, lpc, + gboolean create = FALSE; enum rsc_role_e child_role = child_rsc->fns->state(child_rsc, down_stack); - crm_info("Testing for %s: %s->%s for %s: %s vs. %s: %d", - reason, order->lh_action_task, order->rh_action_task, child_rsc->id, - role2text(child_role), role2text(rh_role), down_stack); - - if(down_stack && child_role > rh_role) { - child_rsc->fns->location(child_rsc, &hosts, down_stack); - /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ - } else if(child_role >= rh_role) { - child_rsc->fns->location(child_rsc, &hosts, down_stack); - /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + crm_info("Testing %s->%s for %s: %s vs. %s %s", + lh_action->task, order->rh_action_task, child_rsc->id, + role2text(rh_role), role2text(child_role), order->rh_action_task); + + if(lh_hosts == NULL) { + crm_info("Terminating search: %s.%d list is empty: no possible %s", order->rh_rsc->id, down_stack, reason); + break; + } + + hosts = NULL; + child_rsc->fns->location(child_rsc, &hosts, down_stack); + intersection = node_list_and(hosts, lh_hosts, FALSE); + if(intersection == NULL) { + crm_info("Ignoring %s->%s for %s: no relevant %s", + lh_action->task, order->rh_action_task, child_rsc->id, reason); + g_list_free(hosts); + continue; + } + + /* slist_iter(h, node_t, hosts, llpc, crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + if(restart) { + reason = "restart"; + create = TRUE; + + } else if(down_stack && lh_role_old >= rh_role) { + create = TRUE; + + } else if(down_stack == FALSE && lh_role_old <= rh_role) { + create = TRUE; + } else { reason = "role"; } - - intersection = node_list_and(hosts, lh_hosts, FALSE); - if(intersection != NULL) { + + if(create) { enum pe_ordering type = order->type; crm_info("Enforcing %s->%s for %s on %s: found %s", order->lh_action_task, order->rh_action_task, child_rsc->id, ((node_t*)intersection->data)->details->uname, reason); child_rsc->cmds->rsc_order_rh(lh_action, child_rsc, order); order->type = pe_order_optional; native_rsc_order_rh(lh_action, rsc, order); order->type = type; - - } else { - crm_debug("Ignoring %s->%s for %s: no relevant %s", - order->lh_action_task, order->rh_action_task, child_rsc->id, reason); } - + + crm_info("Processed %s->%s for %s on %s: found %s", + lh_action->task, order->rh_action_task, child_rsc->id, + ((node_t*)intersection->data)->details->uname, reason); + + /* slist_iter(h, node_t, hosts, llpc, */ + /* crm_info("H: %s %s", child_rsc->id, h->details->uname)); */ + g_list_free(intersection); - g_list_free(hosts); hosts = NULL; + g_list_free(hosts); ); - + cleanup: g_list_free(lh_hosts); return; } - + native_rsc_order_rh(lh_action, rsc, order); order->type = type; } void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing location constraint %s for %s", constraint->id, rsc->id); native_rsc_location(rsc, constraint); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_location(child_rsc, constraint); ); } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_2("Processing actions from %s", rsc->id); 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 */ slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->expand(child_rsc, data_set)); native_expand(rsc, data_set); /* The notifications are in the graph now, we can destroy the notify_data */ free_notification_data(clone_data->demote_notify); free_notification_data(clone_data->stop_notify); free_notification_data(clone_data->start_notify); free_notification_data(clone_data->promote_notify); } 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); } static resource_t *find_instance_on(resource_t *rsc, node_t *node) { slist_iter(child, resource_t, rsc->children, lpc, GListPtr known_list = NULL; rsc_known_on(child, &known_list); slist_iter(known, node_t, known_list, lpc2, if(node->details == known->details) { g_list_free(known_list); return child; } ); g_list_free(known_list); ); return NULL; } gboolean clone_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { gboolean any_created = FALSE; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); 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 */ slist_iter( child_rsc, resource_t, rsc->children, lpc, 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); } slist_iter( child_rsc, resource_t, rsc->children, lpc, if(child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set)) { any_created = TRUE; } 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; } diff --git a/pengine/native.c b/pengine/native.c index 77f5f3c5fe..89ff52b51a 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -1,2157 +1,2158 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #define DELETE_THEN_REFRESH 1 /* The crmd will remove the resource from the CIB itself, making this redundant */ #define VARIANT_NATIVE 1 #include void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); 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, }, }; static gboolean native_choose_node(resource_t *rsc) { /* 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 */ GListPtr nodes = NULL; node_t *chosen = NULL; int lpc = 0; int multiple = 0; int length = g_list_length(rsc->allowed_nodes); if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to?TRUE:FALSE; } crm_debug_3("Choosing node for %s from %d candidates", rsc->id, length); if(rsc->allowed_nodes) { rsc->allowed_nodes = g_list_sort(rsc->allowed_nodes, sort_node_weight); nodes = rsc->allowed_nodes; chosen = g_list_nth_data(nodes, 0); if(chosen && chosen->weight > 0 && can_run_resources(chosen)) { node_t *running = g_list_nth_data(rsc->running_on, 0); if(can_run_resources(running) == FALSE) { running = NULL; } for(lpc = 1; lpc < length; lpc++) { node_t *tmp = g_list_nth_data(nodes, lpc); if(tmp->weight == chosen->weight) { multiple++; if(running && tmp->details == running->details) { /* prefer the existing node if scores are equal */ chosen = tmp; } } } } } 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); } return native_assign_node(rsc, nodes, chosen, FALSE); } int node_list_attr_score(GListPtr list, const char *attr, const char *value) { int best_score = -INFINITY; const char *best_node = NULL; if(attr == NULL) { attr = "#"XML_ATTR_UNAME; } slist_iter(node, node_t, list, lpc, 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_list_update(GListPtr list1, GListPtr list2, const char *attr, int factor) { int score = 0; if(attr == NULL) { attr = "#"XML_ATTR_UNAME; } slist_iter( node, node_t, list1, lpc, CRM_CHECK(node != NULL, continue); score = node_list_attr_score(list2, attr, g_hash_table_lookup(node->details->attrs, attr)); 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 * */ continue; } crm_debug_2("%s: %d + %d*%d", node->details->uname, node->weight, factor, score); node->weight = merge_weights(factor*score, node->weight); ); } GListPtr native_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, const char *attr, int factor, gboolean allow_rollback) { GListPtr archive = NULL; int multiplier = 1; if(factor < 0) { multiplier = -1; } if(is_set(rsc->flags, pe_rsc_merging)) { crm_info("%s: Breaking dependancy 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); if(allow_rollback) { archive = node_list_dup(nodes, FALSE, FALSE); } node_list_update(nodes, rsc->allowed_nodes, attr, factor); if(can_run_any(nodes) == FALSE) { if(archive) { crm_info("%s: Rolling back scores from %s", rhs, rsc->id); pe_free_shallow_adv(nodes, TRUE); nodes = archive; } goto bail; } pe_free_shallow_adv(archive, TRUE); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, crm_info("%s: Rolling back scores from %s", rhs, rsc->id); nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rhs, nodes, constraint->node_attribute, multiplier*constraint->score/INFINITY, allow_rollback); ); bail: clear_bit(rsc->flags, pe_rsc_merging); return nodes; } node_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { int alloc_details = scores_log_level+1; 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->color(rsc->parent, data_set); } if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to; } if(is_set(rsc->flags, pe_rsc_allocating)) { crm_debug("Dependancy 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); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, resource_t *rsc_rh = constraint->rsc_rh; crm_debug_2("%s: Pre-Processing %s (%s)", rsc->id, constraint->id, rsc_rh->id); rsc_rh->cmds->color(rsc_rh, data_set); rsc->cmds->rsc_colocation_lh(rsc, rsc_rh, constraint); ); dump_node_scores(alloc_details, rsc, "Post-coloc", rsc->allowed_nodes); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rsc->id, rsc->allowed_nodes, constraint->node_attribute, constraint->score/INFINITY, TRUE); ); 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)) { 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) ) { 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)) { pe_warn("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; xml_child_iter_filter( rsc->ops_xml, operation, "op", value = crm_element_value(operation, "name"); if(safe_str_neq(value, name)) { continue; } value = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); if(value == NULL) { value = "0"; } if(safe_str_neq(value, interval)) { continue; } if(id == NULL) { id = ID(operation); } else { crm_config_err("Operation %s is a duplicate of %s", ID(operation), id); crm_config_err("Do not use the same (name, interval) combination more than once per resource"); dup = TRUE; } ); return dup; } void RecurringOp(resource_t *rsc, action_t *start, node_t *node, xmlNode *operation, pe_working_set_t *data_set) { char *key = NULL; const char *name = NULL; const char *value = NULL; const char *interval = NULL; const char *node_uname = NULL; 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; } key = generate_op_key(rsc->id, name, interval_ms); if(find_rsc_op_entry(rsc, key) == NULL) { /* disabled */ return; } if(start != NULL) { crm_debug_3("Marking %s %s due to %s", key, start->optional?"optional":"manditory", start->uuid); is_optional = start->optional; } else { crm_debug_2("Marking %s optional", key); is_optional = TRUE; } /* start a monitor for an already active resource */ possible_matches = find_actions_exact(rsc->actions, key, node); if(possible_matches == NULL) { is_optional = FALSE; crm_debug_3("Marking %s manditory: not active", key); } 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 || start->runnable == FALSE) { crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_notice(" 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_right|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)) { xml_child_iter_filter( rsc->ops_xml, operation, "op", RecurringOp(rsc, start, node, operation, data_set); ); } } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; node_t *chosen = NULL; enum rsc_role_e role = RSC_ROLE_UNKNOWN; enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; 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); if(g_list_length(rsc->running_on) > 1) { if(rsc->recovery_type == recovery_stop_start) { pe_proc_warn("Attempting recovery of resource %s", rsc->id); if(rsc->role == RSC_ROLE_MASTER) { DemoteRsc(rsc, NULL, FALSE, data_set); } StopRsc(rsc, NULL, FALSE, data_set); rsc->role = RSC_ROLE_STOPPED; } } else if(rsc->running_on != NULL) { node_t *current = rsc->running_on->data; NoRoleChange(rsc, current, chosen, data_set); } else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) { char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, NULL); slist_iter( action, action_t, possible_matches, lpc, action->optional = TRUE; /* 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) { int type = pe_order_optional; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); if(rsc->variant == pe_native) { type |= pe_order_implies_right; } if(rsc->parent == NULL || rsc->parent->variant == pe_group) { type |= pe_order_restart; } new_rsc_order(rsc, RSC_STOP, rsc, RSC_START, type, data_set); new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_STOP, pe_order_demote_stop, data_set); new_rsc_order(rsc, RSC_START, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set); new_rsc_order(rsc, RSC_DELETE, rsc, RSC_START, pe_order_optional, 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(rsc->variant == pe_native && safe_str_neq(class, "stonith")) { custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(all_stopped->task), all_stopped, pe_order_implies_right|pe_order_runnable_left, 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; gboolean do_check = FALSE; const char *attribute = "#id"; 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; } slist_iter( node, node_t, rsc_lh->allowed_nodes, lpc, 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); } ); } 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); } } static GListPtr find_actions_by_task(GListPtr actions, resource_t *rsc, const char *original_key) { GListPtr list = NULL; list = find_actions(actions, original_key, NULL); if(list == NULL) { /* we're potentially searching a child of the original resource */ char *key = NULL; char *tmp = NULL; char *task = NULL; int interval = 0; if(parse_op_key(original_key, &tmp, &task, &interval)) { key = generate_op_key(rsc->id, task, interval); /* crm_err("looking up %s instead of %s", key, original_key); */ /* slist_iter(action, action_t, actions, lpc, */ /* crm_err(" - %s", action->uuid)); */ list = find_actions(actions, key, NULL); } else { crm_err("search key: %s", original_key); } crm_free(key); crm_free(tmp); crm_free(task); } return list; } void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order, pe_working_set_t *data_set) { GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; resource_t *rh_rsc = order->rh_rsc; crm_debug_3("Processing LH of ordering constraint %d", order->id); CRM_ASSERT(lh_rsc != NULL); if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL) { lh_actions = find_actions_by_task( lh_rsc->actions, lh_rsc, order->lh_action_task); } if(lh_actions == NULL && lh_rsc != rh_rsc) { char *key = NULL; char *rsc_id = NULL; char *op_type = NULL; int interval = 0; crm_debug_4("No LH-Side (%s/%s) found for constraint %d with %s - creating", lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task); parse_op_key( order->lh_action_task, &rsc_id, &op_type, &interval); key = generate_op_key(lh_rsc->id, op_type, interval); lh_action = custom_action(lh_rsc, key, op_type, NULL, TRUE, TRUE, data_set); if(lh_rsc->fns->state(lh_rsc, TRUE) == RSC_ROLE_STOPPED && safe_str_eq(op_type, RSC_STOP)) { lh_action->pseudo = TRUE; lh_action->runnable = TRUE; } lh_actions = g_list_append(NULL, lh_action); crm_free(op_type); crm_free(rsc_id); } slist_iter( lh_action_iter, action_t, lh_actions, lpc, if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { rh_rsc->cmds->rsc_order_rh( lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions( lh_action_iter, order->rh_action, order->type); } ); pe_free_shallow_adv(lh_actions, FALSE); } void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { GListPtr rh_actions = NULL; action_t *rh_action = NULL; CRM_CHECK(rsc != NULL, return); CRM_CHECK(order != NULL, return); rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_append(NULL, rh_action); } else if(rsc != NULL) { rh_actions = find_actions_by_task( rsc->actions, rsc, order->rh_action_task); } if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id,order->rh_action_task); if(lh_action) { crm_debug_4("LH-Side was: %s", lh_action->uuid); } return; } slist_iter( rh_action_iter, action_t, rh_actions, lpc, if(lh_action) { order_actions(lh_action, rh_action_iter, order->type); } else if(order->type & pe_order_implies_right) { rh_action_iter->runnable = FALSE; crm_warn("Unrunnable %s 0x%.6x", rh_action_iter->uuid, order->type); } else { crm_warn("neither %s 0x%.6x", rh_action_iter->uuid, order->type); } ); pe_free_shallow_adv(rh_actions, FALSE); } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr or_list; crm_debug_2("Applying %s (%s) to %s", constraint->id, role2text(constraint->role_filter), rsc->id); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } or_list = node_list_or( rsc->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(rsc->allowed_nodes); rsc->allowed_nodes = or_list; slist_iter(node, node_t, or_list, lpc, crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight); ); } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { crm_debug_3("Processing actions from %s", rsc->id); slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, data_set); ); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->expand(child_rsc, data_set); ); } void LogActions(resource_t *rsc, pe_working_set_t *data_set) { node_t *next = NULL; node_t *current = NULL; gboolean moving = FALSE; if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, LogActions(child_rsc, data_set); ); return; } next = rsc->allocated_to; if(rsc->running_on) { current = rsc->running_on->data; if(rsc->role == RSC_ROLE_STOPPED) { /* * This can occur when resources are being recovered * We fiddle with the current role in native_create_actions() */ rsc->role = RSC_ROLE_STARTED; } } if(current == NULL && is_set(rsc->flags, pe_rsc_orphan)) { /* Don't log stopped orphans */ return; } if(is_not_set(rsc->flags, pe_rsc_managed) || (current == NULL && next == NULL)) { crm_notice("Leave resource %s\t(%s%s)", rsc->id, role2text(rsc->role), is_not_set(rsc->flags, pe_rsc_managed)?" unmanaged":""); return; } if(current != NULL && next != NULL && safe_str_neq(current->details->id, next->details->id)) { moving = TRUE; } if(rsc->role == rsc->next_role) { action_t *start = NULL; char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, next); crm_free(key); if(possible_matches) { start = possible_matches->data; g_list_free(possible_matches); } key = generate_op_key(rsc->id, CRMD_ACTION_MIGRATED, 0); possible_matches = find_actions(rsc->actions, key, next); crm_free(key); CRM_CHECK(next != NULL,); if(next == NULL) { } else if(possible_matches) { crm_notice("Migrate resource %s\t(%s %s -> %s)", rsc->id, role2text(rsc->role), current->details->uname, next->details->uname); g_list_free(possible_matches); } else if(start == NULL || start->optional) { crm_notice("Leave resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else if(moving && current) { crm_notice("Move resource %s\t(%s %s -> %s)", rsc->id, role2text(rsc->role), current->details->uname, next->details->uname); } else if(is_set(rsc->flags, pe_rsc_failed)) { crm_notice("Recover resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else if(start && start->runnable == FALSE) { crm_notice("Stop resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } else { crm_notice("Restart resource %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname); } return; } if(rsc->role > RSC_ROLE_SLAVE && rsc->role > rsc->next_role) { CRM_CHECK(current != NULL,); if(current != NULL) { crm_notice("Demote %s\t(%s -> %s %s)", rsc->id, role2text(rsc->role), role2text(rsc->next_role), current->details->uname); } } if(rsc->next_role == RSC_ROLE_STOPPED || moving) { CRM_CHECK(current != NULL,); slist_iter(node, node_t, rsc->running_on, lpc, crm_notice("Stop resource %s\t(%s)", rsc->id, node->details->uname)); } if(rsc->role == RSC_ROLE_STOPPED || moving) { CRM_CHECK(next != NULL,); if(next != NULL) { crm_notice("Start %s\t(%s)", rsc->id, next->details->uname); } } if(rsc->next_role > RSC_ROLE_SLAVE && rsc->role < rsc->next_role) { CRM_CHECK(next != NULL,); crm_notice("Promote %s\t(%s -> %s %s)", rsc->id, role2text(rsc->role), role2text(rsc->next_role), next->details->uname); } } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { action_t *stop = NULL; action_t *start = NULL; GListPtr possible_matches = NULL; 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); slist_iter(match, action_t, possible_matches, lpc, if(match->optional == FALSE) { crm_debug("Fixing recurring action: %s", match->uuid); match->optional = TRUE; } ); g_list_free(possible_matches); } else if(is_set(rsc->flags, pe_rsc_start_pending)) { start = start_action(rsc, next, TRUE); if(start->runnable) { /* wait for StartRsc() to be called */ rsc->role = RSC_ROLE_STOPPED; } else { /* wait for StopRsc() to be called */ rsc->next_role = RSC_ROLE_STOPPED; } } else { stop = stop_action(rsc, current, TRUE); start = start_action(rsc, next, TRUE); stop->optional = start->optional; if(rsc->next_role > RSC_ROLE_STARTED) { DemoteRsc(rsc, current, start->optional, data_set); } StopRsc(rsc, current, start->optional, data_set); StartRsc(rsc, current, start->optional, data_set); if(rsc->next_role == RSC_ROLE_MASTER) { PromoteRsc(rsc, next, start->optional, data_set); } if(start->runnable == FALSE) { rsc->next_role = RSC_ROLE_STOPPED; } } } gboolean StopRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { action_t *stop = 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_implies_left|pe_order_stonith_stop, data_set); } slist_iter( current, node_t, rsc->running_on, lpc, stop = 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(start->runnable && optional == FALSE) { start->optional = FALSE; } return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { char *key = NULL; gboolean runnable = TRUE; GListPtr action_list = NULL; crm_debug_2("Executing: %s", rsc->id); CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, crm_err("Next role: %s", role2text(rsc->next_role)); return FALSE); CRM_CHECK(next != NULL, return FALSE); key = start_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); slist_iter(start, action_t, action_list, lpc, if(start->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); slist_iter(promote, action_t, action_list, lpc, promote->runnable = FALSE; ); g_list_free(action_list); return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); /* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */ slist_iter( current, node_t, rsc->running_on, lpc, demote_action(rsc, current, optional); ); return TRUE; } 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_right:pe_order_implies_left, 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> gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { char *key = NULL; char *target_rc = NULL; action_t *probe = NULL; node_t *running = NULL; resource_t *top = uber_parent(rsc); CRM_CHECK(node != NULL, return FALSE); if(rsc->children) { gboolean any_created = FALSE; slist_iter( child_rsc, resource_t, rsc->children, lpc, any_created = child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set) || any_created; ); return any_created; } if(is_set(rsc->flags, pe_rsc_orphan)) { crm_debug_2("Skipping orphan: %s", rsc->id); return FALSE; } running = pe_find_node_id(rsc->known_on, node->details->id); if(force == FALSE && running != NULL) { /* we already know the status of the resource on this node */ crm_debug_3("Skipping active: %s", rsc->id); return FALSE; } 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() */ char *clone_id = clone_zero(rsc->id); resource_t *peer = pe_find_resource(top->children, clone_id); while(peer && running == NULL) { running = pe_find_node_id(peer->known_on, node->details->id); if(force == FALSE && 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 FALSE; } clone_id = increment_clone(clone_id); peer = pe_find_resource(data_set->resources, clone_id); } crm_free(clone_id); } key = generate_op_key(rsc->id, RSC_STATUS, 0); probe = custom_action(rsc, key, RSC_STATUS, node, FALSE, TRUE, data_set); probe->optional = FALSE; running = pe_find_node_id(rsc->running_on, node->details->id); if(running == NULL) { target_rc = crm_itoa(EXECRA_NOT_RUNNING); } else if(rsc->role == RSC_ROLE_MASTER) { target_rc = crm_itoa(EXECRA_RUNNING_MASTER); } if(target_rc != NULL) { add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc); crm_free(target_rc); } crm_debug("Probing %s on %s (%s)", rsc->id, node->details->uname, role2text(rsc->role)); order_actions(probe, complete, pe_order_implies_right); 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, data_set); } else { action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); action_t *stonith_done = get_pseudo_op(STONITH_DONE, data_set); slist_iter(action, action_t, rsc->actions, lpc2, if(action->needs == rsc_req_stonith) { order_actions(stonith_done, action, pe_order_implies_left); } else if(target != NULL && safe_str_eq(action->task, RSC_START) && NULL == pe_find_node_id( 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_info("Ordering %s after %s recovery", action->uuid, target->details->uname); order_actions(all_stopped, action, pe_order_implies_left|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 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 */ slist_iter( action, action_t, action_list, lpc2, resource_t *parent = NULL; 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 */ action->pseudo = TRUE; action->runnable = TRUE; action->implied_by_stonith = TRUE; 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); } /* find the top-most resource */ parent = rsc->parent; while(parent != NULL && parent->parent != NULL) { parent = parent->parent; } if(parent) { crm_debug_2("Re-creating actions for %s", parent->id); parent->cmds->create_actions(parent, data_set); /* make sure we dont mess anything up in create_actions */ CRM_CHECK(action->pseudo, action->pseudo = TRUE); CRM_CHECK(action->runnable, action->runnable = TRUE); } /* 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" dependancy 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" dependancy 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); slist_iter( action, action_t, action_list, lpc2, if(action->node->details->online == FALSE || is_set(rsc->flags, pe_rsc_failed)) { crm_info("Demote of failed resource %s is" " implict after %s is fenced", rsc->id, action->node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; if(is_stonith == FALSE) { order_actions(stonith_op, action, pe_order_optional); } } ); g_list_free(action_list); } void complex_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) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->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); } #define ALLOW_WEAK_MIGRATION 0 enum stack_activity { stack_stable = 0, stack_starting = 1, stack_stopping = 2, stack_middle = 4, }; static enum stack_activity find_clone_activity_on(resource_t *rsc, resource_t *target, node_t *node, const char *type) { int mode = stack_stable; action_t *active = NULL; if(target->children) { slist_iter( child, resource_t, target->children, lpc, mode |= find_clone_activity_on(rsc, child, node, type); ); return mode; } active = find_first_action(target->actions, NULL, CRMD_ACTION_START, NULL); if(active && active->optional == FALSE && active->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 && active->optional == FALSE && active->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_rsc->variant == pe_native) { + } else if(other_p->variant == pe_native) { crm_notice("Cannot migrate %s due to dependancy on %s (%s)", rsc->id, other_rsc->id, type); return stack_middle; } else if(other_rsc == rsc->parent) { int mode = 0; slist_iter(constraint, rsc_colocation_t, other_rsc->rsc_cons, lpc, if(constraint->score > 0) { mode |= check_stack_element(rsc, constraint->rsc_rh, type); } ); return mode; - } else if(other_rsc->variant == pe_group) { + } else if(other_p->variant == pe_group) { crm_notice("Cannot migrate %s due to dependancy 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; key = start_key(rsc); action_list = find_actions(rsc->actions, key, NULL); crm_free(key); crm_debug_3("%s: processing", rsc->id); CRM_CHECK(action_list != NULL, return FALSE); start = action_list->data; g_list_free(action_list); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, resource_t *target = constraint->rsc_rh; crm_debug_4("Checking %s: %s == %s (%d)", constraint->id, rsc->id, target->id, constraint->score); if(constraint->score > 0) { mode |= check_stack_element(rsc, target, "coloc"); if(mode & stack_middle) { return FALSE; } else if((mode & stack_stopping) && (mode & stack_starting)) { crm_notice("Cannot migrate %s due to colocation activity (last was %s)", rsc->id, target->id); return FALSE; } } ); slist_iter( other_w, action_wrapper_t, start->actions_before, lpc, other = other_w->action; #if ALLOW_WEAK_MIGRATION if((other_w->type & pe_order_implies_right) == 0) { crm_debug_3("%s: depends on %s (optional ordering)", rsc->id, other->uuid); continue; } #endif crm_debug_2("%s: Checking %s ordering", rsc->id, other->uuid); if(other->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 complex_migrate_reload(resource_t *rsc, pe_working_set_t *data_set) { char *key = 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) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->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) && start->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->pseudo || action->optional || action->node == NULL || action->runnable == FALSE) { do_crm_log_unlikely(level, "%s: %s", rsc->id, action->task); return; } action = stop; if(action->pseudo || action->optional || action->node == NULL || 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)) { crm_info("Migrating %s from %s to %s", rsc->id, stop->node->details->uname, start->node->details->uname); crm_free(stop->uuid); crm_free(stop->task); stop->task = crm_strdup(RSC_MIGRATE); stop->uuid = generate_op_key(rsc->id, stop->task, 0); add_hash_param(stop->meta, "migrate_source", stop->node->details->uname); add_hash_param(stop->meta, "migrate_target", start->node->details->uname); /* Create the correct ordering ajustments based on find_clone_activity_on(); */ slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, resource_t *target = constraint->rsc_rh; crm_info("Repairing %s: %s == %s (%d)", constraint->id, rsc->id, target->id, constraint->score); if(constraint->score > 0) { int mode = check_stack_element(rsc, target, "coloc"); action_t *clone_stop = find_first_action(target->actions, NULL, RSC_STOP, NULL); action_t *clone_start = find_first_action(target->actions, NULL, RSC_STARTED, NULL); CRM_ASSERT(clone_stop != NULL); CRM_ASSERT(clone_start != NULL); CRM_ASSERT((mode & stack_middle) == 0); CRM_ASSERT(((mode & stack_stopping) && (mode & stack_starting)) == 0); if(mode & stack_stopping) { 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_debug("Creating %s.start -> %s.stop ordering", rsc->id, target->id); order_actions(start, clone_stop, pe_order_optional); slist_iter( other_w, action_wrapper_t, start->actions_before, lpc2, /* Needed if the clone's started pseudo-action ever gets printed in the graph */ if(other_w->action == clone_start) { crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, start->uuid); other_w->type = pe_order_none; } ); } else if(mode & stack_starting) { crm_debug("Creating %s.started -> %s.stop ordering", target->id, rsc->id); order_actions(clone_start, stop, pe_order_optional); slist_iter( other_w, action_wrapper_t, clone_stop->actions_before, lpc2, /* Needed if the clone's stop pseudo-action ever gets printed in the graph */ if(other_w->action == stop) { crm_debug("Breaking %s -> %s ordering", other_w->action->uuid, clone_stop->uuid); other_w->type = pe_order_none; } ); } } ); crm_free(start->uuid); crm_free(start->task); start->task = crm_strdup(RSC_MIGRATED); start->uuid = generate_op_key(rsc->id, start->task, 0); add_hash_param(start->meta, "migrate_source_uuid", stop->node->details->id); add_hash_param(start->meta, "migrate_source", stop->node->details->uname); add_hash_param(start->meta, "migrate_target", start->node->details->uname); /* Anything that needed stop to complete, now also needs start to have completed */ slist_iter( other_w, action_wrapper_t, stop->actions_after, lpc, other = other_w->action; if(other->optional || other->rsc != NULL) { continue; } crm_debug("Ordering %s before %s (stop)", start->uuid, other_w->action->uuid); order_actions(start, other, other_w->type); ); /* Stop also needs anything that the start needed to have completed too */ slist_iter( other_w, action_wrapper_t, start->actions_before, lpc, other = other_w->action; if(other->rsc == NULL) { /* nothing */ } else if(other->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, stop, other_w->type); ); } else if(start && stop && start->allow_reload_conversion && stop->node->details == start->node->details) { action_t *rewrite = NULL; start->pseudo = TRUE; /* 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 && action->optional == FALSE) { action->pseudo = TRUE; } 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 && action->optional == FALSE) { rewrite = action; stop->pseudo = TRUE; } 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); } } diff --git a/pengine/test10/inc1.dot b/pengine/test10/inc1.dot index f93798de7f..29181c8503 100644 --- a/pengine/test10/inc1.dot +++ b/pengine/test10/inc1.dot @@ -1,66 +1,68 @@ digraph "g" { "child_rsc2:0_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:0_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:0_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_start_0 node2" -> "rsc2_running_0" [ style = bold] +"child_rsc2:0_start_0 node2" -> "rsc3_start_0 node2" [ style = bold] "child_rsc2:0_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_start_0 node1" -> "rsc2_running_0" [ style = bold] "child_rsc2:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:2_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_start_0 node2" -> "rsc2_running_0" [ style = bold] +"child_rsc2:2_start_0 node2" -> "rsc3_start_0 node2" [ style = bold] "child_rsc2:2_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:3_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:3_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_start_0 node1" -> "rsc2_running_0" [ style = bold] "child_rsc2:3_start_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:4_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:4_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "probe_complete node1" -> "probe_complete" [ style = bold] "probe_complete node1" [ style=bold color="green" fontcolor="black" ] "probe_complete node2" -> "probe_complete" [ style = bold] "probe_complete node2" [ style=bold color="green" fontcolor="black" ] "probe_complete" -> "child_rsc2:0_start_0 node2" [ style = bold] "probe_complete" -> "child_rsc2:1_start_0 node1" [ style = bold] "probe_complete" -> "child_rsc2:2_start_0 node2" [ style = bold] "probe_complete" -> "child_rsc2:3_start_0 node1" [ style = bold] "probe_complete" -> "rsc1_start_0 node1" [ style = bold] "probe_complete" -> "rsc2_start_0" [ style = bold] "probe_complete" -> "rsc2_stop_0" [ style = bold] "probe_complete" -> "rsc3_start_0 node2" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange" ] "rsc1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "rsc1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "rsc1_monitor_0 node2" -> "probe_complete node2" [ style = bold] "rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "rsc1_start_0 node1" -> "child_rsc2:1_start_0 node1" [ style = bold] "rsc1_start_0 node1" -> "child_rsc2:3_start_0 node1" [ style = bold] "rsc1_start_0 node1" -> "rsc2_start_0" [ style = bold] "rsc1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "rsc2_running_0" -> "rsc3_start_0 node2" [ style = bold] "rsc2_running_0" [ style=bold color="green" fontcolor="orange" ] "rsc2_start_0" -> "child_rsc2:0_start_0 node2" [ style = bold] "rsc2_start_0" -> "child_rsc2:1_start_0 node1" [ style = bold] "rsc2_start_0" -> "child_rsc2:2_start_0 node2" [ style = bold] "rsc2_start_0" -> "child_rsc2:3_start_0 node1" [ style = bold] "rsc2_start_0" -> "rsc2_running_0" [ style = bold] "rsc2_start_0" [ style=bold color="green" fontcolor="orange" ] "rsc2_stop_0" -> "rsc2_start_0" [ style = bold] "rsc2_stop_0" [ style=bold color="green" fontcolor="orange" ] "rsc3_monitor_0 node1" -> "probe_complete node1" [ style = bold] "rsc3_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "rsc3_monitor_0 node2" -> "probe_complete node2" [ style = bold] "rsc3_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "rsc3_start_0 node2" [ style=bold color="green" fontcolor="black" ] } diff --git a/pengine/test10/inc1.exp b/pengine/test10/inc1.exp index 5bf3b3ed40..daa261eda5 100644 --- a/pengine/test10/inc1.exp +++ b/pengine/test10/inc1.exp @@ -1,357 +1,363 @@ + + + + + + diff --git a/pengine/test10/migrate-start-complex.dot b/pengine/test10/migrate-start-complex.dot index ef9ae662b4..561495818f 100644 --- a/pengine/test10/migrate-start-complex.dot +++ b/pengine/test10/migrate-start-complex.dot @@ -1,53 +1,57 @@ digraph "g" { "all_stopped" [ style=bold color="green" fontcolor="orange" ] "bottom:0_monitor_0 dom0-02" -> "probe_complete dom0-02" [ style = bold] "bottom:0_monitor_0 dom0-02" [ style=bold color="green" fontcolor="black" ] "bottom:0_start_0 dom0-02" -> "clone-bottom_running_0" [ style = bold] "bottom:0_start_0 dom0-02" [ style=bold color="green" fontcolor="black" ] "bottom:1_monitor_0 dom0-01" -> "probe_complete dom0-01" [ style = bold] "bottom:1_monitor_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "bottom:1_start_0 dom0-01" -> "clone-bottom_running_0" [ style = bold] +"bottom:1_start_0 dom0-01" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] +"bottom:1_start_0 dom0-01" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "bottom:1_start_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "clone-bottom_running_0" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] "clone-bottom_running_0" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "clone-bottom_running_0" [ style=bold color="green" fontcolor="orange" ] "clone-bottom_start_0" -> "bottom:0_start_0 dom0-02" [ style = bold] "clone-bottom_start_0" -> "bottom:1_start_0 dom0-01" [ style = bold] "clone-bottom_start_0" -> "clone-bottom_running_0" [ style = bold] "clone-bottom_start_0" [ style=bold color="green" fontcolor="orange" ] "clone-bottom_stop_0" -> "clone-bottom_start_0" [ style = bold] "clone-bottom_stop_0" [ style=bold color="green" fontcolor="orange" ] "clone-dom0-iscsi1_running_0" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] "clone-dom0-iscsi1_running_0" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "clone-dom0-iscsi1_running_0" [ style=bold color="green" fontcolor="orange" ] "clone-dom0-iscsi1_start_0" -> "clone-dom0-iscsi1_running_0" [ style = bold] "clone-dom0-iscsi1_start_0" -> "dom0-iscsi1:1_start_0" [ style = bold] "clone-dom0-iscsi1_start_0" [ style=bold color="green" fontcolor="orange" ] "dom0-iscsi1-cnx1:1_start_0 dom0-01" -> "dom0-iscsi1:1_running_0" [ style = bold] "dom0-iscsi1-cnx1:1_start_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "dom0-iscsi1:1_running_0" -> "clone-dom0-iscsi1_running_0" [ style = bold] "dom0-iscsi1:1_running_0" [ style=bold color="green" fontcolor="orange" ] "dom0-iscsi1:1_start_0" -> "dom0-iscsi1-cnx1:1_start_0 dom0-01" [ style = bold] "dom0-iscsi1:1_start_0" -> "dom0-iscsi1:1_running_0" [ style = bold] +"dom0-iscsi1:1_start_0" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] +"dom0-iscsi1:1_start_0" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "dom0-iscsi1:1_start_0" [ style=bold color="green" fontcolor="orange" ] "domU-test01_migrate_from_0 dom0-01" -> "all_stopped" [ style = bold] "domU-test01_migrate_from_0 dom0-01" -> "top_start_0 dom0-01" [ style = bold] "domU-test01_migrate_from_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "domU-test01_migrate_to_0 dom0-02" -> "all_stopped" [ style = bold] "domU-test01_migrate_to_0 dom0-02" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] "domU-test01_migrate_to_0 dom0-02" [ style=bold color="green" fontcolor="black" ] "probe_complete dom0-01" -> "probe_complete" [ style = bold] "probe_complete dom0-01" [ style=bold color="green" fontcolor="black" ] "probe_complete dom0-02" -> "probe_complete" [ style = bold] "probe_complete dom0-02" [ style=bold color="green" fontcolor="black" ] "probe_complete" -> "bottom:0_start_0 dom0-02" [ style = bold] "probe_complete" -> "bottom:1_start_0 dom0-01" [ style = bold] "probe_complete" -> "clone-bottom_start_0" [ style = bold] "probe_complete" -> "clone-bottom_stop_0" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange" ] "top_start_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "top_stop_0 dom0-02" -> "all_stopped" [ style = bold] "top_stop_0 dom0-02" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "top_stop_0 dom0-02" -> "top_start_0 dom0-01" [ style = bold] "top_stop_0 dom0-02" [ style=bold color="green" fontcolor="black" ] } diff --git a/pengine/test10/migrate-start-complex.exp b/pengine/test10/migrate-start-complex.exp index 4eb9d7448d..593a821ca2 100644 --- a/pengine/test10/migrate-start-complex.exp +++ b/pengine/test10/migrate-start-complex.exp @@ -1,281 +1,293 @@ + + + + + + + + + + + + diff --git a/pengine/test10/migrate-start.dot b/pengine/test10/migrate-start.dot index 6bc6d1dfab..a164ff795b 100644 --- a/pengine/test10/migrate-start.dot +++ b/pengine/test10/migrate-start.dot @@ -1,21 +1,23 @@ digraph "g" { "all_stopped" [ style=bold color="green" fontcolor="orange" ] "clone-dom0-iscsi1_running_0" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] "clone-dom0-iscsi1_running_0" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "clone-dom0-iscsi1_running_0" [ style=bold color="green" fontcolor="orange" ] "clone-dom0-iscsi1_start_0" -> "clone-dom0-iscsi1_running_0" [ style = bold] "clone-dom0-iscsi1_start_0" -> "dom0-iscsi1:1_start_0" [ style = bold] "clone-dom0-iscsi1_start_0" [ style=bold color="green" fontcolor="orange" ] "dom0-iscsi1-cnx1:1_start_0 dom0-01" -> "dom0-iscsi1:1_running_0" [ style = bold] "dom0-iscsi1-cnx1:1_start_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "dom0-iscsi1:1_running_0" -> "clone-dom0-iscsi1_running_0" [ style = bold] "dom0-iscsi1:1_running_0" [ style=bold color="green" fontcolor="orange" ] "dom0-iscsi1:1_start_0" -> "dom0-iscsi1-cnx1:1_start_0 dom0-01" [ style = bold] "dom0-iscsi1:1_start_0" -> "dom0-iscsi1:1_running_0" [ style = bold] +"dom0-iscsi1:1_start_0" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] +"dom0-iscsi1:1_start_0" -> "domU-test01_migrate_to_0 dom0-02" [ style = bold] "dom0-iscsi1:1_start_0" [ style=bold color="green" fontcolor="orange" ] "domU-test01_migrate_from_0 dom0-01" -> "all_stopped" [ style = bold] "domU-test01_migrate_from_0 dom0-01" [ style=bold color="green" fontcolor="black" ] "domU-test01_migrate_to_0 dom0-02" -> "all_stopped" [ style = bold] "domU-test01_migrate_to_0 dom0-02" -> "domU-test01_migrate_from_0 dom0-01" [ style = bold] "domU-test01_migrate_to_0 dom0-02" [ style=bold color="green" fontcolor="black" ] } diff --git a/pengine/test10/migrate-start.exp b/pengine/test10/migrate-start.exp index 461bd9cd69..4a64c89f22 100644 --- a/pengine/test10/migrate-start.exp +++ b/pengine/test10/migrate-start.exp @@ -1,110 +1,116 @@ + + + + + + diff --git a/pengine/test10/novell-252693-2.dot b/pengine/test10/novell-252693-2.dot index 88f7430d76..9885be26d9 100644 --- a/pengine/test10/novell-252693-2.dot +++ b/pengine/test10/novell-252693-2.dot @@ -1,144 +1,148 @@ digraph "g" { "all_stopped" [ style=bold color="green" fontcolor="orange" ] "configstoreclone:0_post_notify_start_0 node2" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstoreclone:0_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "configstoreclone:0_pre_notify_start_0 node2" -> "configstorecloneset_confirmed-pre_notify_start_0" [ style = bold] "configstoreclone:0_pre_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "configstoreclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_monitor_20000 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_post_notify_start_0 node1" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstoreclone:1_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_start_0 node1" -> "configstoreclone:1_monitor_20000 node1" [ style = bold] "configstoreclone:1_start_0 node1" -> "configstorecloneset_running_0" [ style = bold] +"configstoreclone:1_start_0 node1" -> "sles10_migrate_from_0 node1" [ style = bold] +"configstoreclone:1_start_0 node1" -> "sles10_migrate_to_0 node2" [ style = bold] "configstoreclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "configstorecloneset_confirmed-post_notify_running_0" -> "configstoreclone:1_monitor_20000 node1" [ style = bold] "configstorecloneset_confirmed-post_notify_running_0" -> "sles10_migrate_from_0 node1" [ style = bold] "configstorecloneset_confirmed-post_notify_running_0" -> "sles10_migrate_to_0 node2" [ style = bold] "configstorecloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_confirmed-pre_notify_start_0" -> "configstorecloneset_post_notify_running_0" [ style = bold] "configstorecloneset_confirmed-pre_notify_start_0" -> "configstorecloneset_start_0" [ style = bold] "configstorecloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_post_notify_running_0" -> "configstoreclone:0_post_notify_start_0 node2" [ style = bold] "configstorecloneset_post_notify_running_0" -> "configstoreclone:1_post_notify_start_0 node1" [ style = bold] "configstorecloneset_post_notify_running_0" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstorecloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_pre_notify_start_0" -> "configstoreclone:0_pre_notify_start_0 node2" [ style = bold] "configstorecloneset_pre_notify_start_0" -> "configstorecloneset_confirmed-pre_notify_start_0" [ style = bold] "configstorecloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_running_0" -> "configstorecloneset_post_notify_running_0" [ style = bold] "configstorecloneset_running_0" -> "sles10_migrate_from_0 node1" [ style = bold] "configstorecloneset_running_0" -> "sles10_migrate_to_0 node2" [ style = bold] "configstorecloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_start_0" -> "configstoreclone:1_start_0 node1" [ style = bold] "configstorecloneset_start_0" -> "configstorecloneset_running_0" [ style = bold] "configstorecloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "evmsclone:0_post_notify_start_0 node2" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmsclone:0_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "evmsclone:0_pre_notify_start_0 node2" -> "evmscloneset_confirmed-pre_notify_start_0" [ style = bold] "evmsclone:0_pre_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "evmsclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_post_notify_start_0 node1" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmsclone:1_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_start_0 node1" -> "evmscloneset_running_0" [ style = bold] "evmsclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmscloneset_confirmed-post_notify_running_0" -> "configstorecloneset_start_0" [ style = bold] "evmscloneset_confirmed-post_notify_running_0" -> "imagestorecloneset_start_0" [ style = bold] "evmscloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_confirmed-pre_notify_start_0" -> "evmscloneset_post_notify_running_0" [ style = bold] "evmscloneset_confirmed-pre_notify_start_0" -> "evmscloneset_start_0" [ style = bold] "evmscloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_post_notify_running_0" -> "evmsclone:0_post_notify_start_0 node2" [ style = bold] "evmscloneset_post_notify_running_0" -> "evmsclone:1_post_notify_start_0 node1" [ style = bold] "evmscloneset_post_notify_running_0" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmscloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_pre_notify_start_0" -> "evmsclone:0_pre_notify_start_0 node2" [ style = bold] "evmscloneset_pre_notify_start_0" -> "evmscloneset_confirmed-pre_notify_start_0" [ style = bold] "evmscloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_running_0" -> "configstorecloneset_start_0" [ style = bold] "evmscloneset_running_0" -> "evmscloneset_post_notify_running_0" [ style = bold] "evmscloneset_running_0" -> "imagestorecloneset_start_0" [ style = bold] "evmscloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_start_0" -> "evmsclone:1_start_0 node1" [ style = bold] "evmscloneset_start_0" -> "evmscloneset_running_0" [ style = bold] "evmscloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "evmsdclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "evmsdclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsdclone:1_monitor_5000 node1" [ style=bold color="green" fontcolor="black" ] "evmsdclone:1_start_0 node1" -> "evmsdclone:1_monitor_5000 node1" [ style = bold] "evmsdclone:1_start_0 node1" -> "evmsdcloneset_running_0" [ style = bold] "evmsdclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsdcloneset_running_0" -> "evmscloneset_start_0" [ style = bold] "evmsdcloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "evmsdcloneset_start_0" -> "evmsdclone:1_start_0 node1" [ style = bold] "evmsdcloneset_start_0" -> "evmsdcloneset_running_0" [ style = bold] "evmsdcloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestoreclone:0_post_notify_start_0 node2" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestoreclone:0_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_pre_notify_start_0 node2" -> "imagestorecloneset_confirmed-pre_notify_start_0" [ style = bold] "imagestoreclone:0_pre_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "imagestoreclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_monitor_20000 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_post_notify_start_0 node1" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestoreclone:1_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_start_0 node1" -> "imagestoreclone:1_monitor_20000 node1" [ style = bold] "imagestoreclone:1_start_0 node1" -> "imagestorecloneset_running_0" [ style = bold] +"imagestoreclone:1_start_0 node1" -> "sles10_migrate_from_0 node1" [ style = bold] +"imagestoreclone:1_start_0 node1" -> "sles10_migrate_to_0 node2" [ style = bold] "imagestoreclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestorecloneset_confirmed-post_notify_running_0" -> "imagestoreclone:1_monitor_20000 node1" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" -> "sles10_migrate_from_0 node1" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" -> "sles10_migrate_to_0 node2" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_confirmed-pre_notify_start_0" -> "imagestorecloneset_post_notify_running_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_start_0" -> "imagestorecloneset_start_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_post_notify_running_0" -> "imagestoreclone:0_post_notify_start_0 node2" [ style = bold] "imagestorecloneset_post_notify_running_0" -> "imagestoreclone:1_post_notify_start_0 node1" [ style = bold] "imagestorecloneset_post_notify_running_0" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestorecloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_pre_notify_start_0" -> "imagestoreclone:0_pre_notify_start_0 node2" [ style = bold] "imagestorecloneset_pre_notify_start_0" -> "imagestorecloneset_confirmed-pre_notify_start_0" [ style = bold] "imagestorecloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_running_0" -> "imagestorecloneset_post_notify_running_0" [ style = bold] "imagestorecloneset_running_0" -> "sles10_migrate_from_0 node1" [ style = bold] "imagestorecloneset_running_0" -> "sles10_migrate_to_0 node2" [ style = bold] "imagestorecloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_start_0" -> "imagestoreclone:1_start_0 node1" [ style = bold] "imagestorecloneset_start_0" -> "imagestorecloneset_running_0" [ style = bold] "imagestorecloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "probe_complete node1" -> "probe_complete" [ style = bold] "probe_complete node1" [ style=bold color="green" fontcolor="black" ] "probe_complete" -> "configstoreclone:1_start_0 node1" [ style = bold] "probe_complete" -> "configstorecloneset_start_0" [ style = bold] "probe_complete" -> "evmsclone:1_start_0 node1" [ style = bold] "probe_complete" -> "evmscloneset_start_0" [ style = bold] "probe_complete" -> "evmsdclone:1_start_0 node1" [ style = bold] "probe_complete" -> "evmsdcloneset_start_0" [ style = bold] "probe_complete" -> "imagestoreclone:1_start_0 node1" [ style = bold] "probe_complete" -> "imagestorecloneset_start_0" [ style = bold] "probe_complete" -> "sles10_migrate_from_0 node1" [ style = bold] "probe_complete" -> "sles10_migrate_to_0 node2" [ style = bold] "probe_complete" -> "stonithclone:1_start_0 node1" [ style = bold] "probe_complete" -> "stonithcloneset_start_0" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange" ] "sles10_migrate_from_0 node1" -> "all_stopped" [ style = bold] "sles10_migrate_from_0 node1" -> "sles10_monitor_10000 node1" [ style = bold] "sles10_migrate_from_0 node1" [ style=bold color="green" fontcolor="black" ] "sles10_migrate_to_0 node2" -> "all_stopped" [ style = bold] "sles10_migrate_to_0 node2" -> "sles10_migrate_from_0 node1" [ style = bold] "sles10_migrate_to_0 node2" [ style=bold color="green" fontcolor="black" ] "sles10_monitor_0 node1" -> "probe_complete node1" [ style = bold] "sles10_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "sles10_monitor_10000 node1" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "stonithclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_monitor_5000 node1" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_start_0 node1" -> "stonithclone:1_monitor_5000 node1" [ style = bold] "stonithclone:1_start_0 node1" -> "stonithcloneset_running_0" [ style = bold] "stonithclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "stonithcloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "stonithcloneset_start_0" -> "stonithclone:1_start_0 node1" [ style = bold] "stonithcloneset_start_0" -> "stonithcloneset_running_0" [ style = bold] "stonithcloneset_start_0" [ style=bold color="green" fontcolor="orange" ] } diff --git a/pengine/test10/novell-252693-2.exp b/pengine/test10/novell-252693-2.exp index 18e19e3059..203f066bf3 100644 --- a/pengine/test10/novell-252693-2.exp +++ b/pengine/test10/novell-252693-2.exp @@ -1,759 +1,771 @@ + + + + + + + + + + + + diff --git a/pengine/test10/novell-252693-3.dot b/pengine/test10/novell-252693-3.dot index c4ec399c94..07cd03d999 100644 --- a/pengine/test10/novell-252693-3.dot +++ b/pengine/test10/novell-252693-3.dot @@ -1,171 +1,172 @@ digraph "g" { "all_stopped" [ style=bold color="green" fontcolor="orange" ] "configstoreclone:0_post_notify_start_0 node2" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstoreclone:0_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "configstoreclone:0_pre_notify_start_0 node2" -> "configstorecloneset_confirmed-pre_notify_start_0" [ style = bold] "configstoreclone:0_pre_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "configstoreclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_monitor_20000 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_post_notify_start_0 node1" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstoreclone:1_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "configstoreclone:1_start_0 node1" -> "configstoreclone:1_monitor_20000 node1" [ style = bold] "configstoreclone:1_start_0 node1" -> "configstorecloneset_running_0" [ style = bold] +"configstoreclone:1_start_0 node1" -> "sles10_start_0 node1" [ style = bold] "configstoreclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "configstorecloneset_confirmed-post_notify_running_0" -> "configstoreclone:1_monitor_20000 node1" [ style = bold] "configstorecloneset_confirmed-post_notify_running_0" -> "sles10_start_0 node1" [ style = bold] "configstorecloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_confirmed-pre_notify_start_0" -> "configstorecloneset_post_notify_running_0" [ style = bold] "configstorecloneset_confirmed-pre_notify_start_0" -> "configstorecloneset_start_0" [ style = bold] "configstorecloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_post_notify_running_0" -> "configstoreclone:0_post_notify_start_0 node2" [ style = bold] "configstorecloneset_post_notify_running_0" -> "configstoreclone:1_post_notify_start_0 node1" [ style = bold] "configstorecloneset_post_notify_running_0" -> "configstorecloneset_confirmed-post_notify_running_0" [ style = bold] "configstorecloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_pre_notify_start_0" -> "configstoreclone:0_pre_notify_start_0 node2" [ style = bold] "configstorecloneset_pre_notify_start_0" -> "configstorecloneset_confirmed-pre_notify_start_0" [ style = bold] "configstorecloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_running_0" -> "configstorecloneset_post_notify_running_0" [ style = bold] "configstorecloneset_running_0" -> "sles10_start_0 node1" [ style = bold] "configstorecloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "configstorecloneset_start_0" -> "configstoreclone:1_start_0 node1" [ style = bold] "configstorecloneset_start_0" -> "configstorecloneset_running_0" [ style = bold] "configstorecloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "evmsclone:0_post_notify_start_0 node2" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmsclone:0_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "evmsclone:0_pre_notify_start_0 node2" -> "evmscloneset_confirmed-pre_notify_start_0" [ style = bold] "evmsclone:0_pre_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "evmsclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_post_notify_start_0 node1" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmsclone:1_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsclone:1_start_0 node1" -> "evmscloneset_running_0" [ style = bold] "evmsclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmscloneset_confirmed-post_notify_running_0" -> "configstorecloneset_start_0" [ style = bold] "evmscloneset_confirmed-post_notify_running_0" -> "imagestorecloneset_start_0" [ style = bold] "evmscloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_confirmed-pre_notify_start_0" -> "evmscloneset_post_notify_running_0" [ style = bold] "evmscloneset_confirmed-pre_notify_start_0" -> "evmscloneset_start_0" [ style = bold] "evmscloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_post_notify_running_0" -> "evmsclone:0_post_notify_start_0 node2" [ style = bold] "evmscloneset_post_notify_running_0" -> "evmsclone:1_post_notify_start_0 node1" [ style = bold] "evmscloneset_post_notify_running_0" -> "evmscloneset_confirmed-post_notify_running_0" [ style = bold] "evmscloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_pre_notify_start_0" -> "evmsclone:0_pre_notify_start_0 node2" [ style = bold] "evmscloneset_pre_notify_start_0" -> "evmscloneset_confirmed-pre_notify_start_0" [ style = bold] "evmscloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_running_0" -> "configstorecloneset_start_0" [ style = bold] "evmscloneset_running_0" -> "evmscloneset_post_notify_running_0" [ style = bold] "evmscloneset_running_0" -> "imagestorecloneset_start_0" [ style = bold] "evmscloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "evmscloneset_start_0" -> "evmsclone:1_start_0 node1" [ style = bold] "evmscloneset_start_0" -> "evmscloneset_running_0" [ style = bold] "evmscloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "evmsdclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "evmsdclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsdclone:1_monitor_5000 node1" [ style=bold color="green" fontcolor="black" ] "evmsdclone:1_start_0 node1" -> "evmsdclone:1_monitor_5000 node1" [ style = bold] "evmsdclone:1_start_0 node1" -> "evmsdcloneset_running_0" [ style = bold] "evmsdclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "evmsdcloneset_running_0" -> "evmscloneset_start_0" [ style = bold] "evmsdcloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "evmsdcloneset_start_0" -> "evmsdclone:1_start_0 node1" [ style = bold] "evmsdcloneset_start_0" -> "evmsdcloneset_running_0" [ style = bold] "evmsdcloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestoreclone:0_monitor_0 node1" -> "probe_complete node1" [ style = bold] "imagestoreclone:0_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_monitor_20000 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_post_notify_start_0 node1" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestoreclone:0_post_notify_start_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_pre_notify_stop_0 node2" -> "imagestorecloneset_confirmed-pre_notify_stop_0" [ style = bold] "imagestoreclone:0_pre_notify_stop_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_start_0 node1" -> "imagestoreclone:0_monitor_20000 node1" [ style = bold] "imagestoreclone:0_start_0 node1" -> "imagestorecloneset_running_0" [ style = bold] "imagestoreclone:0_start_0 node1" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:0_stop_0 node2" -> "all_stopped" [ style = bold] "imagestoreclone:0_stop_0 node2" -> "imagestoreclone:0_start_0 node1" [ style = bold] "imagestoreclone:0_stop_0 node2" -> "imagestorecloneset_stopped_0" [ style = bold] "imagestoreclone:0_stop_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_monitor_20000 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_post_notify_start_0 node2" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestoreclone:1_post_notify_start_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestoreclone:1_start_0 node2" -> "imagestoreclone:1_monitor_20000 node2" [ style = bold] "imagestoreclone:1_start_0 node2" -> "imagestorecloneset_running_0" [ style = bold] "imagestoreclone:1_start_0 node2" [ style=bold color="green" fontcolor="black" ] "imagestorecloneset_confirmed-post_notify_running_0" -> "imagestoreclone:0_monitor_20000 node1" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" -> "imagestoreclone:1_monitor_20000 node2" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" -> "sles10_start_0 node1" [ style = bold] "imagestorecloneset_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_confirmed-post_notify_stopped_0" -> "all_stopped" [ style = bold] "imagestorecloneset_confirmed-post_notify_stopped_0" -> "imagestorecloneset_pre_notify_start_0" [ style = bold] "imagestorecloneset_confirmed-post_notify_stopped_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_confirmed-pre_notify_start_0" -> "imagestorecloneset_post_notify_running_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_start_0" -> "imagestorecloneset_start_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_confirmed-pre_notify_stop_0" -> "imagestorecloneset_post_notify_stopped_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_stop_0" -> "imagestorecloneset_stop_0" [ style = bold] "imagestorecloneset_confirmed-pre_notify_stop_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_post_notify_running_0" -> "imagestoreclone:0_post_notify_start_0 node1" [ style = bold] "imagestorecloneset_post_notify_running_0" -> "imagestoreclone:1_post_notify_start_0 node2" [ style = bold] "imagestorecloneset_post_notify_running_0" -> "imagestorecloneset_confirmed-post_notify_running_0" [ style = bold] "imagestorecloneset_post_notify_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_post_notify_stopped_0" -> "imagestorecloneset_confirmed-post_notify_stopped_0" [ style = bold] "imagestorecloneset_post_notify_stopped_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_pre_notify_start_0" -> "imagestorecloneset_confirmed-pre_notify_start_0" [ style = bold] "imagestorecloneset_pre_notify_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_pre_notify_stop_0" -> "imagestoreclone:0_pre_notify_stop_0 node2" [ style = bold] "imagestorecloneset_pre_notify_stop_0" -> "imagestorecloneset_confirmed-pre_notify_stop_0" [ style = bold] "imagestorecloneset_pre_notify_stop_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_running_0" -> "imagestorecloneset_post_notify_running_0" [ style = bold] "imagestorecloneset_running_0" -> "sles10_start_0 node1" [ style = bold] "imagestorecloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_start_0" -> "imagestoreclone:0_start_0 node1" [ style = bold] "imagestorecloneset_start_0" -> "imagestoreclone:1_start_0 node2" [ style = bold] "imagestorecloneset_start_0" -> "imagestorecloneset_running_0" [ style = bold] "imagestorecloneset_start_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_stop_0" -> "imagestoreclone:0_stop_0 node2" [ style = bold] "imagestorecloneset_stop_0" -> "imagestorecloneset_start_0" [ style = bold] "imagestorecloneset_stop_0" -> "imagestorecloneset_stopped_0" [ style = bold] "imagestorecloneset_stop_0" [ style=bold color="green" fontcolor="orange" ] "imagestorecloneset_stopped_0" -> "imagestorecloneset_post_notify_stopped_0" [ style = bold] "imagestorecloneset_stopped_0" -> "imagestorecloneset_start_0" [ style = bold] "imagestorecloneset_stopped_0" [ style=bold color="green" fontcolor="orange" ] "probe_complete node1" -> "probe_complete" [ style = bold] "probe_complete node1" [ style=bold color="green" fontcolor="black" ] "probe_complete" -> "configstoreclone:1_start_0 node1" [ style = bold] "probe_complete" -> "configstorecloneset_start_0" [ style = bold] "probe_complete" -> "evmsclone:1_start_0 node1" [ style = bold] "probe_complete" -> "evmscloneset_start_0" [ style = bold] "probe_complete" -> "evmsdclone:1_start_0 node1" [ style = bold] "probe_complete" -> "evmsdcloneset_start_0" [ style = bold] "probe_complete" -> "imagestoreclone:0_start_0 node1" [ style = bold] "probe_complete" -> "imagestoreclone:0_stop_0 node2" [ style = bold] "probe_complete" -> "imagestoreclone:1_start_0 node2" [ style = bold] "probe_complete" -> "imagestorecloneset_start_0" [ style = bold] "probe_complete" -> "imagestorecloneset_stop_0" [ style = bold] "probe_complete" -> "sles10_start_0 node1" [ style = bold] "probe_complete" -> "sles10_stop_0 node2" [ style = bold] "probe_complete" -> "stonithclone:1_start_0 node1" [ style = bold] "probe_complete" -> "stonithcloneset_start_0" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange" ] "sles10_monitor_0 node1" -> "probe_complete node1" [ style = bold] "sles10_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "sles10_monitor_10000 node1" [ style=bold color="green" fontcolor="black" ] "sles10_start_0 node1" -> "sles10_monitor_10000 node1" [ style = bold] "sles10_start_0 node1" [ style=bold color="green" fontcolor="black" ] "sles10_stop_0 node2" -> "all_stopped" [ style = bold] "sles10_stop_0 node2" -> "imagestoreclone:0_stop_0 node2" [ style = bold] "sles10_stop_0 node2" -> "imagestorecloneset_stop_0" [ style = bold] "sles10_stop_0 node2" -> "sles10_start_0 node1" [ style = bold] "sles10_stop_0 node2" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "stonithclone:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_monitor_5000 node1" [ style=bold color="green" fontcolor="black" ] "stonithclone:1_start_0 node1" -> "stonithclone:1_monitor_5000 node1" [ style = bold] "stonithclone:1_start_0 node1" -> "stonithcloneset_running_0" [ style = bold] "stonithclone:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] "stonithcloneset_running_0" [ style=bold color="green" fontcolor="orange" ] "stonithcloneset_start_0" -> "stonithclone:1_start_0 node1" [ style = bold] "stonithcloneset_start_0" -> "stonithcloneset_running_0" [ style = bold] "stonithcloneset_start_0" [ style=bold color="green" fontcolor="orange" ] } diff --git a/pengine/test10/novell-252693-3.exp b/pengine/test10/novell-252693-3.exp index 58ef3c103b..4afa58135d 100644 --- a/pengine/test10/novell-252693-3.exp +++ b/pengine/test10/novell-252693-3.exp @@ -1,897 +1,900 @@ + + +