diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c index 4c074496bf..497bda584d 100644 --- a/crm/pengine/graph.c +++ b/crm/pengine/graph.c @@ -1,364 +1,376 @@ -/* $Id: graph.c,v 1.31 2005/04/07 13:51:25 andrew Exp $ */ +/* $Id: graph.c,v 1.32 2005/04/08 16:57:10 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 gboolean update_action(action_t *action); gboolean update_action_states(GListPtr actions) { slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } gboolean update_action(action_t *action) { gboolean change = FALSE; if(action->optional && action->runnable) { return FALSE; } slist_iter( other, action_wrapper_t, action->actions_after, lpc, if(action->runnable == FALSE && action->optional == FALSE) { if(other->action->runnable == FALSE) { continue; } else if (other->strength == pecs_must) { change = TRUE; other->action->runnable =FALSE; crm_devel_action( print_action("Marking unrunnable", other->action, FALSE); print_action("Reason", action, FALSE); ); } } if(action->optional == FALSE && other->action->optional) { switch(action->rsc->restart_type) { case pe_restart_ignore: break; case pe_restart_recover: crm_err("Recover after dependancy " "restart not supported... " "forcing a restart"); /* keep going */ case pe_restart_restart: change = TRUE; other->action->optional = FALSE; crm_devel_action( print_action("Marking manditory", other->action, FALSE)); } } if(change) { update_action(other->action); } ); return change; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, GListPtr *ordering_constraints) { /* 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, order_new(rsc, stop_rsc, NULL, NULL, shutdown_crm, shutdown_op, pecs_must, ordering_constraints); ); return TRUE; } gboolean stonith_constraints(node_t *node, action_t *stonith_op, action_t *shutdown_op, GListPtr *ordering_constraints) { GListPtr stop_actions = NULL; if(shutdown_op != NULL) { /* shutdown before stonith */ /* add the shutdown OP to the before lists so it counts as a pre-req */ crm_devel("Adding shutdown (%d) as an input to stonith (%d)", shutdown_op->id, stonith_op->id); order_new(NULL, shutdown_crm, shutdown_op, NULL, stonith_node, stonith_op, pecs_must, ordering_constraints); } /* add the stonith OP to the before lists so it counts as a pre-req */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, /* make use of timeouts in the TE for cases such * as this. * ie. the node may be cactus and unable to receive the * stop let alone reply with failed. */ stop_actions = find_actions(rsc->actions, stop_rsc, node); slist_iter( action, action_t, stop_actions, lpc2, action->discard = TRUE; ); if(rsc->stopfail_type == pesf_block) { /* depend on the stop action which will fail */ crm_warn("SHARED RESOURCE %s WILL REMAIN BLOCKED" " UNTIL CLEANED UP MANUALLY ON NODE %s", rsc->id, node->details->uname); continue; } else if(rsc->stopfail_type == pesf_ignore) { /* nothing to do here */ crm_warn("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); continue; } /* case pesf_stonith: */ /* remedial action: * shutdown (so all other resources are * stopped gracefully) and then STONITH node */ if(stonith_enabled == FALSE) { /* depend on an action that will never complete */ crm_err("STONITH is not enabled in this" " cluster but is required for " "resource %s after a failed stop", rsc->id); } crm_devel("Adding stonith (%d) as an input to start", stonith_op->id); /* stonith before start */ order_new(NULL, stonith_node, stonith_op, rsc, start_rsc, NULL, pecs_must, ordering_constraints); /* a pointless optimization? probably */ /* if(shutdown_op != NULL) { */ /* /\* the next rule is implied *\/ */ /* continue; */ /* } */ /* stop before stonith */ order_new(rsc, stop_rsc, NULL, NULL, stonith_node, stonith_op, pecs_must, ordering_constraints); ); return TRUE; } crm_data_t * action2xml(action_t *action, gboolean as_input) { crm_data_t * action_xml = NULL; crm_data_t * args_xml = NULL; if(action == NULL) { return NULL; } crm_devel("Dumping action %d as XML", action->id); switch(action->task) { case stonith_node: case shutdown_crm: action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); set_xml_property_copy( action_xml, XML_ATTR_ID, crm_itoa(action->id)); set_xml_property_copy(action_xml, XML_LRM_ATTR_TASK, task2text(action->task)); break; default: if(action->pseudo) { action_xml = create_xml_node(NULL,XML_GRAPH_TAG_PSEUDO_EVENT); } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } if(!as_input && action->rsc != NULL) { crm_data_t *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); copy_in_properties(rsc_xml, action->rsc->xml); } set_xml_property_copy( action_xml, XML_ATTR_ID, crm_itoa(action->id)); if(safe_val3(NULL, action, rsc, id) != NULL) { set_xml_property_copy( action_xml, XML_LRM_ATTR_RSCID, safe_val3(NULL, action, rsc, id)); } set_xml_property_copy(action_xml, XML_LRM_ATTR_TASK, task2text(action->task)); break; } if(action->task != stonith_node && (action->pseudo == FALSE || action->node != NULL)) { set_xml_property_copy( action_xml, XML_LRM_ATTR_TARGET, safe_val4(NULL, action, node, details,uname)); set_xml_property_copy( action_xml, XML_LRM_ATTR_TARGET_UUID, safe_val4(NULL, action, node, details, id)); CRM_DEV_ASSERT(NULL != crm_element_value( action_xml, XML_LRM_ATTR_TARGET)); CRM_DEV_ASSERT(NULL != crm_element_value( action_xml, XML_LRM_ATTR_TARGET_UUID)); } set_xml_property_copy( action_xml, "allow_fail", action->failure_is_fatal?XML_BOOLEAN_FALSE:XML_BOOLEAN_TRUE); if(as_input) { return action_xml; } args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); g_hash_table_foreach(action->extra, hash2nvpair, args_xml); if(action->rsc != NULL) { g_hash_table_foreach( action->rsc->parameters, hash2nvpair, args_xml); } crm_xml_debug(args_xml, "copied in extra attributes"); return action_xml; } void graph_element_from_action(action_t *action, crm_data_t * *graph) { char *syn_id = NULL; 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(action == NULL) { crm_err("Cannot dump NULL action"); return; + } else if(action->optional) { crm_trace("action %d was optional", action->id); return; + } else if(action->runnable == FALSE) { crm_trace("action %d was not runnable", action->id); return; + } else if(action->dumped) { crm_trace("action %d was already dumped", action->id); return; } else if(action->discard) { crm_trace("action %d was discarded", action->id); return; + + } else if(action->node == NULL) { + crm_err("action %d was not allocated", action->id); + return; + + } else if(action->node->details->online == NULL) { + crm_err("action %d was scheduled for offline node", action->id); + return; } + action->dumped = TRUE; syn = create_xml_node(*graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); syn_id = crm_itoa(num_synapse++); set_xml_property_copy(syn, XML_ATTR_ID, syn_id); crm_free(syn_id); xml_action = action2xml(action, FALSE); add_node_copy(set, xml_action); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(wrapper->action->optional == TRUE) { continue; } else if(wrapper->action->discard == TRUE) { continue; } switch(wrapper->strength) { case pecs_must_not: case pecs_ignore: /* ignore both */ break; case pecs_startstop: if(wrapper->action->runnable == FALSE){ break; } /* keep going */ case pecs_must: input = create_xml_node(in, "trigger"); xml_action = action2xml( wrapper->action, TRUE); add_node_copy(input, xml_action); break; } ); free_xml(xml_action); } diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h index 82c688cb6a..fc09bb011f 100644 --- a/crm/pengine/pengine.h +++ b/crm/pengine/pengine.h @@ -1,340 +1,341 @@ -/* $Id: pengine.h,v 1.55 2005/04/06 13:54:39 andrew Exp $ */ +/* $Id: pengine.h,v 1.56 2005/04/08 16:57:10 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 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, shutdown_crm, stonith_node }; enum rsc_recovery_type { recovery_stop_start, recovery_stop_only, recovery_block }; enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; enum pe_restart { pe_restart_restart, pe_restart_recover, pe_restart_ignore }; struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean unclean; gboolean shutdown; + gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GListPtr agents; /* lrm_agent_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { float weight; gboolean fixed; struct node_shared_s *details; }; struct color_shared_s { int id; float 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; float local_weight; }; struct rsc_colocation_s { const char *id; resource_t *rsc_lh; resource_t *rsc_rh; enum con_strength strength; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; float weight; GListPtr node_list_rh; /* node_t* */ }; struct lrm_agent_s { const char *class; const char *type; const char *version; }; struct resource_s { const char *id; crm_data_t * xml; crm_data_t * ops_xml; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; float priority; float effective_priority; gboolean starting; gboolean stopping; gboolean is_stonith; gboolean runnable; gboolean provisional; enum rsc_recovery_type recovery_type; enum pe_stop_fail stopfail_type; enum pe_restart restart_type; GListPtr candidate_colors; /* color_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr actions; /* action_t* */ GHashTable * parameters; }; struct action_wrapper_s { enum con_strength strength; action_t *action; }; struct action_s { int id; resource_t *rsc; void *rsc_opaque; node_t *node; enum action_tasks task; gboolean pseudo; gboolean runnable; gboolean dumped; gboolean processed; gboolean optional; gboolean discard; gboolean failure_is_fatal; int seen_count; const char *timeout; /* crm_data_t *args; */ GHashTable *extra; GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; struct order_constraint_s { int id; enum con_strength strength; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; enum action_tasks lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; enum action_tasks rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; extern gboolean stage0(crm_data_t *cib, GListPtr *nodes, GListPtr *rscs, GListPtr *cons, GListPtr *actions, GListPtr *ordering_constraints, GListPtr *stonith_list, GListPtr *shutdown_list); extern gboolean stage1(GListPtr placement_constraints, GListPtr nodes, GListPtr resources); extern gboolean stage2(GListPtr sorted_rscs, GListPtr sorted_nodes, GListPtr *colors); extern gboolean stage3(GListPtr colors); extern gboolean stage4(GListPtr colors); extern gboolean stage5(GListPtr resources, GListPtr *ordering_constraints); extern gboolean stage6( GListPtr *actions, GListPtr *ordering_constraints, GListPtr nodes, GListPtr resources); extern gboolean stage7( GListPtr resources, GListPtr actions, GListPtr ordering_constraints); extern gboolean stage8( GListPtr resources, GListPtr action_sets, crm_data_t **graph); 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, GListPtr nodes, GListPtr resources, GListPtr *placement_constraints, GListPtr *ordering_constraints); extern gboolean unpack_resources(crm_data_t *xml_resources, GListPtr *resources, GListPtr *actions, GListPtr *ordering_constraints, GListPtr *placement_constraints, GListPtr all_nodes); extern gboolean unpack_config(crm_data_t *config); extern gboolean unpack_config(crm_data_t *config); extern gboolean unpack_global_defaults(crm_data_t *defaults); extern gboolean unpack_nodes(crm_data_t *xml_nodes, GListPtr *nodes); extern gboolean unpack_status(crm_data_t *status, GListPtr nodes, GListPtr rsc_list, GListPtr *actions, GListPtr *placement_constraints); extern gboolean apply_placement_constraints(GListPtr constraints, GListPtr nodes); extern gboolean apply_agent_constraints(GListPtr resources); extern void color_resource(resource_t *lh_resource, GListPtr *colors, GListPtr resources); 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, GListPtr *ordering_constraints); extern gboolean stonith_constraints( node_t *node, action_t *stonith_op, action_t *shutdown_op, GListPtr *ordering_constraints); extern gboolean order_new( resource_t *lh_rsc, enum action_tasks lh_task, action_t *lh_action, resource_t *rh_rsc, enum action_tasks rh_task, action_t *rh_action, enum con_strength strength, GListPtr *ordering_constraints); extern gboolean process_colored_constraints(resource_t *rsc); extern void graph_element_from_action(action_t *action, crm_data_t **graph); extern color_t *no_color; extern int max_valid_nodes; extern int order_id; extern int action_id; extern gboolean stonith_enabled; extern gboolean have_quorum; extern gboolean require_quorum; extern gboolean symmetric_cluster; extern GListPtr agent_defaults; extern const char* transition_timeout; extern int num_synapse; extern int color_id; extern char *dc_uuid; #endif diff --git a/crm/pengine/stages.c b/crm/pengine/stages.c index b0db4a335f..e2219fb7a5 100644 --- a/crm/pengine/stages.c +++ b/crm/pengine/stages.c @@ -1,456 +1,462 @@ -/* $Id: stages.c,v 1.47 2005/04/01 12:33:08 andrew Exp $ */ +/* $Id: stages.c,v 1.48 2005/04/08 16:57:10 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 node_t *choose_fencer(action_t *stonith, node_t *node, GListPtr resources); void order_actions(action_t *lh, action_t *rh, order_constraint_t *order); int order_id = 1; int max_valid_nodes = 0; GListPtr agent_defaults = NULL; gboolean have_quorum = FALSE; gboolean require_quorum = FALSE; gboolean stonith_enabled = FALSE; gboolean symmetric_cluster = TRUE; char *dc_uuid = NULL; const char* transition_timeout = "60000"; /* 1 minute */ /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependancies 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 dependancies) */ gboolean stage0(crm_data_t * cib, GListPtr *resources, GListPtr *nodes, GListPtr *placement_constraints, GListPtr *actions, GListPtr *ordering_constraints, GListPtr *stonith_list, GListPtr *shutdown_list) { /* int lpc; */ crm_data_t * cib_nodes = get_object_root( XML_CIB_TAG_NODES, cib); crm_data_t * cib_status = get_object_root( XML_CIB_TAG_STATUS, cib); crm_data_t * cib_resources = get_object_root( XML_CIB_TAG_RESOURCES, cib); crm_data_t * cib_constraints = get_object_root( XML_CIB_TAG_CONSTRAINTS, cib); crm_data_t * config = get_object_root( XML_CIB_TAG_CRMCONFIG, cib); crm_data_t * agent_defaults = NULL; /*get_object_root(XML_CIB_TAG_RA_DEFAULTS, cib); */ crm_free(dc_uuid); dc_uuid = NULL; if(cib != NULL && crm_element_value(cib, XML_ATTR_DC_UUID) != NULL) { /* this should always be present */ dc_uuid = crm_element_value_copy(cib, XML_ATTR_DC_UUID); } /* reset remaining global variables */ num_synapse = 0; max_valid_nodes = 0; order_id = 1; action_id = 1; color_id = 0; have_quorum = FALSE; require_quorum = FALSE; stonith_enabled = FALSE; unpack_config(config); if(require_quorum) { const char *value = crm_element_value(cib, XML_ATTR_HAVE_QUORUM); if(value != NULL) { crm_str_to_boolean(value, &have_quorum); } if(have_quorum == FALSE) { crm_warn("We do not have quorum" " - fencing and resource management disabled"); } } unpack_global_defaults(agent_defaults); unpack_nodes(cib_nodes, nodes); unpack_resources(cib_resources, resources, actions, ordering_constraints, placement_constraints, *nodes); unpack_status(cib_status, *nodes, *resources, actions, placement_constraints); unpack_constraints(cib_constraints, *nodes, *resources, placement_constraints, ordering_constraints); 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(GListPtr placement_constraints, GListPtr nodes, GListPtr resources) { crm_devel("Processing stage 1"); slist_iter( node, node_t, nodes, lpc, if(node == NULL) { /* error */ } else if(node->weight >= 0.0 /* global weight */ && node->details->online && node->details->type == node_member) { max_valid_nodes++; } ); apply_placement_constraints(placement_constraints, nodes); /* will also filter -ve "final" weighted nodes from resources' * allowed lists while we are there */ apply_agent_constraints(resources); return TRUE; } /* * Choose a color for all resources from highest priority and XML_STRENGTH_VAL_MUST * dependancies 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(GListPtr sorted_rscs, GListPtr sorted_nodes, GListPtr *colors) { crm_devel("Processing stage 2"); if(no_color != NULL) { crm_free(no_color->details); crm_free(no_color); } crm_trace("create \"no color\""); no_color = create_color(NULL, NULL, NULL); /* Take (next) highest resource */ slist_iter( lh_resource, resource_t, sorted_rscs, lpc, /* if resource.provisional == FALSE, repeat */ if(lh_resource->provisional == FALSE) { /* already processed this resource */ continue; } color_resource(lh_resource, colors, sorted_rscs); /* next resource */ ); return TRUE; } /* * not sure if this is a good idea or not, but eventually we might like * to utilize as many nodes as possible... and this might be a convienient * hook */ gboolean stage3(GListPtr colors) { crm_devel("Processing stage 3"); /* not sure if this is a good idea or not */ if((ssize_t)g_list_length(colors) > max_valid_nodes) { /* we need to consolidate some */ } else if((ssize_t)g_list_length(colors) < max_valid_nodes) { /* we can create a few more */ } return TRUE; } /* * Choose a node for each (if possible) color */ gboolean stage4(GListPtr colors) { crm_devel("Processing stage 4"); slist_iter( color, color_t, colors, lpc, crm_devel("assigning node to color %d", color->id); if(color == NULL) { crm_err("NULL color detected"); continue; } else if(color->details->pending == FALSE) { continue; } choose_node_from_list(color); crm_devel("assigned %s to color %d", safe_val5(NULL, color, details, chosen_node, details, uname), color->id); slist_iter( rsc, resource_t, color->details->allocated_resources, lpc2, slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, rsc->fns->rsc_colocation_lh(constraint); ); ); ); crm_verbose("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(GListPtr resources, GListPtr *ordering_constraints) { slist_iter( rsc, resource_t, resources, lpc, rsc->fns->create_actions(rsc, ordering_constraints); rsc->fns->internal_constraints(rsc, ordering_constraints); ); return TRUE; } /* * Create dependacies for stonith and shutdown operations */ gboolean stage6(GListPtr *actions, GListPtr *ordering_constraints, GListPtr nodes, GListPtr resources) { action_t *down_op = NULL; action_t *stonith_op = NULL; crm_devel("Processing stage 6"); slist_iter( node, node_t, nodes, lpc, - if(node->details->shutdown) { + if(node->details->online && node->details->shutdown) { crm_info("Scheduling Node %s for shutdown", node->details->uname); down_op = action_new(NULL, shutdown_crm, NULL, node); down_op->runnable = TRUE; *actions = g_list_append(*actions, down_op); shutdown_constraints( node, down_op, ordering_constraints); } if(node->details->unclean && stonith_enabled) { crm_warn("Scheduling Node %s for STONITH", node->details->uname); stonith_op = action_new(NULL, stonith_node,NULL,NULL); stonith_op->runnable = TRUE; add_hash_param( stonith_op->extra, XML_LRM_ATTR_TARGET, node->details->uname); add_hash_param( stonith_op->extra, XML_LRM_ATTR_TARGET_UUID, node->details->id); if(down_op != NULL) { down_op->failure_is_fatal = FALSE; } *actions = g_list_append(*actions, stonith_op); stonith_constraints(node, stonith_op, down_op, ordering_constraints); + } else if(node->details->expected_up) { + crm_warn("Node %s was expected to be up!", + node->details->uname); + crm_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); + crm_warn("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); } + ); return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependancies of un-runnable actions un-runnable * */ gboolean stage7(GListPtr resources, GListPtr actions, GListPtr ordering_constraints) { crm_devel("Processing stage 7"); slist_iter( order, order_constraint_t, 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); } ); update_action_states(actions); return TRUE; } /* * Create a dependancy graph to send to the transitioner (via the CRMd) */ gboolean stage8(GListPtr resources, GListPtr actions, crm_data_t * *graph) { crm_devel("Processing stage 8"); *graph = create_xml_node(NULL, XML_TAG_GRAPH); set_xml_property_copy( *graph, "global_timeout", transition_timeout); /* 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, resources, lpc, crm_devel("processing actions for rsc=%s", rsc->id); rsc->fns->expand(rsc, graph); ); crm_xml_devel(*graph, "created resource-driven action list"); /* catch any non-resource specific actions */ crm_devel("processing non-resource actions"); slist_iter( action, action_t, actions, lpc, graph_element_from_action(action, graph); ); crm_xml_devel(*graph, "created generic action list"); 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; crm_devel("Choosing node for color %d", color->id); nodes = g_list_sort(nodes, sort_node_weight); chosen = g_list_nth_data(nodes, 0); color->details->chosen_node = NULL; color->details->pending = FALSE; if(chosen == NULL) { crm_debug("Could not allocate a node for color %d", color->id); return FALSE; } /* 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/unpack.c b/crm/pengine/unpack.c index 4add54e2a8..4ae458cfc9 100644 --- a/crm/pengine/unpack.c +++ b/crm/pengine/unpack.c @@ -1,1160 +1,1140 @@ -/* $Id: unpack.c,v 1.68 2005/04/07 13:54:47 andrew Exp $ */ +/* $Id: unpack.c,v 1.69 2005/04/08 16:57:10 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 /* for ONLINESTATUS */ #include #include #include gboolean unpack_rsc_to_attr(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints); gboolean unpack_rsc_to_node(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints); gboolean unpack_rsc_order( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints); gboolean unpack_rsc_colocation( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints); gboolean unpack_rsc_location( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *ordering_constraints); gboolean unpack_lrm_rsc_state( node_t *node, crm_data_t * lrm_state, GListPtr rsc_list, GListPtr nodes, GListPtr *actions, GListPtr *placement_constraints); gboolean add_node_attrs(crm_data_t * attrs, node_t *node); gboolean unpack_healthy_resource(GListPtr *placement_constraints, GListPtr *actions, crm_data_t * rsc_entry, resource_t *rsc_lh, node_t *node); gboolean unpack_failed_resource(GListPtr *placement_constraints, crm_data_t * rsc_entry, resource_t *rsc_lh, node_t *node); gboolean determine_online_status(crm_data_t * node_state, node_t *this_node); gboolean unpack_lrm_agents(node_t *node, crm_data_t * agent_list); -gboolean is_node_unclean(crm_data_t * node_state); - gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); gboolean create_ordering( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, GListPtr *ordering_constraints); rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, double weight, gboolean can_run, node_t *node, GListPtr *placement_constraints); const char *get_agent_param(resource_t *rsc, const char *param); const char *get_agent_param_rsc(resource_t *rsc, const char *param); const void *get_agent_param_metadata(resource_t *rsc, const char *param); const char *get_agent_param_global(resource_t *rsc, const char *param); const char *param_value(crm_data_t * parent, const char *name); gboolean unpack_config(crm_data_t * config) { const char *value = NULL; value = param_value(config, "transition_timeout"); if(value != NULL) { int tmp = atoi(value); if(tmp > 0) { transition_timeout = value; } else { crm_warn("Invalid value for %s: %s", "transition_timeout", value); } } crm_devel("%s set to: %s", "transition_timeout", transition_timeout); value = param_value(config, "stonith_enabled"); if(value != NULL) { crm_str_to_boolean(value, &stonith_enabled); } crm_info("STONITH of failed nodes is %s", stonith_enabled?"enabled":"disabled"); value = param_value(config, "symmetric_cluster"); if(value != NULL) { crm_str_to_boolean(value, &symmetric_cluster); } if(symmetric_cluster) { crm_info("Cluster is symmetric" " - resources can run anywhere by default"); } value = param_value(config, "require_quorum"); if(value != NULL) { crm_str_to_boolean(value, &require_quorum); } if(require_quorum) { crm_info("Quorum required for fencing and resource management"); } return TRUE; } const char * param_value(crm_data_t * parent, const char *name) { crm_data_t * a_default = NULL; if(parent != NULL) { a_default = find_entity( parent, XML_CIB_TAG_NVPAIR, name, FALSE); } if(a_default == NULL) { crm_warn("Option %s not set", name); return NULL; } return crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); } const char * get_agent_param(resource_t *rsc, const char *param) { const char *value = NULL; if(param == NULL) { return NULL; } value = get_agent_param_rsc(rsc, param); if(value == NULL) { value = get_agent_param_metadata(rsc, param); } if(value == NULL) { value = get_agent_param_global(rsc, param); } return value; } const char * get_agent_param_rsc(resource_t *rsc, const char *param) { crm_data_t * xml_rsc = rsc->xml; return crm_element_value(xml_rsc, param); } const void * get_agent_param_metadata(resource_t *rsc, const char *param) { return NULL; } const char * get_agent_param_global(resource_t *rsc, const char *param) { const char * value = NULL;/*g_hashtable_lookup(agent_global_defaults, param); */ if(value == NULL) { crm_err("No global value default for %s", param); } return value; } gboolean unpack_global_defaults(crm_data_t * defaults) { return TRUE; } gboolean unpack_nodes(crm_data_t * xml_nodes, GListPtr *nodes) { node_t *new_node = NULL; crm_data_t * attrs = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; crm_verbose("Begining unpack..."); xml_child_iter( xml_nodes, xml_obj, XML_CIB_TAG_NODE, id = crm_element_value(xml_obj, XML_ATTR_ID); uname = crm_element_value(xml_obj, XML_ATTR_UNAME); type = crm_element_value(xml_obj, XML_ATTR_TYPE); crm_verbose("Processing node %s/%s", uname, id); attrs = find_xml_node(xml_obj, "attributes", FALSE); if(id == NULL) { crm_err("Must specify id tag in "); continue; } if(type == NULL) { crm_err("Must specify type tag in "); continue; } crm_malloc(new_node, sizeof(node_t)); if(new_node == NULL) { return FALSE; } new_node->weight = 1.0; new_node->fixed = FALSE; crm_malloc(new_node->details, sizeof(struct node_shared_s)); if(new_node->details == NULL) { crm_free(new_node); return FALSE; } crm_verbose("Creaing node for entry %s/%s", uname, id); new_node->details->id = id; new_node->details->uname = uname; new_node->details->type = node_ping; new_node->details->online = FALSE; new_node->details->unclean = TRUE; /* all nodes are unclean until we've seen their status entry */ new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->agents = NULL; new_node->details->attrs = g_hash_table_new( g_str_hash, g_str_equal); if(safe_str_eq(type, "member")) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node); if(crm_is_true(g_hash_table_lookup( new_node->details->attrs, "standby"))) { crm_info("Node %s is in standby-mode", new_node->details->uname); new_node->weight = -1.0; } *nodes = g_list_append(*nodes, new_node); crm_verbose("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); crm_devel_action(print_node("Added", new_node, FALSE)); ); *nodes = g_list_sort(*nodes, sort_node_weight); return TRUE; } gboolean unpack_resources(crm_data_t * xml_resources, GListPtr *resources, GListPtr *actions, GListPtr *ordering_constraints, GListPtr *placement_constraints, GListPtr all_nodes) { crm_verbose("Begining unpack..."); xml_child_iter( xml_resources, xml_obj, NULL, resource_t *new_rsc = NULL; if(common_unpack(xml_obj, &new_rsc)) { *resources = g_list_append(*resources, new_rsc); crm_devel_action( print_resource("Added", new_rsc, FALSE)); if(symmetric_cluster) { rsc_to_node_t *new_con = rsc2node_new( "symmetric_default", new_rsc, 0, TRUE, NULL, placement_constraints); new_con->node_list_rh = node_list_dup(all_nodes, FALSE); } } else { crm_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); } ); *resources = g_list_sort(*resources, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(crm_data_t * xml_constraints, GListPtr nodes, GListPtr resources, GListPtr *placement_constraints, GListPtr *ordering_constraints) { crm_verbose("Begining unpack..."); xml_child_iter( xml_constraints, xml_obj, NULL, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { crm_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_verbose("Processing constraint %s %s", crm_element_name(xml_obj),id); if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order( xml_obj, resources, ordering_constraints); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation( xml_obj, resources, ordering_constraints); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location( xml_obj, resources, nodes, placement_constraints); } else { crm_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, double weight, gboolean can, node_t *node, GListPtr *placement_constraints) { rsc_to_node_t *new_con = NULL; if(rsc == NULL || id == NULL) { crm_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); return NULL; } crm_malloc(new_con, sizeof(rsc_to_node_t)); if(new_con != NULL) { new_con->id = id; new_con->rsc_lh = rsc; new_con->node_list_rh = NULL; new_con->weight = weight; if(node != NULL) { new_con->node_list_rh = g_list_append(NULL, node); } *placement_constraints = g_list_append(*placement_constraints, new_con); } return new_con; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean unpack_status(crm_data_t * status, GListPtr nodes, GListPtr rsc_list, GListPtr *actions, GListPtr *placement_constraints) { const char *uname = NULL; crm_data_t * lrm_rsc = NULL; crm_data_t * lrm_agents = NULL; crm_data_t * attrs = NULL; node_t *this_node = NULL; crm_verbose("Begining unpack"); xml_child_iter( status, node_state, XML_CIB_TAG_STATE, /* id = crm_element_value(node_state, XML_ATTR_ID); */ uname = crm_element_value(node_state, XML_ATTR_UNAME); attrs = find_xml_node(node_state, XML_LRM_TAG_ATTRIBUTES,FALSE); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_agents = find_xml_node(lrm_rsc, XML_LRM_TAG_AGENTS, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_verbose("Processing node %s", uname); this_node = pe_find_node(nodes, uname); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { crm_warn("Node %s in status section no longer exists", uname); continue; } /* Mark the node as provisionally clean * - at least we have seen it in the current cluster's lifetime */ this_node->details->unclean = FALSE; crm_verbose("Adding runtime node attrs"); add_node_attrs(node_state, this_node); crm_verbose("determining node state"); determine_online_status(node_state, this_node); - crm_verbose("Processing lrm resource entries"); - unpack_lrm_rsc_state(this_node, lrm_rsc, rsc_list, nodes, - actions, placement_constraints); - - crm_verbose("Processing lrm agents"); - unpack_lrm_agents(this_node, lrm_agents); - + if(this_node->details->online || stonith_enabled) { + /* offline nodes run no resources + * unless stonith is enabled in which case we need to + * know + */ + crm_verbose("Processing lrm resource entries"); + unpack_lrm_rsc_state( + this_node, lrm_rsc, rsc_list, nodes, + actions, placement_constraints); + } + ); return TRUE; } gboolean determine_online_status(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); /* const char *state = crm_element_value(node_state,XML_NODE_ATTR_STATE); */ const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *shutdown = crm_element_value(node_state,XML_CIB_ATTR_SHUTDOWN); - const char *unclean = NULL;/*crm_element_value(node_state,XML_CIB_ATTR_STONITH); */ - - if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER) - && crm_is_true(ccm_state) - && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) - && safe_str_eq(crm_state, ONLINESTATUS) - && shutdown == NULL) { - if(this_node != NULL) { - this_node->details->online = TRUE; - } - crm_debug("Node %s is online", uname); - online = TRUE; - - } else if(this_node != NULL) { - /* remove node from contention */ - this_node->weight = -1; - this_node->fixed = TRUE; - crm_verbose("join_state=%s, expected=%s, shutdown=%s", - crm_str(join_state), crm_str(exp_state), - crm_str(shutdown)); - - if(unclean != NULL) { - this_node->details->unclean = TRUE; - - } else if(is_node_unclean(node_state)) { - /* report and or take remedial action */ - this_node->details->unclean = TRUE; - } - - if(shutdown != NULL) { - this_node->details->shutdown = TRUE; - - } - - if(this_node->details->unclean) { - crm_warn("Node %s is unclean", uname); - } - - if(this_node->details->shutdown) { - crm_debug("Node %s is due for shutdown", uname); - } + if(this_node == NULL) { + return online; } - return online; -} -gboolean -is_node_unclean(crm_data_t * node_state) -{ -/* const char *state = crm_element_value(node_state,XML_NODE_ATTR_STATE); */ - const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); - const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); - const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); - const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); - const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); - const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); + if(shutdown != NULL) { + this_node->details->shutdown = TRUE; + } + if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { + this_node->details->expected_up = TRUE; + } - if(safe_str_eq(exp_state, CRMD_STATE_INACTIVE)) { - crm_debug("Node %s is safely inactive", uname); - return FALSE; + if(crm_is_true(ccm_state) == FALSE + || ha_state == NULL + || safe_str_eq(ha_state, DEADSTATUS)) { + crm_debug("Node is down: ha_state=%s, ccm_state=%s", + crm_str(ha_state), crm_str(ccm_state)); - /* do an actual calculation once STONITH is available */ - } else if(safe_str_neq(exp_state, CRMD_JOINSTATE_DOWN)) { + } else if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER) + && safe_str_eq(crm_state, ONLINESTATUS)) { + online = TRUE; - if(safe_str_eq(crm_state, OFFLINESTATUS) - || (ha_state != NULL && safe_str_eq(ha_state, DEADSTATUS)) - || safe_str_eq(join_state, CRMD_JOINSTATE_DOWN) - || FALSE == crm_is_true(ccm_state)) { - crm_warn("Node %s is un-expectedly down", uname); - return TRUE; - } - crm_debug("Node %s: ha=%s, join=%s, crm=%s, ccm=%s", - uname, crm_str(ha_state), crm_str(join_state), - crm_str(crm_state), crm_str(ccm_state)); + } else if(this_node->details->expected_up == FALSE) { + crm_debug("CRMd is down: ha_state=%s, ccm_state=%s", + crm_str(ha_state), crm_str(ccm_state)); + crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", + crm_str(crm_state), crm_str(join_state), + crm_str(exp_state)); + } else { - crm_debug("Node %s was expected to be down", uname); + /* mark it unclean */ + this_node->details->unclean = TRUE; + + crm_warn("Node %s is un-expectedly down", uname); + crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", + crm_str(crm_state), crm_str(join_state), + crm_str(exp_state)); } - return FALSE; + if(online) { + crm_debug("Node %s is online", uname); + this_node->details->online = TRUE; + } else { + /* remove node from contention */ + crm_debug("Node %s is down", uname); + this_node->weight = -1; + this_node->fixed = TRUE; + } + if(this_node->details->unclean) { + crm_warn("Node %s is unclean", uname); + } + if(this_node->details->shutdown) { + crm_debug("Node %s is due for shutdown", uname); + } + + return online; } + gboolean unpack_lrm_agents(node_t *node, crm_data_t * agent_list) { /* if the agent is not listed, remove the node from * the resource's list of allowed_nodes */ lrm_agent_t *agent = NULL; const char *version = NULL; if(agent_list == NULL) { return FALSE; } xml_child_iter( agent_list, xml_agent, XML_LRM_TAG_AGENT, crm_malloc(agent, sizeof(lrm_agent_t)); if(agent == NULL) { continue; } agent->class = crm_element_value(xml_agent, XML_AGENT_ATTR_CLASS); agent->type = crm_element_value(xml_agent, XML_ATTR_TYPE); version = crm_element_value(xml_agent, XML_ATTR_VERSION); agent->version = version?version:"0.0"; crm_trace("Adding agent %s/%s v%s to node %s", agent->class, agent->type, agent->version, node->details->uname); node->details->agents = g_list_append( node->details->agents, agent); ); return TRUE; } gboolean unpack_lrm_rsc_state(node_t *node, crm_data_t * lrm_rsc, GListPtr rsc_list, GListPtr nodes, GListPtr *actions, GListPtr *placement_constraints) { const char *rsc_id = NULL; const char *node_id = NULL; const char *rsc_state = NULL; const char *op_status = NULL; const char *last_rc = NULL; const char *last_op = NULL; resource_t *rsc_lh = NULL; op_status_t action_status_i = LRM_OP_ERROR; xml_child_iter( lrm_rsc, rsc_entry, XML_LRM_TAG_RESOURCE, rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); node_id = crm_element_value(rsc_entry, XML_LRM_ATTR_TARGET); rsc_state = crm_element_value(rsc_entry, XML_LRM_ATTR_RSCSTATE); op_status = crm_element_value(rsc_entry, XML_LRM_ATTR_OPSTATUS); last_rc = crm_element_value(rsc_entry, XML_LRM_ATTR_RC); last_op = crm_element_value(rsc_entry, XML_LRM_ATTR_LASTOP); rsc_lh = pe_find_resource(rsc_list, rsc_id); crm_verbose("[%s] Processing %s on %s (%s)", crm_element_name(rsc_entry), rsc_id, node_id, rsc_state); if(rsc_lh == NULL) { crm_err("Could not find a match for resource" " %s in %s's status section", rsc_id, node_id); continue; } else if(op_status == NULL) { crm_err("Invalid resource status entry for %s in %s", rsc_id, node_id); continue; } action_status_i = atoi(op_status); if(node->details->unclean) { crm_debug("Node %s (where %s is running) is unclean." " Further action depends on the value of %s", node->details->uname, rsc_lh->id, XML_RSC_ATTR_STOPFAIL); /* map the status to an error and then handle as a * failed resource. */ action_status_i = LRM_OP_ERROR; - + } else if(action_status_i == (op_status_t)-1) { /* * TODO: this may need some more thought * Some cases: * - PE reinvoked with pending action that will succeed * - PE reinvoked with pending action that will fail * - After DC election * - After startup * * pending start - required start * pending stop - required stop * pending on unavailable node - stonith * * For now this should do */ if(safe_str_eq(last_op, "stop")) { /* map this to a timeout so it is re-issued */ action_status_i = LRM_OP_TIMEOUT; } else { /* map this to a "done" so it is not marked * as failed, then make sure it is re-issued */ action_new(rsc_lh, start_rsc, NULL, node); action_status_i = LRM_OP_DONE; } } switch(action_status_i) { case LRM_OP_DONE: unpack_healthy_resource( placement_constraints, actions, rsc_entry, rsc_lh,node); break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: unpack_failed_resource(placement_constraints, rsc_entry, rsc_lh,node); break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_warn("Dont know what to do for cancelled ops yet"); break; } ); return TRUE; } gboolean unpack_failed_resource(GListPtr *placement_constraints, crm_data_t * rsc_entry, resource_t *rsc_lh, node_t *node) { const char *last_op = crm_element_value(rsc_entry, XML_LRM_ATTR_LASTOP); crm_devel("Unpacking failed action %s on %s", last_op, rsc_lh->id); /* make sure we dont allocate the resource here again*/ rsc2node_new("dont_run__generated", rsc_lh, -INFINITY, FALSE, node, placement_constraints); if(safe_str_eq(last_op, "start")) { /* the resource is not actually running... nothing more to do*/ return TRUE; } switch(rsc_lh->stopfail_type) { case pesf_stonith: /* treat it as if it is still running * but also mark the node as unclean */ native_add_running(rsc_lh, node); node->details->running_rsc = g_list_append( node->details->running_rsc, rsc_lh); if(node->details->online) { node->details->shutdown = TRUE; } node->details->unclean = TRUE; break; case pesf_block: /* let this depend on the stop action which will fail * but make sure the transition continues... */ native_add_running(rsc_lh, node); (node->details->num_resources)++; node->details->running_rsc = g_list_append( node->details->running_rsc, rsc_lh); /* rsc_lh->stop->timeout = NULL; /\* wait forever *\/ */ break; case pesf_ignore: /* pretend nothing happened */ break; } return TRUE; } gboolean unpack_healthy_resource(GListPtr *placement_constraints, GListPtr *actions, crm_data_t * rsc_entry, resource_t *rsc_lh, node_t *node) { const char *last_op = crm_element_value(rsc_entry, XML_LRM_ATTR_LASTOP); crm_devel("Unpacking healthy action %s on %s", last_op, rsc_lh->id); if(safe_str_neq(last_op, "stop")) { /* create the link between this node and the rsc */ crm_verbose("Setting cur_node = %s for rsc = %s", node->details->uname, rsc_lh->id); native_add_running(rsc_lh, node); (node->details->num_resources)++; node->details->running_rsc = g_list_append( node->details->running_rsc, rsc_lh); } return TRUE; } gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh) { rsc_colocation_t *new_con = NULL; rsc_colocation_t *inverted_con = NULL; if(rsc_lh == NULL || rsc_rh == NULL){ /* error */ return FALSE; } crm_malloc(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; inverted_con = invert_constraint(new_con); crm_devel("Adding constraint %s (%p) to %s", new_con->id, new_con, rsc_lh->id); rsc_lh->rsc_cons = g_list_insert_sorted( rsc_lh->rsc_cons, new_con, sort_cons_strength); crm_devel("Adding constraint %s (%p) to %s", inverted_con->id, inverted_con, rsc_rh->id); rsc_rh->rsc_cons = g_list_insert_sorted( rsc_rh->rsc_cons, inverted_con, sort_cons_strength); return TRUE; } gboolean order_new(resource_t *lh_rsc, enum action_tasks lh_action_task, action_t *lh_action, resource_t *rh_rsc, enum action_tasks rh_action_task, action_t *rh_action, enum con_strength strength, GListPtr *ordering_constraints) { order_constraint_t *order = NULL; if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL) || ordering_constraints == NULL){ crm_err("Invalid inputs lh_rsc=%p, lh_a=%p," " rh_rsc=%p, rh_a=%p, l=%p", lh_rsc, lh_action, rh_rsc, rh_action, ordering_constraints); return FALSE; } crm_malloc(order, sizeof(order_constraint_t)); if(order == NULL) { return FALSE; } order->id = order_id++; order->strength = strength; order->lh_rsc = lh_rsc; order->rh_rsc = rh_rsc; order->lh_action = lh_action; order->rh_action = rh_action; order->lh_action_task = lh_action_task; order->rh_action_task = rh_action_task; *ordering_constraints = g_list_append( *ordering_constraints, order); if(lh_rsc != NULL && rh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " %s/%s before %s/%s", order->id, strength2text(order->strength), lh_rsc->id, task2text(lh_action_task), rh_rsc->id, task2text(rh_action_task)); } else if(lh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " %s/%s before action %d (%s)", order->id, strength2text(order->strength), lh_rsc->id, task2text(lh_action_task), rh_action->id, task2text(rh_action_task)); } else if(rh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " action %d (%s) before %s/%s", order->id, strength2text(order->strength), lh_action->id, task2text(lh_action_task), rh_rsc->id, task2text(rh_action_task)); } else { crm_devel("Created ordering constraint %d (%s):" " action %d (%s) before action %d (%s)", order->id, strength2text(order->strength), lh_action->id, task2text(lh_action_task), rh_action->id, task2text(rh_action_task)); } return TRUE; } gboolean unpack_rsc_colocation(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints) { enum con_strength strength_e = pecs_ignore; const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); if(rsc_lh == NULL) { crm_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_err("No resource (con=%s, rsc=%s)", id, id_rh); return FALSE; } if(safe_str_eq(type, XML_STRENGTH_VAL_MUST)) { strength_e = pecs_must; } else if(safe_str_eq(type, XML_STRENGTH_VAL_SHOULD)) { crm_err("Type %s is no longer supported", type); strength_e = pecs_must; } else if(safe_str_eq(type, XML_STRENGTH_VAL_SHOULDNOT)) { crm_err("Type %s is no longer supported", type); strength_e = pecs_must_not; } else if(safe_str_eq(type, XML_STRENGTH_VAL_MUSTNOT)) { strength_e = pecs_must_not; } else { crm_err("Unknown value for %s: %s", XML_ATTR_TYPE, type); return FALSE; } return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh); } gboolean unpack_rsc_order( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints) { gboolean symmetrical_bool = TRUE; gboolean action_is_start = TRUE; gboolean type_is_after = TRUE; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); const char *symmetrical = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL); const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); if(xml_obj == NULL) { crm_err("No constraint object to process."); return FALSE; } else if(id == NULL) { crm_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } else if(rsc_lh == NULL || rsc_rh == NULL) { crm_err("Constraint %s needs two sides lh: %p rh: %p" " (NULL indicates missing side)", id, rsc_lh, rsc_rh); return FALSE; } crm_str_to_boolean(symmetrical, &symmetrical_bool); if(safe_str_eq(type, "before")) { type_is_after = FALSE; } if(safe_str_eq(action, CRMD_RSCSTATE_STOP)) { action_is_start = FALSE; } #if 1 if((type_is_after && action_is_start) || (type_is_after == FALSE && action_is_start == FALSE)){ if(symmetrical_bool || action_is_start == FALSE) { order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL, pecs_startstop, ordering_constraints); } if(symmetrical_bool || action_is_start) { order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL, pecs_startstop, ordering_constraints); } } else { if(symmetrical_bool || action_is_start == FALSE) { order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL, pecs_startstop, ordering_constraints); } if(symmetrical_bool || action_is_start) { order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL, pecs_startstop, ordering_constraints); } } #else if(type_is_after) { order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL, pecs_startstop, ordering_constraints); order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL, pecs_startstop, ordering_constraints); } else { order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL, pecs_startstop, ordering_constraints); order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL, pecs_startstop, ordering_constraints); } #endif return TRUE; } gboolean add_node_attrs(crm_data_t *xml_obj, node_t *node) { g_hash_table_insert(node->details->attrs, crm_strdup(XML_ATTR_UNAME), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup(XML_ATTR_ID), crm_strdup(node->details->id)); if(safe_str_eq(node->details->id, dc_uuid)) { node->details->is_dc = TRUE; g_hash_table_insert(node->details->attrs, crm_strdup(XML_ATTR_DC), crm_strdup(XML_BOOLEAN_TRUE)); } else { g_hash_table_insert(node->details->attrs, crm_strdup(XML_ATTR_DC), crm_strdup(XML_BOOLEAN_FALSE)); } unpack_instance_attributes(xml_obj, node->details->attrs); return TRUE; } gboolean unpack_rsc_location( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints) { gboolean were_rules = FALSE; const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { crm_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } xml_child_iter( xml_obj, rule, XML_TAG_RULE, gboolean first_expr = TRUE; gboolean can_run = FALSE; gboolean do_and = TRUE; gboolean rule_has_expressions; const char *rule_id = crm_element_value(rule, XML_ATTR_ID); const char *score = crm_element_value(rule, XML_RULE_ATTR_SCORE); const char *boolean = crm_element_value(rule, XML_RULE_ATTR_BOOLEAN_OP); GListPtr match_L = NULL; GListPtr old_list = NULL; float score_f = 0.0; rsc_to_node_t *new_con = NULL; were_rules = TRUE; if(score == NULL) { score_f = 0.0; } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else { score_f = atof(score); } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } if(score_f >= 0.0) { can_run = TRUE; } new_con = rsc2node_new(rule_id, rsc_lh, score_f, can_run, NULL, placement_constraints); if(new_con == NULL) { continue; } crm_trace("processing rule: %s", crm_element_value(rule, XML_ATTR_ID)); rule_has_expressions = FALSE; xml_child_iter( rule, expr, XML_TAG_EXPRESSION, const char *attr = crm_element_value( expr, XML_EXPR_ATTR_ATTRIBUTE); const char *op = crm_element_value( expr, XML_EXPR_ATTR_OPERATION); const char *value = crm_element_value( expr, XML_EXPR_ATTR_VALUE); const char *type = crm_element_value( expr, XML_EXPR_ATTR_TYPE); rule_has_expressions = TRUE; crm_trace("processing expression: %s", crm_element_value(expr, XML_ATTR_ID)); match_L = apply_node_expression( attr, op, value, type, node_list); if(first_expr) { new_con->node_list_rh = node_list_dup( match_L, FALSE); first_expr = FALSE; continue; } old_list = new_con->node_list_rh; if(do_and) { crm_trace("do_and"); new_con->node_list_rh = node_list_and( old_list, match_L, FALSE); } else { crm_trace("do_or"); new_con->node_list_rh = node_list_or( old_list, match_L, FALSE); } pe_free_shallow_adv(match_L, FALSE); pe_free_shallow_adv(old_list, TRUE); ); if(rule_has_expressions == FALSE && symmetric_cluster == FALSE) { /* feels like a hack */ crm_devel("Rule %s had no expressions," " adding all nodes", crm_element_value(rule, XML_ATTR_ID)); new_con->node_list_rh = node_list_dup(node_list,FALSE); } if(new_con->node_list_rh == NULL) { crm_debug("No matching nodes for constraint/rule %s/%s", id, crm_element_value(rule, XML_ATTR_ID)); } crm_devel_action(print_rsc_to_node("Added", new_con, FALSE)); ); if(were_rules == FALSE) { crm_debug("no rules for constraint %s", id); } return TRUE; }