Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639730
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
67 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c
index 07ef3b7dec..4e52fbb93a 100644
--- a/crm/pengine/graph.c
+++ b/crm/pengine/graph.c
@@ -1,376 +1,370 @@
-/* $Id: graph.c,v 1.33 2005/04/08 17:04:12 andrew Exp $ */
+/* $Id: graph.c,v 1.34 2005/04/11 10:51:05 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
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) {
+ /* stop everything we can via shutdown_constraints() and then
+ * shoot the node... the shutdown has been superceeded
+ */
+ shutdown_op->pseudo = TRUE;
+
/* shutdown before stonith */
- /* add the shutdown OP to the before lists so it counts as a pre-req */
+ /* Give any resources a chance to shutdown normally */
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) {
+ if(stonith_op != NULL) {
+ stop_actions = find_actions(rsc->actions,stop_rsc,node);
+ slist_iter(
+ action, action_t, stop_actions, lpc2,
+ if(node->details->unclean || rsc->unclean) {
+ /* the stop would never complete and is
+ * now implied by the stonith operation
+ */
+ action->pseudo = TRUE;
+ order_new(NULL,stonith_node,stonith_op,
+ rsc, stop_rsc, NULL,
+ pecs_must, ordering_constraints);
+ } else {
+ /* stop healthy resources before the
+ * stonith op
+ */
+ order_new(rsc, stop_rsc, NULL,
+ NULL,stonith_node,stonith_op,
+ pecs_must, ordering_constraints);
+ }
+ );
+
+ crm_devel("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 */
- crm_warn("SHARED RESOURCE %s WILL REMAIN BLOCKED"
+ crm_err("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) {
+ } else if((rsc->unclean || node->details->unclean)
+ && rsc->stopfail_type == pesf_ignore) {
/* nothing to do here */
- crm_warn("SHARED RESOURCE %s IS NOT PROTECTED",
+ crm_err("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)) {
+ const char *default_value = NULL;
+ if(as_input) {
+ default_value = "__none__";
+ }
set_xml_property_copy(
action_xml, XML_LRM_ATTR_TARGET,
- safe_val4(NULL, action, node, details,uname));
+ safe_val4(default_value, action, node, details,uname));
set_xml_property_copy(
action_xml, XML_LRM_ATTR_TARGET_UUID,
- safe_val4(NULL, action, node, details, id));
+ safe_val4(default_value, 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 == FALSE) {
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 fc09bb011f..a91531077a 100644
--- a/crm/pengine/pengine.h
+++ b/crm/pengine/pengine.h
@@ -1,341 +1,342 @@
-/* $Id: pengine.h,v 1.56 2005/04/08 16:57:10 andrew Exp $ */
+/* $Id: pengine.h,v 1.57 2005/04/11 10:51:05 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <clplumbing/ipc.h>
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 <glib.h>
#include <crm/crm.h>
#include <crm/common/msg.h>
#include <complex.h>
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;
+ gboolean unclean;
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 e4a68d4d14..7a8f2081f8 100644
--- a/crm/pengine/stages.c
+++ b/crm/pengine/stages.c
@@ -1,480 +1,479 @@
-/* $Id: stages.c,v 1.50 2005/04/08 19:10:14 andrew Exp $ */
+/* $Id: stages.c,v 1.51 2005/04/11 10:51:05 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
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->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);
- }
-
- if(node->details->online == FALSE
- && node->details->expected_up) {
- crm_warn("Node %s was expected to be up!",
- node->details->uname);
+ } else if(node->details->unclean) {
+ crm_err("Node %s is unclean!", node->details->uname);
crm_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED");
crm_warn("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE");
}
+
+ if(node->details->unclean) {
+ stonith_constraints(
+ node, stonith_op, down_op, ordering_constraints);
+ }
);
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);
}
);
*/
crm_verbose("========= Action List =========");
slist_iter(action, action_t, actions, lpc,
print_action(NULL, action, FALSE));
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;
} else if(chosen->details->unclean || chosen->details->shutdown) {
crm_debug("Even highest ranked node for color %d"
" is unclean or shutting down",
color->id);
return FALSE;
} else if(chosen->weight < 0) {
crm_debug("Even highest ranked node for color %d, had weight %f",
color->id, chosen->weight);
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 6bb21d6c13..0efaebb718 100644
--- a/crm/pengine/unpack.c
+++ b/crm/pengine/unpack.c
@@ -1,1143 +1,1199 @@
-/* $Id: unpack.c,v 1.71 2005/04/08 19:10:14 andrew Exp $ */
+/* $Id: unpack.c,v 1.72 2005/04/11 10:51:05 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <lrm/lrm_api.h>
#include <glib.h>
#include <heartbeat.h> /* for ONLINESTATUS */
#include <pengine.h>
#include <pe_utils.h>
#include <pe_rules.h>
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 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 <node>");
continue;
}
if(type == NULL) {
crm_err("Must specify type tag in <node>");
continue;
}
crm_malloc(new_node, sizeof(node_t));
if(new_node == NULL) {
return FALSE;
}
new_node->weight = 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(stonith_enabled) {
+ /* all nodes are unclean until we've seen their
+ * status entry
+ */
+ new_node->details->unclean = TRUE;
+ } else {
+ /* blind faith... */
+ new_node->details->unclean = FALSE;
+ }
+
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;
+ new_node->weight = -INFINITY;
}
*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);
if(this_node->details->online || stonith_enabled) {
- /* offline nodes run no resources
+ /* offline nodes run no resources...
* unless stonith is enabled in which case we need to
- * know
+ * make sure rsc start events happen after the stonith
*/
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 *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);
if(this_node == NULL) {
return online;
}
if(shutdown != NULL) {
this_node->details->shutdown = TRUE;
}
if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
this_node->details->expected_up = TRUE;
}
- 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));
-
- } else if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)
- && safe_str_eq(crm_state, ONLINESTATUS)) {
- online = TRUE;
-
- } 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));
-
+ if(stonith_enabled == FALSE) {
+ if(!crm_is_true(ccm_state) || 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));
+
+ } else if(!crm_is_true(ccm_state)
+ || safe_str_eq(ha_state, DEADSTATUS)) {
+
+ } else if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)
+ && safe_str_eq(crm_state, ONLINESTATUS)) {
+ online = TRUE;
+
+ } 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 {
+ /* mark it unclean */
+ this_node->details->unclean = TRUE;
+
+ crm_err("Node %s is partially & 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));
+ }
} else {
- /* 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));
+ if(crm_is_true(ccm_state)
+ && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS))
+ && safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
+ online = TRUE;
+
+ } else if(this_node->details->expected_up == FALSE) {
+ crm_debug("CRMd on %s is down: ha_state=%s, ccm_state=%s",
+ uname, 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 {
+ /* mark it unclean */
+ this_node->details->unclean = TRUE;
+
+ crm_err("Node %s is un-expectedly down", uname);
+ crm_debug("\tha_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));
+ }
}
-
+
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->weight = -INFINITY;
this_node->fixed = TRUE;
}
+
if(this_node->details->unclean) {
crm_warn("Node %s is unclean", uname);
}
+
if(this_node->details->shutdown) {
/* dont run resources here */
- this_node->weight = -1;
+ this_node->weight = -INFINITY;
this_node->fixed = TRUE;
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",
+ crm_trace("Adding agent %s/%s %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 <any> 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);
+ CRM_DEV_ASSERT(node != NULL);
+ if(crm_assert_failed) {
+ return FALSE;
+ }
/* 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;
- }
+ } else if(stonith_enabled == FALSE
+ && rsc_lh->stopfail_type == pesf_stonith) {
+ crm_err("Cannot fence node %s after %s on %s"
+ " as STONITH is disabled",
+ node->details->uname, last_op, rsc_lh->id);
+ return FALSE;
+ }
+
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;
- }
+
+ rsc_lh->unclean = 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 *\/ */
+ rsc_lh->unclean = TRUE;
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;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 10, 3:21 AM (12 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009913
Default Alt Text
(67 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment