diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c index b783cb56c1..7b6513bcc0 100644 --- a/crm/pengine/graph.c +++ b/crm/pengine/graph.c @@ -1,611 +1,594 @@ -/* $Id: graph.c,v 1.95 2006/05/30 09:24:03 andrew Exp $ */ +/* $Id: graph.c,v 1.96 2006/06/07 07:34:38 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include gboolean update_action(action_t *action); gboolean update_action_states(GListPtr actions) { crm_debug_2("Updating %d actions", g_list_length(actions)); slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } #define UPDATE_THEM 1 gboolean update_action(action_t *action) { enum action_tasks task = no_action; crm_debug_3("Processing action %s: %s", action->uuid, action->optional?"optional":"required"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, crm_debug_3("\tChecking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->type == pe_ordering_restart && action->rsc->role > RSC_ROLE_STOPPED) { crm_debug_3("Upgrading %s constraint to %s", ordering_type2text(other->type), ordering_type2text(pe_ordering_manditory)); other->type = pe_ordering_manditory; } if(other->type != pe_ordering_manditory) { crm_debug_3("\t Ignoring: %s", ordering_type2text(other->type)); continue; } else if(action->optional || other->action->optional == FALSE){ crm_debug_3("\t Ignoring: %s/%s", other->action->optional?"-":"they are not optional", action->optional?"we are optional":"-"); continue; } else if(safe_str_eq(other->action->task, CRMD_ACTION_START)) { const char *interval = g_hash_table_lookup( action->meta, XML_LRM_ATTR_INTERVAL); int interval_i = 0; if(interval != NULL) { interval_i = crm_parse_int(interval, NULL); if(interval_i > 0) { crm_debug_3("Ignoring: start + recurring"); continue; } } } other->action->optional = FALSE; crm_debug_2("* Marking action %s mandatory because of %s", other->action->uuid, action->uuid); update_action(other->action); ); slist_iter( other, action_wrapper_t, action->actions_after, lpc, if(action->pseudo == FALSE && action->runnable == FALSE) { if(other->action->runnable == FALSE) { crm_debug_2("Action %s already un-runnable", other->action->uuid); } else if(action->optional == FALSE) { other->action->runnable = FALSE; crm_debug_2("Marking action %s un-runnable" " because of %s", other->action->uuid, action->uuid); update_action(other->action); } } crm_debug_3("\t(Recover) Checking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->action->rsc == NULL) { continue; } else if(other->type == pe_ordering_recover) { if(other->action->rsc->restart_type != pe_restart_restart) { crm_debug_3("\t Ignoring: restart type %d", other->action->rsc->restart_type); continue; } } else if(other->type == pe_ordering_restart) { } else if(other->type == pe_ordering_postnotify) { CRM_CHECK(action->rsc == other->action->rsc, continue); } else { crm_debug_3("\t Ignoring: ordering %s", ordering_type2text(other->type)); continue; } if(other->action->optional == FALSE || action->optional) { crm_debug_3("\t Ignoring: %s/%s", action->optional?"we are optional":"-", other->action->optional?"-":"they are not optional"); continue; } task = text2task(action->task); switch(task) { case stop_rsc: case stopped_rsc: crm_debug_3("\t Ignoring: action %s", action->uuid); break; case start_rsc: case started_rsc: crm_debug_2("* (Recover) Marking action %s" " mandatory because of %s", other->action->uuid, action->uuid); other->action->optional = FALSE; update_action(other->action); break; default: crm_debug_3("\t Ignoring: action %s", action->uuid); break; } ); return FALSE; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { /* add the stop to the before lists so it counts as a pre-req * for the shutdown */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { continue; } custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, pe_ordering_manditory, data_set); ); return TRUE; } gboolean -stonith_constraints(node_t *node, - action_t *stonith_op, action_t *shutdown_op, - pe_working_set_t *data_set) +stonith_constraints( + node_t *node, action_t *stonith_op, pe_working_set_t *data_set) { + char *key = NULL; GListPtr action_list = NULL; - - if(shutdown_op != NULL && stonith_op != NULL) { - /* stop everything we can via shutdown_constraints() and then - * shoot the node... the shutdown has been superceeded - */ - shutdown_op->pseudo = TRUE; - shutdown_op->runnable = TRUE; - - /* shutdown before stonith */ - /* Give any resources a chance to shutdown normally */ - crm_debug_4("Adding shutdown (%d) as an input to stonith (%d)", - shutdown_op->id, stonith_op->id); - - custom_action_order( - NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, - NULL, crm_strdup(CRM_OP_FENCE), stonith_op, - pe_ordering_manditory, data_set); - - } + CRM_CHECK(stonith_op != NULL, return FALSE); + /* * Make sure the stonith OP occurs before we start any shared resources */ if(stonith_op != NULL) { slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->fns->stonith_ordering(rsc, stonith_op, data_set); ); } /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { crm_debug_2("Skipping fencing constraints for unmanaged resource: %s", rsc->id); + continue; - } else if(stonith_op != NULL) { - char *key = stop_key(rsc); - action_list = find_actions(rsc->actions, key, node); - crm_free(key); - - slist_iter( - action, action_t, action_list, lpc2, - if(node->details->online == FALSE - || rsc->failed) { - resource_t *parent = NULL; - crm_info("Stop of failed resource %s is" - " implict after %s is fenced", - rsc->id, node->details->uname); - /* the stop would never complete and is - * now implied by the stonith operation - */ - action->pseudo = TRUE; - action->runnable = TRUE; - if(action->optional) { - /* does this case ever happen? */ - custom_action_order( - NULL, crm_strdup(CRM_OP_FENCE),stonith_op, - rsc, start_key(rsc), NULL, - pe_ordering_manditory, data_set); - } else { - custom_action_order( - NULL, crm_strdup(CRM_OP_FENCE),stonith_op, - rsc, NULL, action, - pe_ordering_manditory, data_set); - } - - /* find the top-most resource */ - parent = rsc->parent; - while(parent != NULL && parent->parent != NULL) { - parent = parent->parent; - } - - if(parent) { - crm_info("Re-creating actions for %s", - parent->id); - parent->fns->create_actions( - parent, data_set); - } - - } else { - crm_info("Moving healthy resource %s" - " off %s before fencing", - rsc->id, node->details->uname); - - /* stop healthy resources before the - * stonith op - */ + } + + key = stop_key(rsc); + action_list = find_actions(rsc->actions, key, node); + crm_free(key); + + slist_iter( + action, action_t, action_list, lpc2, + if(node->details->online == FALSE || rsc->failed) { + resource_t *parent = NULL; + crm_info("Stop of failed resource %s is" + " implict after %s is fenced", + rsc->id, node->details->uname); + /* the stop would never complete and is + * now implied by the stonith operation + */ + action->pseudo = TRUE; + action->runnable = TRUE; + if(action->optional) { + /* does this case ever happen? */ + custom_action_order( + NULL, crm_strdup(CRM_OP_FENCE),stonith_op, + rsc, start_key(rsc), NULL, + pe_ordering_manditory, data_set); + } else { custom_action_order( - rsc, stop_key(rsc), NULL, - NULL,crm_strdup(CRM_OP_FENCE),stonith_op, + NULL, crm_strdup(CRM_OP_FENCE),stonith_op, + rsc, NULL, action, pe_ordering_manditory, data_set); } - ); - + + /* find the top-most resource */ + parent = rsc->parent; + while(parent != NULL && parent->parent != NULL) { + parent = parent->parent; + } + + if(parent) { + crm_info("Re-creating actions for %s", + parent->id); + parent->fns->create_actions( + parent, data_set); + } + + } else { + 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_ordering_manditory, data_set); + } + ); + key = demote_key(rsc); action_list = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, action_list, lpc2, if(node->details->online == FALSE || rsc->failed) { crm_info("Demote of failed resource %s is" " implict after %s is fenced", rsc->id, node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, demote_key(rsc), NULL, pe_ordering_manditory, data_set); } ); /* crm_debug_4("Adding stonith (%d) as an input to stop", */ /* stonith_op->id); */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_block) { */ /* /\* depend on the stop action which will fail *\/ */ /* pe_err("SHARED RESOURCE %s WILL REMAIN BLOCKED" */ /* " ON NODE %s UNTIL %s", */ /* rsc->id, node->details->uname, */ /* data_set->stonith_enabled?"QUORUM RETURNS":"CLEANED UP MANUALLY"); */ /* continue; */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_ignore) { */ /* /\* nothing to do here *\/ */ /* pe_err("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); */ /* continue; */ - } ); return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } crm_data_t * action2xml(action_t *action, gboolean as_input) { gboolean needs_node_info = TRUE; crm_data_t * action_xml = NULL; crm_data_t * args_xml = NULL; char *action_id_s = NULL; if(action == NULL) { return NULL; } crm_debug_4("Dumping action %d as XML", action->id); if(safe_str_eq(action->task, CRM_OP_FENCE)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* needs_node_info = FALSE; */ } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* } else if(safe_str_eq(action->task, CRMD_ACTION_PROBED)) { */ /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */ } else if(action->pseudo) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); needs_node_info = FALSE; } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } action_id_s = crm_itoa(action->id); crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); crm_free(action_id_s); crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); if(needs_node_info && action->node != NULL) { crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname); crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id); } if(action->failure_is_fatal == FALSE) { add_hash_param(action->meta, XML_ATTR_TE_ALLOWFAIL, XML_BOOLEAN_TRUE); } if(as_input) { return action_xml; } if(action->notify_keys != NULL) { g_hash_table_foreach( action->notify_keys, dup_attr, action->meta); } if(action->rsc != NULL && action->pseudo == FALSE) { int lpc = 0; crm_data_t *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); const char *attr_list[] = { XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER, XML_ATTR_TYPE }; crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id); crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->long_name); for(lpc = 0; lpc < DIMOF(attr_list); lpc++) { crm_xml_add(rsc_xml, attr_list[lpc], g_hash_table_lookup(action->rsc->meta, attr_list[lpc])); } } args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); g_hash_table_foreach(action->extra, hash2field, args_xml); if(action->rsc != NULL) { g_hash_table_foreach(action->rsc->parameters, hash2field, args_xml); } g_hash_table_foreach(action->meta, hash2metafield, args_xml); if(action->rsc != NULL) { int lpc = 0; const char *key = NULL; const char *value = NULL; const char *meta_list[] = { XML_RSC_ATTR_UNIQUE, XML_RSC_ATTR_INCARNATION, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, }; for(lpc = 0; lpc < DIMOF(meta_list); lpc++) { key = meta_list[lpc]; value = g_hash_table_lookup(action->rsc->meta, key); if(value != NULL) { char *crm_name = crm_concat(CRM_META, key, '_'); crm_xml_add(args_xml, crm_name, value); crm_free(crm_name); } } } crm_log_xml_debug_4(action_xml, "dumped action"); return action_xml; } static gboolean should_dump_action(action_t *action) { const char * interval = NULL; CRM_CHECK(action != NULL, return FALSE); interval = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); if(action->optional) { crm_debug_5("action %d was optional", action->id); return FALSE; } else if(action->pseudo == FALSE && action->runnable == FALSE) { crm_debug_5("action %d was not runnable", action->id); return FALSE; } else if(action->dumped) { crm_debug_5("action %d was already dumped", action->id); return FALSE; } else if(action->rsc != NULL && action->rsc->is_managed == FALSE) { /* make sure probes go through */ if(safe_str_neq(action->task, CRMD_ACTION_STATUS)) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } if(interval != NULL && safe_str_neq(interval, "0")) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } } if(action->pseudo || safe_str_eq(action->task, CRM_OP_FENCE) || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { /* skip the next checks */ return TRUE; } if(action->node == NULL) { pe_err("action %d (%s) was not allocated", action->id, action->uuid); log_action(LOG_DEBUG, "Unallocated action", action, FALSE); return FALSE; } else if(action->node->details->online == FALSE) { pe_err("action %d was (%s) scheduled for offline node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for offline node", action, FALSE); return FALSE; #if 0 /* but this would also affect resources that can be safely * migrated before a fencing op */ } else if(action->node->details->unclean == FALSE) { pe_err("action %d was (%s) scheduled for unclean node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); return FALSE; #endif } return TRUE; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { int last_action = -1; int synapse_priority = 0; crm_data_t * syn = NULL; crm_data_t * set = NULL; crm_data_t * in = NULL; crm_data_t * input = NULL; crm_data_t * xml_action = NULL; if(should_dump_action(action) == FALSE) { return; } action->dumped = TRUE; syn = create_xml_node(data_set->graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); data_set->num_synapse++; if(action->rsc != NULL) { synapse_priority = action->rsc->priority; } if(action->priority > synapse_priority) { synapse_priority = action->priority; } if(synapse_priority > 0) { crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); } xml_action = action2xml(action, FALSE); add_node_copy(set, xml_action); free_xml(xml_action); action->actions_before = g_list_sort( action->actions_before, sort_action_id); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(last_action == wrapper->action->id) { crm_debug_2("Input (%d) %s duplicated", wrapper->action->id, wrapper->action->uuid); continue; } else if(wrapper->action->optional == TRUE) { crm_debug_2("Input (%d) %s optional", wrapper->action->id, wrapper->action->uuid); continue; } CRM_CHECK(last_action < wrapper->action->id, ;); last_action = wrapper->action->id; input = create_xml_node(in, "trigger"); xml_action = action2xml(wrapper->action, TRUE); add_node_copy(input, xml_action); free_xml(xml_action); ); } diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h index 74fe27b5ec..cc67522780 100644 --- a/crm/pengine/pengine.h +++ b/crm/pengine/pengine.h @@ -1,497 +1,496 @@ -/* $Id: pengine.h,v 1.112 2006/05/23 07:45:37 andrew Exp $ */ +/* $Id: pengine.h,v 1.113 2006/06/07 07:34:38 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PENGINE__H #define PENGINE__H #include typedef struct node_s node_t; typedef struct color_s color_t; typedef struct rsc_to_node_s rsc_to_node_t; typedef struct rsc_colocation_s rsc_colocation_t; typedef struct resource_s resource_t; typedef struct lrm_agent_s lrm_agent_t; typedef struct order_constraint_s order_constraint_t; typedef struct action_s action_t; typedef struct action_wrapper_s action_wrapper_t; #include #include #include #include #include /* * The man pages for both curses and ncurses suggest inclusion of "curses.h". * We believe the following to be acceptable and portable. */ #if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES) #if defined(HAVE_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_NCURSES_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_CURSES_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #else # define CURSES_ENABLED 0 #endif #else # define CURSES_ENABLED 0 #endif typedef enum no_quorum_policy_e { no_quorum_freeze, no_quorum_stop, no_quorum_ignore } no_quorum_policy_t; enum pe_print_options { pe_print_log = 0x0001, pe_print_html = 0x0002, pe_print_ncurses = 0x0004, pe_print_printf = 0x0008, pe_print_dev = 0x0010, pe_print_details = 0x0020, pe_print_max_details = 0x0040, pe_print_rsconly = 0x0080, }; typedef struct pe_working_set_s { crm_data_t *input; ha_time_t *now; /* options extracted from the input */ char *transition_idle_timeout; char *dc_uuid; node_t *dc_node; gboolean have_quorum; gboolean stonith_enabled; const char *stonith_action; gboolean symmetric_cluster; gboolean is_managed_default; gboolean remove_after_stop; gboolean stop_rsc_orphans; gboolean stop_action_orphans; int default_resource_stickiness; int default_resource_fail_stickiness; no_quorum_policy_t no_quorum_policy; GHashTable *config_hash; /* intermediate steps */ color_t *no_color; GListPtr nodes; GListPtr resources; GListPtr placement_constraints; GListPtr ordering_constraints; GListPtr colors; GListPtr actions; /* stats */ int num_synapse; int max_valid_nodes; int order_id; int action_id; int color_id; /* final output */ crm_data_t *graph; } pe_working_set_t; #include enum con_type { type_none, rsc_colocation, rsc_to_node, rsc_to_attr, base_weight }; enum node_type { node_ping, node_member }; enum con_strength { pecs_ignore, pecs_must, pecs_must_not, pecs_startstop }; enum action_tasks { no_action, monitor_rsc, stop_rsc, stopped_rsc, start_rsc, started_rsc, action_notify, action_notified, action_promote, action_promoted, action_demote, action_demoted, shutdown_crm, stonith_node }; enum rsc_recovery_type { recovery_stop_start, recovery_stop_only, recovery_block }; enum rsc_start_requirement { rsc_req_nothing, rsc_req_quorum, rsc_req_stonith }; enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; enum pe_restart { pe_restart_restart, pe_restart_ignore }; enum pe_ordering { pe_ordering_manditory, pe_ordering_restart, pe_ordering_recover, pe_ordering_postnotify, pe_ordering_optional }; enum rsc_role_e { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }; #define RSC_ROLE_MAX RSC_ROLE_MASTER+1 #define RSC_ROLE_UNKNOWN_S "Unknown" #define RSC_ROLE_STOPPED_S "Stopped" #define RSC_ROLE_STARTED_S "Started" #define RSC_ROLE_SLAVE_S "Slave" #define RSC_ROLE_MASTER_S "Master" struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean standby; gboolean unclean; gboolean shutdown; gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { int weight; gboolean fixed; struct node_shared_s *details; }; struct color_shared_s { int id; int highest_priority; GListPtr candidate_nodes; /* node_t* */ GListPtr allocated_resources; /* resources_t* */ node_t *chosen_node; gboolean pending; int num_resources; }; struct color_s { int id; struct color_shared_s *details; int local_weight; }; struct rsc_colocation_s { const char *id; resource_t *rsc_lh; resource_t *rsc_rh; const char *state_lh; const char *state_rh; enum con_strength strength; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; enum rsc_role_e role_filter; GListPtr node_list_rh; /* node_t* */ }; struct resource_s { char *id; char *long_name; crm_data_t *xml; crm_data_t *ops_xml; resource_t *parent; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; enum rsc_recovery_type recovery_type; enum pe_restart restart_type; int priority; int stickiness; int fail_stickiness; int effective_priority; gboolean notify; gboolean is_managed; gboolean starting; gboolean stopping; gboolean runnable; gboolean provisional; gboolean globally_unique; gboolean failed; gboolean start_pending; gboolean orphan; GListPtr candidate_colors; /* color_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr rsc_location; /* rsc_to_node_t* */ GListPtr actions; /* action_t* */ color_t *color; GListPtr colors; /* color_t* */ GListPtr running_on; /* node_t* */ GListPtr known_on; /* node_t* */ GListPtr allowed_nodes; /* node_t* */ enum rsc_role_e role; enum rsc_role_e next_role; GHashTable *meta; GHashTable *parameters; }; struct action_wrapper_s { enum pe_ordering type; action_t *action; }; /* order is significant here * items listed in order of accending severeness * more severe actions take precedent over lower ones */ enum action_fail_response { action_fail_ignore, action_fail_recover, action_fail_migrate, action_fail_block, /* action_fail_stop, */ action_fail_fence }; struct action_s { int id; int priority; resource_t *rsc; void *rsc_opaque; node_t *node; const char *task; char *uuid; crm_data_t *op_entry; gboolean pseudo; gboolean runnable; gboolean optional; gboolean failure_is_fatal; enum rsc_start_requirement needs; enum action_fail_response on_fail; enum rsc_role_e fail_role; gboolean dumped; gboolean processed; action_t *pre_notify; action_t *pre_notified; action_t *post_notify; action_t *post_notified; int seen_count; GHashTable *meta; GHashTable *extra; GHashTable *notify_keys; /* do NOT free */ GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; struct order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; extern gboolean stage0(pe_working_set_t *data_set); extern gboolean stage1(pe_working_set_t *data_set); extern gboolean stage2(pe_working_set_t *data_set); extern gboolean stage3(pe_working_set_t *data_set); extern gboolean stage4(pe_working_set_t *data_set); extern gboolean stage5(pe_working_set_t *data_set); extern gboolean stage6(pe_working_set_t *data_set); extern gboolean stage7(pe_working_set_t *data_set); extern gboolean stage8(pe_working_set_t *data_set); extern gboolean summary(GListPtr resources); extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data); extern gboolean process_pe_message( HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender); extern gboolean unpack_constraints( crm_data_t *xml_constraints, pe_working_set_t *data_set); extern gboolean unpack_resources( crm_data_t *xml_resources, pe_working_set_t *data_set); extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set); extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set); extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set); extern gboolean apply_placement_constraints(pe_working_set_t *data_set); extern gboolean choose_node_from_list(color_t *color); extern gboolean update_action_states(GListPtr actions); extern gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean stonith_constraints( - node_t *node, action_t *stonith_op, action_t *shutdown_op, - pe_working_set_t *data_set); + node_t *node, action_t *stonith_op, pe_working_set_t *data_set); extern gboolean custom_action_order( resource_t *lh_rsc, char *lh_task, action_t *lh_action, resource_t *rh_rsc, char *rh_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set); #define order_start_start(rsc1,rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_stop_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define order_restart(rsc1) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc1, start_key(rsc1), NULL, \ pe_ordering_restart, data_set) #define order_stop_start(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_start_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define pe_err(fmt...) { was_processing_error = TRUE; was_config_error = TRUE; crm_err(fmt); } #define pe_warn(fmt...) { was_processing_warning = TRUE; was_config_warning = TRUE; crm_warn(fmt); } #define pe_proc_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } #define pe_proc_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } #define pe_config_err(fmt...) { was_config_error = TRUE; crm_err(fmt); } #define pe_config_warn(fmt...) { was_config_warning = TRUE; crm_warn(fmt); } extern gboolean process_colored_constraints(resource_t *rsc); extern void graph_element_from_action( action_t *action, pe_working_set_t *data_set); extern void set_working_set_defaults(pe_working_set_t *data_set); extern void cleanup_calculations(pe_working_set_t *data_set); extern void order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order); extern const char* transition_idle_timeout; extern gboolean was_processing_error; extern gboolean was_processing_warning; extern gboolean was_config_error; extern gboolean was_config_warning; extern unsigned int pengine_input_loglevel; #endif diff --git a/crm/pengine/stages.c b/crm/pengine/stages.c index 0c68eba7c8..76ec47c2ef 100644 --- a/crm/pengine/stages.c +++ b/crm/pengine/stages.c @@ -1,584 +1,576 @@ -/* $Id: stages.c,v 1.103 2006/06/01 16:41:23 andrew Exp $ */ +/* $Id: stages.c,v 1.104 2006/06/07 07:34:38 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include node_t *choose_fencer(action_t *stonith, node_t *node, GListPtr resources); /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependencies on other resources) * - A list of constraints between resources and nodes * - A list of constraints between start/stop actions * - A list of nodes that need to be stonith'd * - A list of nodes that need to be shutdown * - A list of the possible stop/start actions (without dependencies) */ gboolean stage0(pe_working_set_t *data_set) { /* int lpc; */ crm_data_t * config = get_object_root( XML_CIB_TAG_CRMCONFIG, data_set->input); crm_data_t * cib_nodes = get_object_root( XML_CIB_TAG_NODES, data_set->input); crm_data_t * cib_resources = get_object_root( XML_CIB_TAG_RESOURCES, data_set->input); crm_data_t * cib_status = get_object_root( XML_CIB_TAG_STATUS, data_set->input); crm_data_t * cib_constraints = get_object_root( XML_CIB_TAG_CONSTRAINTS, data_set->input); const char *value = crm_element_value( data_set->input, XML_ATTR_HAVE_QUORUM); crm_debug_3("Beginning unpack"); /* reset remaining global variables */ if(data_set->input == NULL) { return FALSE; } if(data_set->input != NULL && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) { /* this should always be present */ data_set->dc_uuid = crm_element_value_copy( data_set->input, XML_ATTR_DC_UUID); } data_set->no_color = create_color(data_set, NULL, NULL); unpack_config(config, data_set); if(value != NULL) { cl_str_to_boolean(value, &data_set->have_quorum); } if(data_set->have_quorum == FALSE && data_set->no_quorum_policy != no_quorum_ignore) { crm_warn("We do not have quorum" " - fencing and resource management disabled"); } unpack_nodes(cib_nodes, data_set); unpack_resources(cib_resources, data_set); unpack_status(cib_status, data_set); unpack_constraints(cib_constraints, data_set); return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage1(pe_working_set_t *data_set) { crm_debug_3("Applying placement constraints"); slist_iter( node, node_t, data_set->nodes, lpc, if(node == NULL) { /* error */ } else if(node->weight >= 0.0 /* global weight */ && node->details->online && node->details->type == node_member) { data_set->max_valid_nodes++; } ); apply_placement_constraints(data_set); return TRUE; } /* * Choose a color for all resources from highest priority and XML_STRENGTH_VAL_MUST * dependencies to lowest, creating new colors as necessary (returned * as "colors"). * * Some nodes may be colored as a "no_color" meaning that it was unresolvable * given the current node stati and constraints. */ gboolean stage2(pe_working_set_t *data_set) { crm_debug_3("Coloring resources"); crm_debug_5("create \"no color\""); /* Take (next) highest resource */ slist_iter( lh_resource, resource_t, data_set->resources, lpc, lh_resource->fns->color(lh_resource, data_set); ); return TRUE; } /* * Check nodes for resources started outside of the LRM */ gboolean stage3(pe_working_set_t *data_set) { action_t *probe_complete = NULL; action_t *probe_node_complete = NULL; slist_iter( node, node_t, data_set->nodes, lpc, gboolean force_probe = FALSE; const char *probed = g_hash_table_lookup( node->details->attrs, CRM_OP_PROBED); crm_debug_2("%s probed: %s", node->details->uname, probed); if(node->details->online == FALSE) { continue; } else if(node->details->unclean) { continue; } else if(probe_complete == NULL) { probe_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, NULL, FALSE, TRUE, data_set); probe_complete->pseudo = TRUE; probe_complete->optional = TRUE; } if(probed != NULL && crm_is_true(probed) == FALSE) { force_probe = TRUE; } probe_node_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, node, FALSE, TRUE, data_set); probe_node_complete->optional = crm_is_true(probed); probe_node_complete->priority = INFINITY; add_hash_param(probe_node_complete->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order(NULL, NULL, probe_node_complete, NULL, NULL, probe_complete, pe_ordering_optional, data_set); slist_iter( rsc, resource_t, data_set->resources, lpc2, if(rsc->fns->create_probe( rsc, node, probe_node_complete, force_probe, data_set)) { probe_complete->optional = FALSE; probe_node_complete->optional = FALSE; custom_action_order( NULL, NULL, probe_complete, rsc, start_key(rsc), NULL, pe_ordering_manditory, data_set); } ); ); return TRUE; } /* * Choose a node for each (if possible) color */ gboolean stage4(pe_working_set_t *data_set) { node_t *chosen = NULL; crm_debug_3("Assigning nodes to colors"); slist_iter( color, color_t, data_set->colors, lpc, crm_debug_4("assigning node to color %d", color->id); if(color == NULL) { pe_err("NULL color detected"); continue; } else if(color->details->pending == FALSE) { continue; } choose_node_from_list(color); chosen = color->details->chosen_node; slist_iter( rsc, resource_t, color->details->allocated_resources, lpc2, crm_debug_2("Processing colocation constraints for %s" " now that color %d is allocated", rsc->id, color->details->id); if(chosen == NULL) { rsc->next_role = RSC_ROLE_STOPPED; } else if(rsc->next_role == RSC_ROLE_UNKNOWN) { rsc->next_role = RSC_ROLE_STARTED; } slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, rsc->fns->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); ); ); crm_debug_3("done"); return TRUE; } /* * Attach nodes to the actions that need to be taken * * Mark actions XML_LRM_ATTR_OPTIONAL if possible (Ie. if the start and stop are * for the same node) * * Mark unrunnable actions */ gboolean stage5(pe_working_set_t *data_set) { crm_debug_3("Creating actions and internal ording constraints"); slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->fns->create_actions(rsc, data_set); rsc->fns->internal_constraints(rsc, data_set); ); return TRUE; } /* * Create dependacies for stonith and shutdown operations */ gboolean stage6(pe_working_set_t *data_set) { - action_t *down_op = NULL; - action_t *stonith_op = NULL; action_t *dc_down = NULL; + action_t *stonith_op = NULL; crm_debug_3("Processing fencing and shutdown cases"); slist_iter( node, node_t, data_set->nodes, lpc, - if(node->details->online && node->details->shutdown) { - crm_info("Scheduling Node %s for shutdown", - node->details->uname); - - down_op = custom_action( - NULL, crm_strdup(CRM_OP_SHUTDOWN), - CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); - down_op->runnable = TRUE; - - shutdown_constraints( - node, down_op, data_set); - - if(node->details->is_dc) { - dc_down = down_op; - } - } - - if(node->details->unclean - && data_set->stonith_enabled == FALSE) { - pe_err("Node %s is unclean!", node->details->uname); - pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); - pe_warn("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); - } else if(node->details->unclean && data_set->stonith_enabled + stonith_op = NULL; + if(node->details->unclean && data_set->stonith_enabled && (data_set->have_quorum || data_set->no_quorum_policy == no_quorum_ignore)) { pe_warn("Scheduling Node %s for STONITH", node->details->uname); stonith_op = custom_action( NULL, crm_strdup(CRM_OP_FENCE), CRM_OP_FENCE, node, FALSE, TRUE, data_set); - stonith_op->runnable = TRUE; add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname); add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id); add_hash_param( stonith_op->meta, "stonith_action", data_set->stonith_action); - if(down_op != NULL) { - down_op->failure_is_fatal = FALSE; - } + stonith_constraints(node, stonith_op, data_set); if(node->details->is_dc) { dc_down = stonith_op; } + + } else if(node->details->online && node->details->shutdown) { + action_t *down_op = NULL; + crm_info("Scheduling Node %s for shutdown", + node->details->uname); + + down_op = custom_action( + NULL, crm_strdup(CRM_OP_SHUTDOWN), + CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); + + shutdown_constraints(node, down_op, data_set); + + if(node->details->is_dc) { + dc_down = down_op; + } } - if(node->details->unclean) { - stonith_constraints( - node, stonith_op, down_op, data_set); + if(node->details->unclean && stonith_op == NULL) { + pe_err("Node %s is unclean!", node->details->uname); + pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); + if(data_set->stonith_enabled == FALSE) { + pe_warn("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); + } else { + CRM_CHECK(data_set->have_quorum == FALSE, ;); + crm_notice("Cannot fence until quorum is attained (or no_quorum_policy is set to ignore)"); + } } - ); if(dc_down != NULL) { GListPtr shutdown_matches = find_actions( data_set->actions, CRM_OP_SHUTDOWN, NULL); crm_debug_2("Ordering shutdowns before %s on %s (DC)", - down_op->task, down_op->node->details->uname); + dc_down->task, dc_down->node->details->uname); add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); slist_iter( - action, action_t, shutdown_matches, lpc, - if(action->node->details->is_dc) { + node_stop, action_t, shutdown_matches, lpc, + if(node_stop->node->details->is_dc) { continue; } crm_debug("Ordering shutdown on %s before %s on %s", - action->node->details->uname, + node_stop->node->details->uname, dc_down->task, dc_down->node->details->uname); - custom_action_order( - NULL, crm_strdup(action->task), action, - NULL, crm_strdup(dc_down->task), dc_down, - pe_ordering_manditory, data_set); + order_actions(node_stop, dc_down, pe_ordering_manditory); ); } return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependencies of un-runnable actions un-runnable * */ gboolean stage7(pe_working_set_t *data_set) { crm_debug_3("Applying ordering constraints"); slist_iter( order, order_constraint_t, data_set->ordering_constraints, lpc, /* try rsc_action-to-rsc_action */ resource_t *rsc = order->lh_rsc; if(rsc == NULL && order->lh_action) { rsc = order->lh_action->rsc; } if(rsc != NULL) { rsc->fns->rsc_order_lh(rsc, order); continue; } /* try action-to-rsc_action */ /* que off the rh resource */ rsc = order->rh_rsc; if(rsc == NULL && order->rh_action) { rsc = order->rh_action->rsc; } if(rsc != NULL) { rsc->fns->rsc_order_rh(order->lh_action, rsc, order); } else { /* fall back to action-to-action */ order_actions( order->lh_action, order->rh_action, order->type); } ); update_action_states(data_set->actions); return TRUE; } int transition_id = -1; /* * Create a dependency graph to send to the transitioner (via the CRMd) */ gboolean stage8(pe_working_set_t *data_set) { char *transition_id_s = NULL; transition_id++; transition_id_s = crm_itoa(transition_id); crm_debug("Creating transition graph %d.", transition_id); data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); crm_xml_add(data_set->graph, "global_timeout", data_set->transition_idle_timeout); crm_xml_add(data_set->graph, "transition_id", transition_id_s); crm_free(transition_id_s); /* errors... slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("Ignoring", action, TRUE); } ); */ slist_iter( rsc, resource_t, data_set->resources, lpc, crm_debug_4("processing actions for rsc=%s", rsc->id); rsc->fns->expand(rsc, data_set); ); crm_log_xml_debug_3( data_set->graph, "created resource-driven action list"); /* catch any non-resource specific actions */ crm_debug_4("processing non-resource actions"); slist_iter( action, action_t, data_set->actions, lpc, graph_element_from_action(action, data_set); ); crm_log_xml_debug_3(data_set->graph, "created generic action list"); crm_notice("Created transition graph %d.", transition_id); return TRUE; } gboolean choose_node_from_list(color_t *color) { /* 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 = color->details->candidate_nodes; node_t *chosen = NULL; int multiple = 0; crm_debug_3("Choosing node for color %d", color->id); color->details->candidate_nodes = g_list_sort(nodes, sort_node_weight); nodes = color->details->candidate_nodes; chosen = g_list_nth_data(nodes, 0); color->details->chosen_node = NULL; color->details->pending = FALSE; if(chosen == NULL) { if(color->id != 0) { crm_debug("Could not allocate a node for color %d", color->id); } return FALSE; } else if(chosen->details->unclean || chosen->details->standby || chosen->details->shutdown) { crm_debug("All nodes for color %d are unavailable" ", unclean or shutting down", color->id); color->details->chosen_node = NULL; return FALSE; } else if(chosen->weight < 0) { crm_debug_2("Even highest ranked node for color %d, had weight %d", color->id, chosen->weight); color->details->chosen_node = NULL; return FALSE; } slist_iter(candidate, node_t, nodes, lpc, crm_debug_2("Color %d, Node[%d] %s: %d", color->id, lpc, candidate->details->uname, candidate->weight); if(chosen->weight > 0 && candidate->details->unclean == FALSE && candidate->weight == chosen->weight) { multiple++; } else { break; } ); if(multiple > 1) { int log_level = LOG_INFO; char *score = score2char(chosen->weight); if(chosen->weight >= INFINITY) { log_level = LOG_WARNING; } crm_log_maybe(log_level, "%d nodes with equal score (%s) for" " running the listed resources (chose %s):", multiple, score, chosen->details->uname); slist_iter(rsc, resource_t, color->details->allocated_resources, lpc, rsc->fns->print( rsc, "\t", pe_print_log|pe_print_rsconly, &log_level); ); crm_free(score); } /* todo: update the old node for each resource to reflect its * new resource count */ chosen->details->num_resources += color->details->num_resources; color->details->chosen_node = node_copy(chosen); return TRUE; } diff --git a/crm/pengine/testcases/rec-node-13.dot b/crm/pengine/testcases/rec-node-13.dot new file mode 100644 index 0000000000..9e25086c79 --- /dev/null +++ b/crm/pengine/testcases/rec-node-13.dot @@ -0,0 +1,190 @@ +digraph "g" { + size = "30,30" +"ocf_msdummy:6_monitor_5000 c001n04" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:6_stop_0 c001n04" [ style=bold color="green" fontcolor="orange" ] +"ocf_192.168.100.181_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_monitor_20000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_monitor_5000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_monitor_6000 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n04_monitor_5000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:9_monitor_5000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n05_monitor_5000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:11_monitor_5000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n07_monitor_5000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:5_monitor_20000 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"lsb_dummy_monitor_5000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_monitor_5000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:8_monitor_5000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:10_monitor_5000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n06_monitor_5000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:4_monitor_20000 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"probe_complete" [ style="dashed" color="blue" fontcolor="orange" ] +"probe_complete c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"probe_complete c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"probe_complete c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.181_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.181_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"heartbeat_192.168.100.182_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_192.168.100.183_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"group-1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] +"group-1_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] +"lsb_dummy_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"lsb_dummy_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n05_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n05_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n03_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n04_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n04_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n02_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n07_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n07_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n06_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"rsc_c001n06_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:3_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:4_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:4_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:5_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"child_DoFencing:5_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"DoFencing_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_stop_0" [ style="dashed" color="blue" fontcolor="orange" ] +"DoFencing_stopped_0" [ style="dashed" color="blue" fontcolor="orange" ] +"ocf_msdummy:0_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:0_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:10_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:10_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:11_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:11_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_stop_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:4_start_0 c001n02" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:8_stop_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:8_start_0 c001n06" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:9_stop_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"ocf_msdummy:9_start_0 c001n07" [ style="dashed" color="blue" fontcolor="black" ] +"master_rsc_1_start_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_running_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_stop_0" [ style=bold color="green" fontcolor="orange" ] +"master_rsc_1_stopped_0" [ style=bold color="green" fontcolor="orange" ] +"master_rsc_1_promote_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_promoted_0" [ style="dashed" color="blue" fontcolor="orange" ] +"master_rsc_1_demote_0" [ style=bold color="green" fontcolor="orange" ] +"master_rsc_1_demoted_0" [ style="dashed" color="blue" fontcolor="orange" ] +"stonith c001n04" [ style=bold color="green" fontcolor="black" ] +"master_rsc_1_stop_0" -> "ocf_msdummy:6_stop_0 c001n04" [ style = bold] +"stonith c001n04" -> "ocf_msdummy:6_stop_0 c001n04" [ style = bold] +"ocf_192.168.100.181_start_0 c001n02" -> "ocf_192.168.100.181_monitor_5000 c001n02" [ style = dashed] +"ocf_msdummy:4_start_0 c001n02" -> "ocf_msdummy:4_monitor_5000 c001n02" [ style = dashed] +"ocf_192.168.100.183_start_0 c001n02" -> "ocf_192.168.100.183_monitor_5000 c001n02" [ style = dashed] +"rsc_c001n02_start_0 c001n02" -> "rsc_c001n02_monitor_5000 c001n02" [ style = dashed] +"child_DoFencing:3_start_0 c001n02" -> "child_DoFencing:3_monitor_20000 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_start_0 c001n02" -> "heartbeat_192.168.100.182_monitor_5000 c001n02" [ style = dashed] +"ocf_msdummy:0_start_0 c001n02" -> "ocf_msdummy:0_monitor_6000 c001n02" [ style = dashed] +"rsc_c001n04_start_0 c001n07" -> "rsc_c001n04_monitor_5000 c001n07" [ style = dashed] +"ocf_msdummy:9_start_0 c001n07" -> "ocf_msdummy:9_monitor_5000 c001n07" [ style = dashed] +"rsc_c001n05_start_0 c001n07" -> "rsc_c001n05_monitor_5000 c001n07" [ style = dashed] +"ocf_msdummy:11_start_0 c001n07" -> "ocf_msdummy:11_monitor_5000 c001n07" [ style = dashed] +"rsc_c001n07_start_0 c001n07" -> "rsc_c001n07_monitor_5000 c001n07" [ style = dashed] +"child_DoFencing:5_start_0 c001n07" -> "child_DoFencing:5_monitor_20000 c001n07" [ style = dashed] +"lsb_dummy_start_0 c001n06" -> "lsb_dummy_monitor_5000 c001n06" [ style = dashed] +"rsc_c001n03_start_0 c001n06" -> "rsc_c001n03_monitor_5000 c001n06" [ style = dashed] +"ocf_msdummy:8_start_0 c001n06" -> "ocf_msdummy:8_monitor_5000 c001n06" [ style = dashed] +"ocf_msdummy:10_start_0 c001n06" -> "ocf_msdummy:10_monitor_5000 c001n06" [ style = dashed] +"rsc_c001n06_start_0 c001n06" -> "rsc_c001n06_monitor_5000 c001n06" [ style = dashed] +"child_DoFencing:4_start_0 c001n06" -> "child_DoFencing:4_monitor_20000 c001n06" [ style = dashed] +"probe_complete c001n02" -> "probe_complete" [ style = dashed] +"probe_complete c001n06" -> "probe_complete" [ style = dashed] +"probe_complete c001n07" -> "probe_complete" [ style = dashed] +"heartbeat_192.168.100.182_stop_0 c001n02" -> "ocf_192.168.100.181_stop_0 c001n02" [ style = dashed] +"ocf_192.168.100.181_stop_0 c001n02" -> "ocf_192.168.100.181_start_0 c001n02" [ style = dashed] +"group-1_start_0" -> "ocf_192.168.100.181_start_0 c001n02" [ style = dashed] +"ocf_192.168.100.183_stop_0 c001n02" -> "heartbeat_192.168.100.182_stop_0 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_stop_0 c001n02" -> "heartbeat_192.168.100.182_start_0 c001n02" [ style = dashed] +"ocf_192.168.100.181_start_0 c001n02" -> "heartbeat_192.168.100.182_start_0 c001n02" [ style = dashed] +"group-1_stop_0" -> "ocf_192.168.100.183_stop_0 c001n02" [ style = dashed] +"ocf_192.168.100.183_stop_0 c001n02" -> "ocf_192.168.100.183_start_0 c001n02" [ style = dashed] +"heartbeat_192.168.100.182_start_0 c001n02" -> "ocf_192.168.100.183_start_0 c001n02" [ style = dashed] +"group-1_stop_0" -> "group-1_start_0" [ style = dashed] +"group-1_stopped_0" -> "group-1_start_0" [ style = dashed] +"group-1_start_0" -> "group-1_running_0" [ style = dashed] +"ocf_192.168.100.183_start_0 c001n02" -> "group-1_running_0" [ style = dashed] +"group-1_stop_0" -> "group-1_stopped_0" [ style = dashed] +"ocf_192.168.100.181_stop_0 c001n02" -> "group-1_stopped_0" [ style = dashed] +"lsb_dummy_stop_0 c001n06" -> "lsb_dummy_start_0 c001n06" [ style = dashed] +"rsc_c001n05_stop_0 c001n07" -> "rsc_c001n05_start_0 c001n07" [ style = dashed] +"rsc_c001n03_stop_0 c001n06" -> "rsc_c001n03_start_0 c001n06" [ style = dashed] +"rsc_c001n04_stop_0 c001n07" -> "rsc_c001n04_start_0 c001n07" [ style = dashed] +"rsc_c001n02_stop_0 c001n02" -> "rsc_c001n02_start_0 c001n02" [ style = dashed] +"rsc_c001n07_stop_0 c001n07" -> "rsc_c001n07_start_0 c001n07" [ style = dashed] +"rsc_c001n06_stop_0 c001n06" -> "rsc_c001n06_start_0 c001n06" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:3_stop_0 c001n02" [ style = dashed] +"child_DoFencing:3_stop_0 c001n02" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:3_start_0 c001n02" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:4_stop_0 c001n06" [ style = dashed] +"child_DoFencing:4_stop_0 c001n06" -> "child_DoFencing:4_start_0 c001n06" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:4_start_0 c001n06" [ style = dashed] +"DoFencing_stop_0" -> "child_DoFencing:5_stop_0 c001n07" [ style = dashed] +"child_DoFencing:5_stop_0 c001n07" -> "child_DoFencing:5_start_0 c001n07" [ style = dashed] +"DoFencing_start_0" -> "child_DoFencing:5_start_0 c001n07" [ style = dashed] +"DoFencing_stop_0" -> "DoFencing_start_0" [ style = dashed] +"DoFencing_stopped_0" -> "DoFencing_start_0" [ style = dashed] +"DoFencing_start_0" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:3_start_0 c001n02" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:4_start_0 c001n06" -> "DoFencing_running_0" [ style = dashed] +"child_DoFencing:5_start_0 c001n07" -> "DoFencing_running_0" [ style = dashed] +"DoFencing_stop_0" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:3_stop_0 c001n02" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:4_stop_0 c001n06" -> "DoFencing_stopped_0" [ style = dashed] +"child_DoFencing:5_stop_0 c001n07" -> "DoFencing_stopped_0" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:0_stop_0 c001n02" [ style = dashed] +"ocf_msdummy:0_stop_0 c001n02" -> "ocf_msdummy:0_start_0 c001n02" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:0_start_0 c001n02" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:10_stop_0 c001n06" [ style = dashed] +"ocf_msdummy:10_stop_0 c001n06" -> "ocf_msdummy:10_start_0 c001n06" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:10_start_0 c001n06" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:11_stop_0 c001n07" [ style = dashed] +"ocf_msdummy:11_stop_0 c001n07" -> "ocf_msdummy:11_start_0 c001n07" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:11_start_0 c001n07" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:4_stop_0 c001n02" [ style = dashed] +"ocf_msdummy:4_stop_0 c001n02" -> "ocf_msdummy:4_start_0 c001n02" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:4_start_0 c001n02" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:8_stop_0 c001n06" [ style = dashed] +"ocf_msdummy:8_stop_0 c001n06" -> "ocf_msdummy:8_start_0 c001n06" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:8_start_0 c001n06" [ style = dashed] +"master_rsc_1_stop_0" -> "ocf_msdummy:9_stop_0 c001n07" [ style = dashed] +"ocf_msdummy:9_stop_0 c001n07" -> "ocf_msdummy:9_start_0 c001n07" [ style = dashed] +"master_rsc_1_start_0" -> "ocf_msdummy:9_start_0 c001n07" [ style = dashed] +"master_rsc_1_stop_0" -> "master_rsc_1_start_0" [ style = dashed] +"master_rsc_1_stopped_0" -> "master_rsc_1_start_0" [ style = dashed] +"master_rsc_1_demoted_0" -> "master_rsc_1_start_0" [ style = dashed] +"master_rsc_1_start_0" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:0_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:10_start_0 c001n06" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:11_start_0 c001n07" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:4_start_0 c001n02" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:8_start_0 c001n06" -> "master_rsc_1_running_0" [ style = dashed] +"ocf_msdummy:9_start_0 c001n07" -> "master_rsc_1_running_0" [ style = dashed] +"master_rsc_1_demote_0" -> "master_rsc_1_stop_0" [ style = bold] +"master_rsc_1_demoted_0" -> "master_rsc_1_stop_0" [ style = dashed] +"ocf_msdummy:6_stop_0 c001n04" -> "master_rsc_1_stopped_0" [ style = bold] +"ocf_msdummy:0_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:10_stop_0 c001n06" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:11_stop_0 c001n07" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:4_stop_0 c001n02" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:8_stop_0 c001n06" -> "master_rsc_1_stopped_0" [ style = dashed] +"ocf_msdummy:9_stop_0 c001n07" -> "master_rsc_1_stopped_0" [ style = dashed] +"master_rsc_1_stop_0" -> "master_rsc_1_stopped_0" [ style = bold] +"master_rsc_1_start_0" -> "master_rsc_1_promote_0" [ style = dashed] +"master_rsc_1_running_0" -> "master_rsc_1_promote_0" [ style = dashed] +"master_rsc_1_demote_0" -> "master_rsc_1_demoted_0" [ style = dashed] +"DoFencing_running_0" -> "stonith c001n04" [ style = dashed] +} diff --git a/crm/pengine/testcases/rec-node-13.exp b/crm/pengine/testcases/rec-node-13.exp new file mode 100644 index 0000000000..b2c3723c77 --- /dev/null +++ b/crm/pengine/testcases/rec-node-13.exp @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crm/pengine/testcases/rec-node-13.xml b/crm/pengine/testcases/rec-node-13.xml new file mode 100644 index 0000000000..7900092e5f --- /dev/null +++ b/crm/pengine/testcases/rec-node-13.xml @@ -0,0 +1,861 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +