Page MenuHomeClusterLabs Projects

No OneTemporary

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

Mime Type
text/x-diff
Expires
Thu, Jul 10, 2:44 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009762
Default Alt Text
(86 KB)

Event Timeline