Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639306
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
86 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/pengine/native.c b/crm/pengine/native.c
index 75e2ecbd75..3c787d2077 100644
--- a/crm/pengine/native.c
+++ b/crm/pengine/native.c
@@ -1,1140 +1,1144 @@
-/* $Id: native.c,v 1.24 2005/04/11 10:42:51 andrew Exp $ */
+/* $Id: native.c,v 1.25 2005/04/11 15:34:12 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 <pengine.h>
#include <pe_utils.h>
#include <crm/msg_xml.h>
extern color_t *add_color(resource_t *rh_resource, color_t *color);
gboolean native_choose_color(resource_t *lh_resource);
void native_assign_color(resource_t *rsc, color_t *color);
void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons,
const char *id, GListPtr nodes);
void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void filter_nodes(resource_t *rsc);
int num_allowed_nodes4color(color_t *color);
void create_monitor_actions(resource_t *rsc, action_t *start, node_t *node,
GListPtr *ordering_constraints);
typedef struct native_variant_data_s
{
lrm_agent_t *agent;
GListPtr running_on; /* node_t* */
color_t *color;
GListPtr node_cons; /* rsc_to_node_t* */
GListPtr allowed_nodes; /* node_t* */
} native_variant_data_t;
#define get_native_variant_data(data, rsc) \
CRM_ASSERT(rsc->variant == pe_native); \
CRM_ASSERT(rsc->variant_opaque != NULL); \
data = (native_variant_data_t *)rsc->variant_opaque;
void
native_add_running(resource_t *rsc, node_t *node)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
native_data->running_on = g_list_append(native_data->running_on, node);
if(g_list_length(native_data->running_on) > 1) {
crm_warn("Resource %s is (potentially) active on %d nodes."
" Latest: %s", rsc->id,
g_list_length(native_data->running_on),
node->details->id);
}
}
void native_unpack(resource_t *rsc)
{
crm_data_t * xml_obj = rsc->xml;
native_variant_data_t *native_data = NULL;
const char *version = crm_element_value(xml_obj, XML_ATTR_VERSION);
crm_verbose("Processing resource %s...", rsc->id);
crm_malloc(native_data, sizeof(native_variant_data_t));
crm_malloc(native_data->agent, sizeof(lrm_agent_t));
native_data->agent->class = crm_element_value(xml_obj, "class");
native_data->agent->type = crm_element_value(xml_obj, "type");
native_data->agent->version = version?version:"0.0";
native_data->color = NULL;
native_data->allowed_nodes = NULL;
native_data->node_cons = NULL;
native_data->running_on = NULL;
rsc->variant_opaque = native_data;
}
resource_t *
native_find_child(resource_t *rsc, const char *id)
{
return NULL;
}
int native_num_allowed_nodes(resource_t *rsc)
{
int num_nodes = 0;
native_variant_data_t *native_data = NULL;
if(rsc->variant == pe_native) {
native_data = (native_variant_data_t *)rsc->variant_opaque;
} else {
crm_err("Resource %s was not a \"native\" variant",
rsc->id);
return 0;
}
if(native_data->color) {
return num_allowed_nodes4color(native_data->color);
} else if(rsc->candidate_colors) {
/* TODO: sort colors first */
color_t *color = g_list_nth_data(rsc->candidate_colors, 0);
return num_allowed_nodes4color(color);
} else {
slist_iter(
this_node, node_t, native_data->allowed_nodes, lpc,
if(this_node->weight < 0) {
continue;
}
num_nodes++;
);
}
return num_nodes;
}
int num_allowed_nodes4color(color_t *color)
{
int num_nodes = 0;
if(color->details->pending == FALSE) {
if(color->details->chosen_node) {
return 1;
}
return 0;
}
slist_iter(
this_node, node_t, color->details->candidate_nodes, lpc,
if(this_node->weight < 0) {
continue;
}
num_nodes++;
);
return num_nodes;
}
void native_color(resource_t *rsc, GListPtr *colors)
{
color_t *new_color = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
if( native_choose_color(rsc) ) {
crm_verbose("Colored resource %s with color %d",
rsc->id, native_data->color->id);
} else {
if(native_data->allowed_nodes != NULL) {
/* filter out nodes with a negative weight */
filter_nodes(rsc);
new_color = create_color(
colors, rsc, native_data->allowed_nodes);
native_assign_color(rsc, new_color);
}
if(new_color == NULL) {
crm_warn("Resource %s cannot run anywhere", rsc->id);
print_resource("ERROR: No color", rsc, FALSE);
native_assign_color(rsc, no_color);
}
}
rsc->provisional = FALSE;
}
void
create_monitor_actions(resource_t *rsc, action_t *start, node_t *node,
GListPtr *ordering_constraints)
{
action_t *mon = NULL;
xml_child_iter(
rsc->ops_xml, operation, "op",
if(safe_str_neq(
crm_element_value(operation, "name"), CRMD_RSCSTATE_MON)) {
continue;
}
mon = action_new(rsc, monitor_rsc,
crm_element_value(operation, "timeout"), node);
add_hash_param(mon->extra, "interval",
crm_element_value(operation, "interval"));
unpack_instance_attributes(operation, mon->extra);
order_new(NULL, start_rsc, start, NULL, monitor_rsc, mon,
pecs_must, ordering_constraints);
);
}
void native_create_actions(resource_t *rsc, GListPtr *ordering_constraints)
{
action_t *op = NULL;
node_t *chosen = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
if(native_data->color != NULL) {
chosen = native_data->color->details->chosen_node;
}
if(chosen != NULL && g_list_length(native_data->running_on) == 0) {
/* create start action */
op = action_new(rsc, start_rsc, NULL, chosen);
- if(have_quorum == FALSE && require_quorum == TRUE) {
+ if( !have_quorum && no_quorum_policy != no_quorum_ignore) {
op->runnable = FALSE;
+
} else {
crm_info("Start resource %s (%s)",
rsc->id, safe_val3(
NULL, chosen, details, uname));
}
} else if(g_list_length(native_data->running_on) > 1) {
crm_info("Attempting recovery of resource %s",
rsc->id);
if(rsc->recovery_type == recovery_stop_start
|| rsc->recovery_type == recovery_stop_only) {
slist_iter(
node, node_t,
native_data->running_on, lpc,
crm_info("Stop resource %s (%s) (recovery)",
rsc->id,
safe_val3(NULL, node, details, uname));
action_new(rsc, stop_rsc, NULL, node);
);
}
if(rsc->recovery_type == recovery_stop_start && chosen) {
+ /* if one of the "stops" is for a node outside
+ * our partition, then this will block anyway
+ */
crm_info("Start resource %s (%s) (recovery)",
rsc->id,
safe_val3(NULL, chosen, details, uname));
op = action_new(rsc, start_rsc, NULL, chosen);
}
- } else {
+ } else if(g_list_length(native_data->running_on) == 1) {
node_t *node = native_data->running_on->data;
crm_debug("Stop%s of %s",
chosen != NULL?" and restart":"",rsc->id);
CRM_DEV_ASSERT(node != NULL);
if(chosen != NULL && safe_str_eq(
node->details->id, chosen->details->id)) {
/* restart */
crm_info("Leave resource %s on (%s)",rsc->id,
safe_val3(NULL,chosen,details,uname));
/* in case the actions already exist */
slist_iter(
action, action_t, rsc->actions, lpc2,
if(action->task == start_rsc
|| action->task == stop_rsc){
action->optional = TRUE;
}
);
} else if(chosen != NULL) {
/* move */
crm_info("Move resource %s (%s -> %s)", rsc->id,
safe_val3(NULL, node, details, uname),
safe_val3(NULL, chosen, details, uname));
action_new(rsc, stop_rsc, NULL, node);
op = action_new(rsc, start_rsc, NULL, chosen);
} else {
crm_info("Stop resource %s (%s)", rsc->id,
safe_val3(NULL, node, details, uname));
action_new(rsc, stop_rsc, NULL, node);
}
}
if(op != NULL && op->runnable) {
create_monitor_actions(
rsc, op, chosen, ordering_constraints);
}
}
void native_internal_constraints(resource_t *rsc, GListPtr *ordering_constraints)
{
order_new(rsc, stop_rsc, NULL, rsc, start_rsc, NULL,
pecs_startstop, ordering_constraints);
}
void native_rsc_colocation_lh(rsc_colocation_t *constraint)
{
resource_t *rsc = constraint->rsc_lh;
if(rsc == NULL) {
crm_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if(constraint->rsc_rh == NULL) {
crm_err("rsc_rh was NULL for %s", constraint->id);
return;
} else {
crm_devel("Processing constraints from %s", rsc->id);
}
constraint->rsc_rh->fns->rsc_colocation_rh(rsc, constraint);
}
void native_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint)
{
gboolean do_check = FALSE;
gboolean update_lh = FALSE;
gboolean update_rh = FALSE;
resource_t *rsc_lh = rsc;
resource_t *rsc_rh = constraint->rsc_rh;
native_variant_data_t *native_data_lh = NULL;
native_variant_data_t *native_data_rh = NULL;
get_native_variant_data(native_data_lh, rsc_lh);
get_native_variant_data(native_data_rh, rsc_rh);
crm_verbose("Processing RH of constraint %s", constraint->id);
crm_devel_action(print_resource("LHS", rsc_lh, TRUE));
crm_devel_action(print_resource("RHS", rsc_rh, TRUE));
if(constraint->strength == pecs_ignore
|| constraint->strength == pecs_startstop){
crm_devel("Skipping constraint type %d", constraint->strength);
return;
}
if(rsc_lh->provisional && rsc_rh->provisional) {
if(constraint->strength == pecs_must) {
/* update effective_priorities */
native_rsc_colocation_rh_must(
rsc_lh, update_lh, rsc_rh, update_rh);
} else {
/* nothing */
crm_devel(
"Skipping constraint, both sides provisional");
}
return;
} else if( (!rsc_lh->provisional) && (!rsc_rh->provisional)
&& (!native_data_lh->color->details->pending)
&& (!native_data_rh->color->details->pending) ) {
/* error check */
do_check = TRUE;
if(rsc_lh->effective_priority < rsc_rh->effective_priority) {
update_lh = TRUE;
} else if(rsc_lh->effective_priority
> rsc_rh->effective_priority) {
update_rh = TRUE;
} else {
update_lh = TRUE;
update_rh = TRUE;
}
} else if(rsc_lh->provisional == FALSE
&& native_data_lh->color->details->pending == FALSE) {
/* update _them_ : postproc color version */
update_rh = TRUE;
} else if(rsc_rh->provisional == FALSE
&& native_data_rh->color->details->pending == FALSE) {
/* update _us_ : postproc color alt version */
update_lh = TRUE;
} else if(rsc_lh->provisional == FALSE) {
/* update _them_ : preproc version */
update_rh = TRUE;
} else if(rsc_rh->provisional == FALSE) {
/* update _us_ : postproc version */
update_lh = TRUE;
} else {
crm_warn("Un-expected combination of inputs");
return;
}
if(update_lh) {
crm_devel("Updating LHS");
}
if(update_rh) {
crm_devel("Updating RHS");
}
if(do_check) {
if(native_constraint_violated(
rsc_lh, rsc_rh, constraint) == FALSE) {
crm_devel("Constraint satisfied");
return;
}
/* else constraint cant be satisified */
crm_warn("Constraint %s could not be satisfied",
constraint->id);
if(update_lh) {
crm_warn("Marking resource %s unrunnable as a result",
rsc_lh->id);
rsc_lh->runnable = FALSE;
}
if(update_rh) {
crm_warn("Marking resource %s unrunnable as a result",
rsc_rh->id);
rsc_rh->runnable = FALSE;
}
}
if(constraint->strength == pecs_must) {
native_rsc_colocation_rh_must(
rsc_lh, update_lh, rsc_rh, update_rh);
return;
} else if(constraint->strength != pecs_must_not) {
/* unknown type */
crm_err("Unknown constraint type %d", constraint->strength);
return;
}
native_rsc_colocation_rh_mustnot(rsc_lh, update_lh,rsc_rh, update_rh);
}
void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order)
{
GListPtr lh_actions = NULL;
action_t *lh_action = order->lh_action;
crm_verbose("Processing LH of ordering constraint %d", order->id);
switch(order->lh_action_task) {
case start_rsc:
case started_rsc:
case stop_rsc:
case stopped_rsc:
break;
default:
crm_err("Task \"%s\" from ordering %d isnt a resource action",
task2text(order->lh_action_task), order->id);
return;
}
if(lh_action != NULL) {
lh_actions = g_list_append(NULL, lh_action);
} else if(lh_action == NULL && lh_rsc != NULL) {
if(order->strength == pecs_must) {
crm_devel("No LH-Side (%s/%s) found for constraint..."
" creating",
lh_rsc->id, task2text(order->lh_action_task));
action_new(lh_rsc, order->lh_action_task, NULL, NULL);
}
lh_actions = find_actions(
lh_rsc->actions, order->lh_action_task, NULL);
if(lh_actions == NULL) {
crm_devel("No LH-Side (%s/%s) found for constraint",
lh_rsc->id, task2text(order->lh_action_task));
crm_devel("RH-Side was: (%s/%s)",
order->rh_rsc?order->rh_rsc->id:order->rh_action?order->rh_action->rsc->id:"<NULL>",
task2text(order->rh_action_task));
return;
}
} else {
crm_warn("No LH-Side (%s) specified for constraint",
task2text(order->lh_action_task));
crm_devel("RH-Side was: (%s/%s)",
order->rh_rsc?order->rh_rsc->id:order->rh_action?order->rh_action->rsc->id:"<NULL>",
task2text(order->rh_action_task));
return;
}
slist_iter(
lh_action_iter, action_t, lh_actions, lpc,
resource_t *rh_rsc = order->rh_rsc;
if(rh_rsc == NULL && order->rh_action) {
rh_rsc = order->rh_action->rsc;
}
if(rh_rsc) {
rh_rsc->fns->rsc_order_rh(
lh_action_iter, rh_rsc, order);
} else if(order->rh_action) {
order_actions(lh_action_iter, order->rh_action, order);
}
);
pe_free_shallow_adv(lh_actions, FALSE);
}
void native_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order)
{
GListPtr rh_actions = NULL;
action_t *rh_action = order->rh_action;
crm_verbose("Processing RH of ordering constraint %d", order->id);
switch(order->rh_action_task) {
case start_rsc:
case started_rsc:
case stop_rsc:
case stopped_rsc:
case monitor_rsc:
break;
default:
crm_err("Task \"%s\" from ordering %d isnt a resource action",
task2text(order->rh_action_task), order->id);
return;
}
if(rh_action != NULL) {
rh_actions = g_list_append(NULL, rh_action);
} else if(rh_action == NULL && rsc != NULL) {
rh_actions = find_actions(
rsc->actions, order->rh_action_task, NULL);
if(rh_actions == NULL) {
crm_devel("No RH-Side (%s/%s) found for constraint..."
" ignoring",
rsc->id, task2text(order->rh_action_task));
crm_devel("LH-Side was: (%s/%s)",
order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
task2text(order->lh_action_task));
return;
}
} else if(rh_action == NULL) {
crm_devel("No RH-Side (%s) specified for constraint..."
" ignoring", task2text(order->rh_action_task));
crm_devel("LH-Side was: (%s/%s)",
order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
task2text(order->lh_action_task));
return;
}
slist_iter(
rh_action_iter, action_t, rh_actions, lpc,
order_actions(lh_action, rh_action_iter, order);
);
pe_free_shallow_adv(rh_actions, FALSE);
}
void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
{
GListPtr or_list;
native_variant_data_t *native_data = NULL;
crm_devel_action(print_rsc_to_node("Applying", constraint, FALSE));
/* take "lifetime" into account */
if(constraint == NULL) {
crm_err("Constraint is NULL");
return;
} else if(is_active(constraint) == FALSE) {
crm_debug("Constraint (%s) is not active", constraint->id);
return;
} else if(rsc == NULL) {
crm_err("LHS of rsc_to_node (%s) is NULL", constraint->id);
return;
}
get_native_variant_data(native_data, rsc);
native_data->node_cons =
g_list_append(native_data->node_cons, constraint);
if(constraint->node_list_rh == NULL) {
crm_debug("RHS of constraint %s is NULL", constraint->id);
return;
}
crm_devel_action(print_resource("before update", rsc,TRUE));
or_list = node_list_or(
native_data->allowed_nodes, constraint->node_list_rh, FALSE);
pe_free_shallow(native_data->allowed_nodes);
native_data->allowed_nodes = or_list;
slist_iter(node_rh, node_t, constraint->node_list_rh, lpc,
native_update_node_weight(
rsc, constraint, node_rh->details->uname,
native_data->allowed_nodes));
crm_devel_action(print_resource("after update", rsc, TRUE));
}
void native_expand(resource_t *rsc, crm_data_t * *graph)
{
slist_iter(
action, action_t, rsc->actions, lpc,
crm_devel("processing action %d for rsc=%s",
action->id, rsc->id);
graph_element_from_action(action, graph);
);
}
void native_dump(resource_t *rsc, const char *pre_text, gboolean details)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
common_dump(rsc, pre_text, details);
crm_devel("\t%d candidate colors, %d allowed nodes,"
" %d rsc_cons and %d node_cons",
g_list_length(rsc->candidate_colors),
g_list_length(native_data->allowed_nodes),
g_list_length(rsc->rsc_cons),
g_list_length(native_data->node_cons));
if(details) {
crm_devel("\t=== Actions");
slist_iter(
action, action_t, rsc->actions, lpc,
print_action("\trsc action: ", action, FALSE);
);
crm_devel("\t=== Colors");
slist_iter(
color, color_t, rsc->candidate_colors, lpc,
print_color("\t", color, FALSE)
);
crm_devel("\t=== Allowed Nodes");
slist_iter(
node, node_t, native_data->allowed_nodes, lpc,
print_node("\t", node, FALSE);
);
}
}
void native_free(resource_t *rsc)
{
native_variant_data_t *native_data =
(native_variant_data_t *)rsc->variant_opaque;
crm_devel("Freeing Allowed Nodes");
pe_free_shallow(native_data->allowed_nodes);
common_free(rsc);
}
void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh)
{
native_variant_data_t *native_data_lh = NULL;
native_variant_data_t *native_data_rh = NULL;
gboolean do_merge = FALSE;
GListPtr old_list = NULL;
GListPtr merged_node_list = NULL;
float max_pri = rsc_lh->effective_priority;
if(max_pri < rsc_rh->effective_priority) {
max_pri = rsc_rh->effective_priority;
}
rsc_lh->effective_priority = max_pri;
rsc_rh->effective_priority = max_pri;
get_native_variant_data(native_data_lh, rsc_lh);
get_native_variant_data(native_data_rh, rsc_rh);
if(native_data_lh->color && native_data_rh->color) {
do_merge = TRUE;
merged_node_list = node_list_and(
native_data_lh->color->details->candidate_nodes,
native_data_rh->color->details->candidate_nodes, TRUE);
} else if(native_data_lh->color) {
do_merge = TRUE;
merged_node_list = node_list_and(
native_data_lh->color->details->candidate_nodes,
native_data_rh->allowed_nodes, TRUE);
} else if(native_data_rh->color) {
do_merge = TRUE;
merged_node_list = node_list_and(
native_data_lh->allowed_nodes,
native_data_rh->color->details->candidate_nodes, TRUE);
}
if(update_lh) {
crm_free(native_data_lh->color);
rsc_lh->runnable = rsc_rh->runnable;
rsc_lh->provisional = rsc_rh->provisional;
native_data_lh->color = copy_color(native_data_rh->color);
}
if(update_rh) {
crm_free(native_data_rh->color);
rsc_rh->runnable = rsc_lh->runnable;
rsc_rh->provisional = rsc_lh->provisional;
native_data_rh->color = copy_color(native_data_lh->color);
}
if((update_rh || update_lh) && do_merge) {
crm_devel("Merging candidate nodes");
old_list = native_data_rh->color->details->candidate_nodes;
native_data_rh->color->details->candidate_nodes = merged_node_list;
pe_free_shallow(old_list);
}
crm_devel("Finished processing pecs_must constraint");
}
void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh)
{
color_t *color_lh = NULL;
color_t *color_rh = NULL;
native_variant_data_t *native_data_lh = NULL;
native_variant_data_t *native_data_rh = NULL;
get_native_variant_data(native_data_lh, rsc_lh);
get_native_variant_data(native_data_rh, rsc_rh);
crm_devel("Processing pecs_must_not constraint");
/* pecs_must_not */
if(update_lh) {
color_rh = native_data_rh->color;
if(rsc_lh->provisional) {
color_lh = find_color(
rsc_lh->candidate_colors, color_rh);
rsc_lh->candidate_colors = g_list_remove(
rsc_lh->candidate_colors, color_lh);
crm_devel_action(
print_color("Removed LH", color_lh, FALSE));
crm_devel_action(
print_resource("Modified LH", rsc_lh, TRUE));
crm_free(color_lh);
} else if(native_data_lh->color
&& native_data_lh->color->details->pending) {
node_t *node_lh = NULL;
color_lh = native_data_lh->color;
node_lh = pe_find_node(
color_lh->details->candidate_nodes,
safe_val5(NULL, color_rh, details,
chosen_node, details, uname));
color_lh->details->candidate_nodes =
g_list_remove(
color_lh->details->candidate_nodes,
node_lh);
crm_devel_action(
print_node("Removed LH", node_lh, FALSE));
crm_devel_action(
print_color("Modified LH", color_lh, FALSE));
crm_free(node_lh);
} else {
/* error, rsc marked as unrunnable above */
crm_warn("lh else");
}
}
if(update_rh) {
color_lh = native_data_lh->color;
if(rsc_rh->provisional) {
color_rh = find_color(
rsc_rh->candidate_colors, color_lh);
rsc_rh->candidate_colors = g_list_remove(
rsc_rh->candidate_colors, color_rh);
crm_devel_action(
print_color("Removed RH", color_rh, FALSE));
crm_devel_action(
print_resource("Modified RH", rsc_rh, TRUE));
crm_free(color_rh);
} else if(native_data_rh->color
&& native_data_rh->color->details->pending) {
node_t *node_rh = NULL;
color_rh = native_data_rh->color;
node_rh = pe_find_node(
color_rh->details->candidate_nodes,
safe_val5(NULL, color_lh, details,
chosen_node, details, uname));
color_rh->details->candidate_nodes =
g_list_remove(
color_rh->details->candidate_nodes,
node_rh);
crm_devel_action(
print_node("Removed RH", node_rh, FALSE));
crm_devel_action(
print_color("Modified RH", color_rh, FALSE));
crm_free(node_rh);
} else {
/* error, rsc marked as unrunnable above */
crm_warn("rh else");
}
}
}
void
native_agent_constraints(resource_t *rsc)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
crm_trace("Applying RA restrictions to %s", rsc->id);
common_agent_constraints(
native_data->allowed_nodes, native_data->agent, rsc->id);
}
gboolean
native_choose_color(resource_t *rsc)
{
GListPtr sorted_colors = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
if(rsc->runnable == FALSE) {
native_assign_color(rsc, no_color);
}
if(rsc->provisional == FALSE) {
return !rsc->provisional;
}
sorted_colors = g_list_sort(
rsc->candidate_colors, sort_color_weight);
rsc->candidate_colors = sorted_colors;
crm_verbose("Choose a color from %d possibilities",
g_list_length(sorted_colors));
slist_iter(
this_color, color_t, rsc->candidate_colors, lpc,
GListPtr intersection = NULL;
GListPtr minus = NULL;
int len = 0;
if(this_color == NULL) {
crm_err("color was NULL");
continue;
} else if(rsc->effective_priority
< this_color->details->highest_priority) {
minus = node_list_minus(
this_color->details->candidate_nodes,
native_data->allowed_nodes, TRUE);
len = g_list_length(minus);
pe_free_shallow(minus);
if(len > 0) {
native_assign_color(rsc, this_color);
break;
}
} else {
intersection = node_list_and(
this_color->details->candidate_nodes,
native_data->allowed_nodes, TRUE);
len = g_list_length(intersection);
pe_free_shallow(intersection);
if(len != 0) {
native_assign_color(rsc, this_color);
break;
}
}
);
return !rsc->provisional;
}
void
native_assign_color(resource_t *rsc, color_t *color)
{
color_t *local_color = add_color(rsc, color);
GListPtr intersection = NULL;
GListPtr old_list = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
native_data->color = local_color;
rsc->provisional = FALSE;
if(local_color != NULL) {
(local_color->details->num_resources)++;
local_color->details->allocated_resources =
g_list_append(
local_color->details->allocated_resources,rsc);
intersection = node_list_and(
local_color->details->candidate_nodes,
native_data->allowed_nodes, TRUE);
old_list = local_color->details->candidate_nodes;
pe_free_shallow(old_list);
local_color->details->candidate_nodes = intersection;
crm_verbose("Colored resource %s with new color %d",
rsc->id, native_data->color->id);
crm_devel_action(
print_resource("Colored Resource", rsc, TRUE));
} else {
crm_err("local color was NULL");
}
return;
}
void
native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons,
const char *id, GListPtr nodes)
{
node_t *node_rh = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
node_rh = pe_find_node(native_data->allowed_nodes, id);
if(node_rh == NULL) {
crm_err("Node not found - cant update");
return;
}
if(node_rh->weight >= INFINITY && cons->weight == -INFINITY) {
crm_err("Constraint %s mixes +/- INFINITY", cons->id);
} else if(node_rh->weight <= -INFINITY && cons->weight == INFINITY) {
crm_err("Constraint %s mixes +/- INFINITY", cons->id);
}
if(node_rh->fixed) {
/* warning */
crm_debug("Constraint %s is irrelevant as the"
" weight of node %s is fixed as %f.",
cons->id,
node_rh->details->uname,
node_rh->weight);
return;
}
if(cons->weight != INFINITY && cons->weight != -INFINITY) {
crm_verbose("Constraint %s (%f): node %s weight %f.",
cons->id,
cons->weight,
node_rh->details->uname,
node_rh->weight);
} else if(cons->weight == -INFINITY) {
crm_verbose("Constraint %s (-INFINITY): node %s weight %f.",
cons->id,
node_rh->details->uname,
node_rh->weight);
} else {
crm_verbose("Constraint %s (+INFINITY): node %s weight %f.",
cons->id,
node_rh->details->uname,
node_rh->weight);
}
node_rh->weight = merge_weights(node_rh->weight, cons->weight);
if(node_rh->weight < 0) {
node_rh->fixed = TRUE;
}
crm_devel_action(print_node("Updated", node_rh, FALSE));
return;
}
gboolean
native_constraint_violated(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
native_variant_data_t *native_data_lh = NULL;
native_variant_data_t *native_data_rh = NULL;
GListPtr result = NULL;
color_t *color_lh = NULL;
color_t *color_rh = NULL;
GListPtr candidate_nodes_lh = NULL;
GListPtr candidate_nodes_rh = NULL;
gboolean matched = FALSE;
get_native_variant_data(native_data_lh, rsc_lh);
get_native_variant_data(native_data_rh, rsc_rh);
color_lh = native_data_lh->color;
color_rh = native_data_rh->color;
if(constraint->strength == pecs_must_not) {
matched = TRUE;
}
if(rsc_lh->provisional || rsc_rh->provisional) {
return FALSE;
}
if(color_lh->details->pending
&& color_rh->details->pending) {
candidate_nodes_lh = color_lh->details->candidate_nodes;
candidate_nodes_rh = color_rh->details->candidate_nodes;
} else if(color_lh->details->pending == FALSE
&& color_rh->details->pending == FALSE) {
if(color_lh == NULL && color_rh == NULL) {
return matched;
} else if(color_lh == NULL || color_rh == NULL) {
return !matched;
} else if(color_lh->details->chosen_node == NULL
&& color_rh->details->chosen_node == NULL) {
return matched;
} else if(color_lh->details->chosen_node == NULL
|| color_rh->details->chosen_node == NULL) {
return !matched;
} else if(safe_str_eq(
color_lh->details->chosen_node->details->id,
color_rh->details->chosen_node->details->id)) {
return matched;
}
return !matched;
} else if(color_lh->details->pending) {
candidate_nodes_lh = color_lh->details->candidate_nodes;
candidate_nodes_rh = g_list_append(
NULL, color_rh->details->chosen_node);
} else if(color_rh->details->pending) {
candidate_nodes_rh = color_rh->details->candidate_nodes;
candidate_nodes_lh = g_list_append(
NULL, color_lh->details->chosen_node);
}
result = node_list_and(candidate_nodes_lh, candidate_nodes_rh, TRUE);
if(g_list_length(result) == 0 && constraint->strength == pecs_must) {
/* free result */
return TRUE;
}
return FALSE;
}
/*
* Remove any nodes with a -ve weight
*/
void
filter_nodes(resource_t *rsc)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
crm_devel_action(print_resource("Filtering nodes for", rsc, FALSE));
slist_iter(
node, node_t, native_data->allowed_nodes, lpc,
if(node == NULL) {
crm_err("Invalid NULL node");
} else if(node->weight < 0.0
|| node->details->online == FALSE
|| node->details->type == node_ping) {
crm_devel_action(print_node("Removing", node, FALSE));
native_data->allowed_nodes =
g_list_remove(native_data->allowed_nodes, node);
crm_free(node);
lpc = -1; /* restart the loop */
}
);
}
diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h
index a91531077a..26dce97507 100644
--- a/crm/pengine/pengine.h
+++ b/crm/pengine/pengine.h
@@ -1,342 +1,348 @@
-/* $Id: pengine.h,v 1.57 2005/04/11 10:51:05 andrew Exp $ */
+/* $Id: pengine.h,v 1.58 2005/04/11 15:34:12 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>
+typedef enum no_quorum_policy_e {
+ no_quorum_freeze,
+ no_quorum_stop,
+ no_quorum_ignore
+} no_quorum_policy_t;
+
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 no_quorum_policy_t no_quorum_policy;
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 7a8f2081f8..156dfef50f 100644
--- a/crm/pengine/stages.c
+++ b/crm/pengine/stages.c
@@ -1,479 +1,483 @@
-/* $Id: stages.c,v 1.51 2005/04/11 10:51:05 andrew Exp $ */
+/* $Id: stages.c,v 1.52 2005/04/11 15:34:12 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;
+no_quorum_policy_t no_quorum_policy = no_quorum_freeze;
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;
+ have_quorum = TRUE;
stonith_enabled = FALSE;
+
+ crm_free(dc_uuid); dc_uuid = NULL;
+
+ if(cib == NULL) {
+ return FALSE;
+ }
+
+ 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);
+ }
unpack_config(config);
- if(require_quorum) {
- const char *value = crm_element_value(cib, XML_ATTR_HAVE_QUORUM);
+ if(no_quorum_policy != no_quorum_ignore) {
+ 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);
} 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 0efaebb718..b9c2b0a8e7 100644
--- a/crm/pengine/unpack.c
+++ b/crm/pengine/unpack.c
@@ -1,1199 +1,1220 @@
-/* $Id: unpack.c,v 1.72 2005/04/11 10:51:05 andrew Exp $ */
+/* $Id: unpack.c,v 1.73 2005/04/11 15:34:12 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);
+ value = param_value(config, "no_quorum_policy");
+ if(safe_str_eq(value, "ignore")) {
+ no_quorum_policy = no_quorum_ignore;
+
+ } else if(safe_str_eq(value, "stop")) {
+ no_quorum_policy = no_quorum_stop;
+
+ } else {
+ no_quorum_policy = no_quorum_freeze;
}
- if(require_quorum) {
- crm_info("Quorum required for fencing and resource management");
+
+ switch (no_quorum_policy) {
+ case no_quorum_freeze:
+ crm_info("On loss of CCM Quorum: Freeze resources");
+ break;
+ case no_quorum_stop:
+ crm_info("On loss of CCM Quorum: Stop ALL resources");
+ break;
+ case no_quorum_ignore:
+ crm_warn("On loss of CCM Quorum: Ignore");
+ break;
}
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->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(have_quorum == FALSE && no_quorum_policy == no_quorum_stop) {
+ /* start shutting resources down */
+ new_node->weight = -INFINITY;
+ }
+
+
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 = -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...
* unless stonith is enabled in which case we need to
* 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 *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(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 {
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 = -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 = -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 %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);
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, 2:44 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009762
Default Alt Text
(86 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment