Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/pengine/complex.c b/crm/pengine/complex.c
index 40fac448ff..b87818ef33 100644
--- a/crm/pengine/complex.c
+++ b/crm/pengine/complex.c
@@ -1,476 +1,479 @@
-/* $Id: complex.c,v 1.39 2005/06/29 16:40:55 andrew Exp $ */
+/* $Id: complex.c,v 1.40 2005/06/29 16:43: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 <pengine.h>
#include <pe_utils.h>
#include <crm/msg_xml.h>
gboolean update_node_weight(rsc_to_node_t *cons,const char *id,GListPtr nodes);
gboolean is_active(rsc_to_node_t *cons);
gboolean constraint_violated(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint);
void order_actions(action_t *lh, action_t *rh, order_constraint_t *order);
gboolean has_agent(node_t *a_node, lrm_agent_t *an_agent);
extern gboolean rsc_colocation_new(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh);
extern rsc_to_node_t *rsc2node_new(
const char *id, resource_t *rsc, double weight, node_t *node,
pe_working_set_t *data_set);
resource_object_functions_t resource_class_functions[] = {
{
native_unpack,
native_find_child,
native_num_allowed_nodes,
native_color,
native_create_actions,
native_internal_constraints,
native_agent_constraints,
native_rsc_colocation_lh,
native_rsc_colocation_rh,
native_rsc_order_lh,
native_rsc_order_rh,
native_rsc_location,
native_expand,
native_dump,
native_printw,
native_free
},
{
group_unpack,
group_find_child,
group_num_allowed_nodes,
group_color,
group_create_actions,
group_internal_constraints,
group_agent_constraints,
group_rsc_colocation_lh,
group_rsc_colocation_rh,
group_rsc_order_lh,
group_rsc_order_rh,
group_rsc_location,
group_expand,
group_dump,
group_printw,
group_free
},
{
incarnation_unpack,
incarnation_find_child,
incarnation_num_allowed_nodes,
incarnation_color,
incarnation_create_actions,
incarnation_internal_constraints,
incarnation_agent_constraints,
incarnation_rsc_colocation_lh,
incarnation_rsc_colocation_rh,
incarnation_rsc_order_lh,
incarnation_rsc_order_rh,
incarnation_rsc_location,
incarnation_expand,
incarnation_dump,
incarnation_printw,
incarnation_free
}
};
/* resource_object_functions_t resource_variants[] = resource_class_functions; */
int get_resource_type(const char *name)
{
if(safe_str_eq(name, "resource")) {
return pe_native;
} else if(safe_str_eq(name, "resource_group")) {
return pe_group;
} else if(safe_str_eq(name, XML_RSC_ATTR_INCARNATION)) {
return pe_incarnation;
}
return pe_unknown;
}
gboolean
is_active(rsc_to_node_t *cons)
{
/* todo: check constraint lifetime */
return TRUE;
}
void
inherit_parent_attributes(
crm_data_t *parent, crm_data_t *child, gboolean overwrite)
{
int lpc = 0;
const char *attributes[] = {
XML_RSC_ATTR_STOPFAIL,
XML_RSC_ATTR_RESTART,
"multiple_active",
"start_prereq",
"resource_stickiness",
"is_managed"
};
for(lpc = 0; lpc < DIMOF(attributes); lpc++) {
const char *attr_p = crm_element_value(parent, attributes[lpc]);
const char *attr_c = crm_element_value(child, attributes[lpc]);
if(attr_c != NULL && safe_str_neq(attr_p, attr_c)) {
if(overwrite == FALSE) {
crm_debug_2("Resource %s: ignoring parent value for %s",
ID(child), attributes[lpc]);
continue;
}
pe_warn("Resource %s: Overwriting attribute %s: %s->%s",
ID(child), attributes[lpc], attr_c, attr_p);
}
if(attr_p != NULL) {
crm_xml_add(child, attributes[lpc], attr_p);
}
}
}
gboolean
common_unpack(
crm_data_t * xml_obj, resource_t **rsc, pe_working_set_t *data_set)
{
int stickiness = data_set->default_resource_stickiness;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
const char *restart = crm_element_value(xml_obj, XML_RSC_ATTR_RESTART);
const char *multiple = crm_element_value(xml_obj, "multiple_active");
const char *placement= crm_element_value(xml_obj, "resource_stickiness");
const char *priority = NULL;
const char *is_managed = NULL;
crm_log_xml_debug_2(xml_obj, "Processing resource input...");
if(id == NULL) {
pe_err("Must specify id tag in <resource>");
return FALSE;
} else if(rsc == NULL) {
pe_err("Nowhere to unpack resource into");
return FALSE;
}
crm_malloc0(*rsc, sizeof(resource_t));
if(*rsc == NULL) {
return FALSE;
}
(*rsc)->id = id;
(*rsc)->xml = xml_obj;
(*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE);
(*rsc)->variant = get_resource_type(crm_element_name(xml_obj));
if((*rsc)->variant == pe_unknown) {
pe_err("Unknown resource type: %s", crm_element_name(xml_obj));
crm_free(*rsc);
return FALSE;
}
(*rsc)->fns = &resource_class_functions[(*rsc)->variant];
crm_debug_3("Unpacking resource...");
(*rsc)->parameters = g_hash_table_new_full(
g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str);
unpack_instance_attributes(xml_obj, (*rsc)->parameters);
priority = get_rsc_param(*rsc, XML_CIB_ATTR_PRIORITY);
(*rsc)->priority = atoi(priority?priority:"0");
(*rsc)->effective_priority = (*rsc)->priority;
(*rsc)->recovery_type = recovery_stop_start;
(*rsc)->runnable = TRUE;
(*rsc)->provisional = TRUE;
(*rsc)->start_pending = FALSE;
(*rsc)->starting = FALSE;
(*rsc)->stopping = FALSE;
(*rsc)->candidate_colors = NULL;
(*rsc)->rsc_cons = NULL;
(*rsc)->actions = NULL;
+ (*rsc)->is_managed = TRUE;
is_managed = crm_element_value((*rsc)->xml, "is_managed");
if(is_managed != NULL && crm_is_true(is_managed) == FALSE) {
+ (*rsc)->is_managed = FALSE;
+ crm_warn("Resource %s is currently not managed", (*rsc)->id);
+#if 0
+ rsc_to_node_t *new_con = NULL;
/* prevent this resource from running anywhere */
- rsc_to_node_t *new_con = rsc2node_new(
+ new_con = rsc2node_new(
"is_managed_default", *rsc, -INFINITY, NULL, data_set);
new_con->node_list_rh = node_list_dup(data_set->nodes, FALSE);
- crm_warn("Resource %s is currently in standby/non-managed mode",
- (*rsc)->id);
-
- } else if(data_set->symmetric_cluster) {
+#endif
+ } else if((*rsc)->is_managed && data_set->symmetric_cluster) {
rsc_to_node_t *new_con = rsc2node_new(
"symmetric_default", *rsc, 0, NULL, data_set);
new_con->node_list_rh = node_list_dup(data_set->nodes, FALSE);
}
crm_debug_2("Options for %s", id);
if(safe_str_eq(restart, "restart")) {
(*rsc)->restart_type = pe_restart_restart;
crm_debug_2("\tDependancy restart handling: restart");
} else {
(*rsc)->restart_type = pe_restart_ignore;
crm_debug_2("\tDependancy restart handling: ignore");
}
if(safe_str_eq(multiple, "stop_only")) {
(*rsc)->recovery_type = recovery_stop_only;
crm_debug_2("\tMultiple running resource recovery: stop only");
} else if(safe_str_eq(multiple, "block")) {
(*rsc)->recovery_type = recovery_block;
crm_debug_2("\tMultiple running resource recovery: block");
} else {
(*rsc)->recovery_type = recovery_stop_start;
crm_debug_2("\tMultiple running resource recovery: stop/start");
}
if(placement != NULL) {
stickiness = atoi(placement);
}
if(stickiness > 0) {
crm_debug_2("\tPlacement: prefer current location%s",
placement == NULL?" (default)":"");
rsc_colocation_new("__generated_internal_placement__",
pecs_must, *rsc, *rsc);
} else if(stickiness < 0) {
crm_warn("\tPlacement: always move from the current location%s",
placement == NULL?" (default)":"");
rsc_colocation_new("__generated_internal_placement__",
pecs_must_not, *rsc, *rsc);
} else {
crm_debug_2("\tPlacement: optimal%s",
placement == NULL?" (default)":"");
}
(*rsc)->fns->unpack(*rsc, data_set);
return TRUE;
}
void
order_actions(action_t *lh_action, action_t *rh_action, order_constraint_t *order)
{
action_wrapper_t *wrapper = NULL;
GListPtr list = NULL;
crm_debug_2("Ordering %d: Action %d before %d",
order?order->id:-1, lh_action->id, rh_action->id);
log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE);
log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE);
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = rh_action;
wrapper->type = order->type;
list = lh_action->actions_after;
list = g_list_append(list, wrapper);
lh_action->actions_after = list;
wrapper = NULL;
}
if(order->type != pe_ordering_recover) {
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = lh_action;
wrapper->type = order->type;
list = rh_action->actions_before;
list = g_list_append(list, wrapper);
rh_action->actions_before = list;
}
}
}
void common_printw(resource_t *rsc, const char *pre_text, int *index)
{
#ifdef HAVE_LIBNCURSES
const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
move(*index, 0);
printw("%s%s %s (%s%s%s:%s):\t",
pre_text?pre_text:"", crm_element_name(rsc->xml), rsc->id,
prov?prov:"", prov?"::":"",
crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS),
crm_element_value(rsc->xml, XML_ATTR_TYPE));
#else
crm_err("printw support requires ncurses to be available during configure");
#endif
}
void common_dump(resource_t *rsc, const char *pre_text, gboolean details)
{
crm_debug_4("%s%s%s%sResource %s: (variant=%s, priority=%f)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
rsc->provisional?"Provisional ":"",
rsc->runnable?"":"(Non-Startable) ",
rsc->id,
crm_element_name(rsc->xml),
(double)rsc->priority);
}
void common_free(resource_t *rsc)
{
if(rsc == NULL) {
return;
}
crm_debug_5("Freeing %s", rsc->id);
while(rsc->rsc_cons) {
pe_free_rsc_colocation(
(rsc_colocation_t*)rsc->rsc_cons->data);
rsc->rsc_cons = rsc->rsc_cons->next;
}
if(rsc->rsc_cons != NULL) {
g_list_free(rsc->rsc_cons);
}
if(rsc->parameters != NULL) {
g_hash_table_destroy(rsc->parameters);
}
pe_free_shallow_adv(rsc->candidate_colors, TRUE);
crm_free(rsc->variant_opaque);
crm_free(rsc);
crm_debug_5("Resource freed");
}
void
common_agent_constraints(
GListPtr node_list, lrm_agent_t *agent, const char *id)
{
#if 0
slist_iter(
node, node_t, node_list, lpc,
crm_debug_5("Checking if %s supports %s/%s (%s)",
node->details->uname,
agent->class, agent->type, agent->version);
if(has_agent(node, agent) == FALSE) {
/* remove node from contention */
crm_debug_5("Marking node %s unavailable for %s",
node->details->uname, id);
node->weight = -1.0;
node->fixed = TRUE;
}
);
#endif
}
void
unpack_instance_attributes(crm_data_t *xml_obj, GHashTable *hash)
{
const char *name = NULL;
const char *value = NULL;
if(xml_obj == NULL) {
crm_debug_4("No instance attributes");
return;
}
xml_child_iter(
xml_obj, attr_set, XML_TAG_ATTR_SETS,
xml_child_iter(
attr_set, attrs, XML_TAG_ATTRS,
/* todo: check any rules */
xml_child_iter(
attrs, an_attr, XML_CIB_TAG_NVPAIR,
name = crm_element_value(
an_attr, XML_NVPAIR_ATTR_NAME);
value = crm_element_value(
an_attr, XML_NVPAIR_ATTR_VALUE);
add_hash_param(hash, name, value);
);
);
);
}
void
add_rsc_param(resource_t *rsc, const char *name, const char *value)
{
CRM_DEV_ASSERT(rsc != NULL);
if(crm_assert_failed) {
return;
}
add_hash_param(rsc->parameters, name, value);
}
void
add_hash_param(GHashTable *hash, const char *name, const char *value)
{
CRM_DEV_ASSERT(hash != NULL);
if(crm_assert_failed) {
return;
}
crm_debug_3("adding: name=%s value=%s", crm_str(name), crm_str(value));
if(name == NULL || value == NULL) {
return;
} else if(g_hash_table_lookup(hash, name) == NULL) {
g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value));
}
}
const char *
get_rsc_param(resource_t *rsc, const char *name)
{
CRM_DEV_ASSERT(rsc != NULL);
if(crm_assert_failed) {
return NULL;
}
return g_hash_table_lookup(rsc->parameters, name);
}
void
hash2nvpair(gpointer key, gpointer value, gpointer user_data)
{
const char *name = key;
const char *s_value = value;
crm_data_t *xml_node = user_data;
crm_data_t *xml_child = create_xml_node(xml_node, XML_CIB_TAG_NVPAIR);
crm_xml_add(xml_child, XML_NVPAIR_ATTR_NAME, name);
crm_xml_add(xml_child, XML_NVPAIR_ATTR_VALUE, s_value);
crm_debug_3("dumped: name=%s value=%s", name, s_value);
}
diff --git a/crm/pengine/complex.h b/crm/pengine/complex.h
index b86e60f5a7..13cdfb1e6b 100644
--- a/crm/pengine/complex.h
+++ b/crm/pengine/complex.h
@@ -1,164 +1,165 @@
-/* $Id: complex.h,v 1.13 2005/06/29 09:03:52 andrew Exp $ */
+/* $Id: complex.h,v 1.14 2005/06/29 16:43: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 CRM_PENGINE_COMPLEX__H
#define CRM_PENGINE_COMPLEX__H
#include <crm/common/xml.h>
#include <crm/pengine/pengine.h>
#include <glib.h>
#define n_object_classes 3
/*#define PE_OBJ_F_ ""*/
#define PE_OBJ_T_NATIVE "native"
#define PE_OBJ_T_GROUP "group"
#define PE_OBJ_T_INCARNATION "incarnation"
enum pe_obj_types
{
pe_native = 0,
pe_group = 1,
pe_incarnation = 2,
pe_unknown = -1
};
extern int get_resource_type(const char *name);
typedef struct resource_object_functions_s
{
void (*unpack)(resource_t *, pe_working_set_t *);
resource_t *(*find_child)(resource_t *, const char *);
int (*num_allowed_nodes)(resource_t *);
void (*color)(resource_t *, pe_working_set_t *);
void (*create_actions)(resource_t *, pe_working_set_t *);
void (*internal_constraints)(resource_t *, pe_working_set_t *);
void (*agent_constraints)(resource_t *);
void (*rsc_colocation_lh)(rsc_colocation_t *);
void (*rsc_colocation_rh)(resource_t *, rsc_colocation_t *);
void (*rsc_order_lh)(resource_t *, order_constraint_t *);
void (*rsc_order_rh)(
action_t *, resource_t *, order_constraint_t *);
void (*rsc_location)(resource_t *, rsc_to_node_t *);
void (*expand)(resource_t *, pe_working_set_t *);
void (*dump)(resource_t *, const char *, gboolean);
void (*printw)(resource_t *, const char *, int*);
void (*free)(resource_t *);
} resource_object_functions_t;
extern void native_unpack(resource_t *rsc, pe_working_set_t *data_set);
extern resource_t *native_find_child(resource_t *rsc, const char *id);
extern int native_num_allowed_nodes(resource_t *rsc);
extern void native_color(resource_t *rsc, pe_working_set_t *data_set);
extern void native_create_actions(
resource_t *rsc, pe_working_set_t *data_set);
extern void native_internal_constraints(
resource_t *rsc, pe_working_set_t *data_set);
extern void native_agent_constraints(resource_t *rsc);
extern void native_rsc_colocation_lh(rsc_colocation_t *constraint);
extern void native_rsc_colocation_rh(
resource_t *rsc, rsc_colocation_t *constraint);
extern void native_rsc_order_lh(resource_t *rsc, order_constraint_t *order);
extern void native_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order);
extern void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint);
extern void native_expand(resource_t *rsc, pe_working_set_t *data_set);
extern void native_dump(resource_t *rsc, const char *pre_text, gboolean details);
extern void native_printw(resource_t *rsc, const char *pre_text, int *index);
extern void native_free(resource_t *rsc);
extern void group_unpack(resource_t *rsc, pe_working_set_t *data_set);
extern resource_t *group_find_child(resource_t *rsc, const char *id);
extern int group_num_allowed_nodes(resource_t *rsc);
extern void group_color(resource_t *rsc, pe_working_set_t *data_set);
extern void group_create_actions(
resource_t *rsc, pe_working_set_t *data_set);
extern void group_internal_constraints(
resource_t *rsc, pe_working_set_t *data_set);
extern void group_agent_constraints(resource_t *rsc);
extern void group_rsc_colocation_lh(rsc_colocation_t *constraint);
extern void group_rsc_colocation_rh(
resource_t *rsc, rsc_colocation_t *constraint);
extern void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order);
extern void group_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order);
extern void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint);
extern void group_expand(resource_t *rsc, pe_working_set_t *data_set);
extern void group_dump(resource_t *rsc, const char *pre_text, gboolean details);
extern void group_printw(resource_t *rsc, const char *pre_text, int *index);
extern void group_free(resource_t *rsc);
extern void incarnation_unpack(resource_t *rsc, pe_working_set_t *data_set);
extern resource_t *incarnation_find_child(resource_t *rsc, const char *id);
extern int incarnation_num_allowed_nodes(resource_t *rsc);
extern void incarnation_color(resource_t *rsc, pe_working_set_t *data_set);
extern void incarnation_create_actions(
resource_t *rsc, pe_working_set_t *data_set);
extern void incarnation_internal_constraints(
resource_t *rsc, pe_working_set_t *data_set);
extern void incarnation_agent_constraints(resource_t *rsc);
extern void incarnation_rsc_colocation_lh(rsc_colocation_t *constraint);
extern void incarnation_rsc_colocation_rh(
resource_t *rsc, rsc_colocation_t *constraint);
extern void incarnation_rsc_order_lh(resource_t *rsc, order_constraint_t *order);
extern void incarnation_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order);
extern void incarnation_rsc_location(resource_t *rsc, rsc_to_node_t *constraint);
extern void incarnation_expand(resource_t *rsc, pe_working_set_t *data_set);
extern void incarnation_dump(resource_t *rsc, const char *pre_text, gboolean details);
extern void incarnation_printw(resource_t *rsc, const char *pre_text, int *index);
extern void incarnation_free(resource_t *rsc);
/* extern resource_object_functions_t resource_variants[]; */
extern resource_object_functions_t resource_class_functions[];
extern gboolean common_unpack(
crm_data_t *xml_obj, resource_t **rsc, pe_working_set_t *data_set);
extern void common_dump(
resource_t *rsc, const char *pre_text, gboolean details);
extern void common_printw(resource_t *rsc, const char *pre_text, int *index);
extern void common_free(resource_t *rsc);
-extern void native_add_running(resource_t *rsc, node_t *node);
+extern void native_add_running(
+ resource_t *rsc, node_t *node, pe_working_set_t *data_set);
extern gboolean is_active(rsc_to_node_t *cons);
extern gboolean native_constraint_violated(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint);
extern void order_actions(action_t *lh, action_t *rh, order_constraint_t *order);
extern void common_agent_constraints(
GListPtr node_list, lrm_agent_t *agent, const char *id);
extern void unpack_instance_attributes(crm_data_t *xml_obj, GHashTable *hash);
extern const char *get_rsc_param(resource_t *rsc, const char *prop);
extern void add_rsc_param(resource_t *rsc, const char *name, const char *value);
extern void add_hash_param(GHashTable *hash, const char *name, const char *value);
extern void hash2nvpair(gpointer key, gpointer value, gpointer user_data);
extern void inherit_parent_attributes(
crm_data_t *parent, crm_data_t *child, gboolean overwrite);
#endif
diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c
index 9def426f4a..e89f97c643 100644
--- a/crm/pengine/graph.c
+++ b/crm/pengine/graph.c
@@ -1,491 +1,496 @@
-/* $Id: graph.c,v 1.52 2005/06/16 12:36:18 andrew Exp $ */
+/* $Id: graph.c,v 1.53 2005/06/29 16:43: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 <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
gboolean update_action(action_t *action);
gboolean
update_action_states(GListPtr actions)
{
crm_debug_2("Updating %d actions", g_list_length(actions));
slist_iter(
action, action_t, actions, lpc,
update_action(action);
);
return TRUE;
}
#define UPDATE_THEM 1
gboolean
update_action(action_t *action)
{
gboolean change = FALSE;
enum action_tasks task = no_action;
crm_debug_3("Processing action %d: %s",
action->id, action->optional?"optional":"required");
#if UPDATE_THEM
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
crm_debug_3("\tChecking action %d: %s/%s",
other->action->id, ordering_type2text(other->type),
other->action->optional?"optional":"required");
if(other->type == pe_ordering_manditory) {
} else if(other->type == pe_ordering_restart
&& action->rsc->start_pending == FALSE) {
} else {
crm_debug_3("\t Ignoring: %s",
ordering_type2text(other->type));
continue;
}
if(action->optional || other->action->optional == FALSE) {
crm_debug_3("\t Ignoring: %s/%s",
other->action->optional?"-":"they are not optional",
action->optional?"we are optional":"-");
continue;
}
other->action->optional = FALSE;
crm_debug_2("* Marking action %d manditory because of %d",
other->action->id, action->id);
update_action(other->action);
);
#else
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
crm_debug_3("\tChecking action %d: %s/%s",
other->action->id, ordering_type2text(other->type),
other->action->optional?"optional":"required");
if(other->type != pe_ordering_manditory) {
crm_debug_3("\t Ignoring: %s",
ordering_type2text(other->type));
continue;
} else if(other->action->optional || action->optional == FALSE) {
crm_debug_3("\t Ignoring: %s/%s",
other->action->optional?"they are optional":"-",
action->optional?"-":"we are not optional");
continue;
}
change = TRUE;
action->optional = FALSE;
crm_debug_2("* Marking action %d manditory because of %d",
action->id, other->action->id);
);
#endif
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
if(action->pseudo == FALSE && action->runnable == FALSE) {
if(other->action->runnable == FALSE) {
crm_debug_2("Action %d already un-runnable",
other->action->id);
} else if(action->optional == FALSE) {
other->action->runnable = FALSE;
crm_debug_2("Marking action %d un-runnable"
" because of %d",
other->action->id, action->id);
update_action(other->action);
}
}
crm_debug_3("\t(Recover) Checking action %d: %s/%s",
other->action->id, ordering_type2text(other->type),
other->action->optional?"optional":"required");
if(other->action->rsc == NULL) {
continue;
} else if(other->type == pe_ordering_recover) {
if(other->action->rsc->restart_type != pe_restart_restart) {
crm_debug_3("\t Ignoring: restart type %d",
other->action->rsc->restart_type);
continue;
}
} else if(other->type == pe_ordering_restart) {
if(action->rsc != other->action->rsc) {
crm_err("Unexpected!");
continue;
}
} else {
crm_debug_3("\t Ignoring: ordering %s",
ordering_type2text(other->type));
continue;
}
if(other->action->optional == FALSE || action->optional) {
crm_debug_3("\t Ignoring: %s/%s",
action->optional?"we are optional":"-",
other->action->optional?"-":"they are not optional");
continue;
}
task = text2task(action->task);
switch(task) {
case stop_rsc:
case stopped_rsc:
crm_debug_3("\t Ignoring: action %s",
action->task);
break;
case start_rsc:
case started_rsc:
crm_debug_2("* (Recover) Marking action %d"
" manditory because of %d",
other->action->id, action->id);
other->action->optional = FALSE;
update_action(other->action);
break;
default:
crm_debug_3("\t Ignoring: action %s",
action->task);
break;
}
);
if(change) {
update_action(action);
}
crm_debug_3("Action %d: %s", action->id, change?"update":"untouched");
return change;
}
gboolean
shutdown_constraints(
node_t *node, action_t *shutdown_op, pe_working_set_t *data_set)
{
/* add the stop to the before lists so it counts as a pre-req
* for the shutdown
*/
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
custom_action_order(
rsc, stop_key(rsc), NULL,
NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op,
pe_ordering_manditory, data_set);
);
return TRUE;
}
gboolean
stonith_constraints(node_t *node,
action_t *stonith_op, action_t *shutdown_op,
pe_working_set_t *data_set)
{
GListPtr stop_actions = NULL;
gboolean run_unprotected = TRUE;
if(shutdown_op != NULL) {
/* stop everything we can via shutdown_constraints() and then
* shoot the node... the shutdown has been superceeded
*/
shutdown_op->pseudo = TRUE;
shutdown_op->runnable = TRUE;
/* shutdown before stonith */
/* Give any resources a chance to shutdown normally */
crm_debug_4("Adding shutdown (%d) as an input to stonith (%d)",
shutdown_op->id, stonith_op->id);
custom_action_order(
NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op,
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
pe_ordering_manditory, data_set);
}
/*
* Make sure the stonith OP occurs before we start any shared resources
*/
slist_iter(
rsc, resource_t, data_set->resources, lpc,
slist_iter(action, action_t, rsc->actions, lpc2,
if(action->needs != rsc_req_stonith) {
continue;
}
if(stonith_op != NULL) {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
rsc, NULL, action,
pe_ordering_manditory, data_set);
} else if(run_unprotected == FALSE) {
/* mark the start unrunnable */
action->runnable = FALSE;
} else {
pe_err("SHARED RESOURCE %s IS NOT PROTECTED:"
" Stonith disabled", rsc->id);
}
);
);
/* add the stonith OP as a stop pre-req and the mark the stop
* as a pseudo op - since its now redundant
*/
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
if(stonith_op != NULL) {
char *key = stop_key(rsc);
stop_actions = find_actions(rsc->actions, key, node);
crm_free(key);
slist_iter(
action, action_t, stop_actions, lpc2,
if(node->details->online == FALSE
|| rsc->unclean) {
/* the stop would never complete and is
* now implied by the stonith operation
*/
action->pseudo = TRUE;
action->runnable = TRUE;
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE),stonith_op,
rsc, stop_key(rsc), NULL,
pe_ordering_manditory, data_set);
} else {
/* stop healthy resources before the
* stonith op
*/
custom_action_order(
rsc, stop_key(rsc), NULL,
NULL,crm_strdup(CRM_OP_FENCE),stonith_op,
pe_ordering_manditory, data_set);
}
);
crm_debug_4("Adding stonith (%d) as an input to stop",
stonith_op->id);
/* } else if((rsc->unclean || node->details->unclean) */
/* && rsc->stopfail_type == pesf_block) { */
/* /\* depend on the stop action which will fail *\/ */
/* pe_err("SHARED RESOURCE %s WILL REMAIN BLOCKED" */
/* " ON NODE %s UNTIL %s", */
/* rsc->id, node->details->uname, */
/* data_set->stonith_enabled?"QUORUM RETURNS":"CLEANED UP MANUALLY"); */
/* continue; */
/* } else if((rsc->unclean || node->details->unclean) */
/* && rsc->stopfail_type == pesf_ignore) { */
/* /\* nothing to do here *\/ */
/* pe_err("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); */
/* continue; */
}
);
return TRUE;
}
crm_data_t *
action2xml(action_t *action, gboolean as_input)
{
gboolean needs_node_info = TRUE;
crm_data_t * action_xml = NULL;
crm_data_t * args_xml = NULL;
char *action_id_s = NULL;
if(action == NULL) {
return NULL;
}
crm_debug_4("Dumping action %d as XML", action->id);
if(safe_str_eq(action->task, CRM_OP_FENCE)) {
action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
needs_node_info = FALSE;
} else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) {
action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
} else if(action->pseudo) {
action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
needs_node_info = FALSE;
} else {
action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
}
action_id_s = crm_itoa(action->id);
crm_xml_add(action_xml, XML_ATTR_ID, action_id_s);
crm_free(action_id_s);
if(action->rsc != NULL) {
crm_xml_add(
action_xml, XML_LRM_ATTR_RSCID, action->rsc->id);
}
crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
if(needs_node_info && action->node != NULL) {
crm_xml_add(action_xml, XML_LRM_ATTR_TARGET,
action->node->details->uname);
crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID,
action->node->details->id);
CRM_DEV_ASSERT(NULL != crm_element_value(
action_xml, XML_LRM_ATTR_TARGET));
CRM_DEV_ASSERT(NULL != crm_element_value(
action_xml, XML_LRM_ATTR_TARGET_UUID));
}
crm_xml_add(action_xml, "allow_fail",
action->failure_is_fatal?XML_BOOLEAN_FALSE:XML_BOOLEAN_TRUE);
if(as_input) {
return action_xml;
}
if(action->rsc != NULL && action->pseudo == FALSE) {
crm_data_t *rsc_xml = create_xml_node(
action_xml, crm_element_name(action->rsc->xml));
copy_in_properties(rsc_xml, action->rsc->xml);
args_xml = create_xml_node(action_xml, XML_TAG_ATTRS);
g_hash_table_foreach(action->extra, hash2nvpair, args_xml);
g_hash_table_foreach(
action->rsc->parameters, hash2nvpair, args_xml);
} else {
args_xml = create_xml_node(action_xml, XML_TAG_ATTRS);
g_hash_table_foreach(action->extra, hash2nvpair, args_xml);
}
crm_log_xml_debug_2(action_xml, "dumped action");
return action_xml;
}
void
graph_element_from_action(action_t *action, pe_working_set_t *data_set)
{
int last_action = -1;
char *syn_id = NULL;
crm_data_t * syn = NULL;
crm_data_t * set = NULL;
crm_data_t * in = NULL;
crm_data_t * input = NULL;
crm_data_t * xml_action = NULL;
if(action == NULL) {
pe_err("Cannot dump NULL action");
return;
} else if(action->optional) {
crm_debug_5("action %d was optional", action->id);
return;
} else if(action->pseudo == FALSE && action->runnable == FALSE) {
crm_debug_5("action %d was not runnable", action->id);
return;
} else if(action->dumped) {
crm_debug_5("action %d was already dumped", action->id);
return;
} else if(action->pseudo
|| safe_str_eq(action->task, CRM_OP_FENCE)
|| safe_str_eq(action->task, CRM_OP_SHUTDOWN)) {
- /* skip the next check */
+ /* skip the next two checks */
+
+ } else if(action->rsc != NULL && action->rsc->is_managed == FALSE) {
+ pe_warn("action %d was for an unmanaged resource (%s)",
+ action->id, action->rsc->id);
+ return;
} else {
if(action->node == NULL) {
pe_err("action %d was not allocated", action->id);
log_action(LOG_DEBUG, "Unallocated action", action, FALSE);
return;
} else if(action->node->details->online == FALSE) {
pe_err("action %d was scheduled for offline node", action->id);
log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
return;
}
}
action->dumped = TRUE;
syn = create_xml_node(data_set->graph, "synapse");
set = create_xml_node(syn, "action_set");
in = create_xml_node(syn, "inputs");
syn_id = crm_itoa(data_set->num_synapse);
crm_xml_add(syn, XML_ATTR_ID, syn_id);
crm_free(syn_id);
data_set->num_synapse++;
xml_action = action2xml(action, FALSE);
add_node_copy(set, xml_action);
free_xml(xml_action);
action->actions_before = g_list_sort(
action->actions_before, sort_action_id);
slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc,
if(last_action == wrapper->action->id) {
crm_debug_2("Input %d duplicated",
wrapper->action->id);
continue;
} else if(wrapper->action->optional == TRUE) {
crm_debug_2("Input %d optional",
wrapper->action->id);
continue;
}
CRM_DEV_ASSERT(last_action < wrapper->action->id);
last_action = wrapper->action->id;
input = create_xml_node(in, "trigger");
xml_action = action2xml(wrapper->action, TRUE);
add_node_copy(input, xml_action);
free_xml(xml_action);
);
}
diff --git a/crm/pengine/native.c b/crm/pengine/native.c
index 2bf0bd9ff4..0bfaa5c423 100644
--- a/crm/pengine/native.c
+++ b/crm/pengine/native.c
@@ -1,1267 +1,1277 @@
-/* $Id: native.c,v 1.53 2005/06/29 12:56:16 andrew Exp $ */
+/* $Id: native.c,v 1.54 2005/06/29 16:43: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 <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, color_t *no_color);
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_recurring_actions(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set);
action_t *create_recurring_action(resource_t *rsc, node_t *node,
const char *action, const char *key);
+extern rsc_to_node_t *
+rsc2node_new(const char *id, resource_t *rsc,
+ double weight, node_t *node, pe_working_set_t *data_set);
+
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_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return; }
slist_iter(
a_node, node_t, native_data->running_on, lpc,
CRM_DEV_ASSERT(a_node != NULL);
if(safe_str_eq(a_node->details->id, node->details->id)) {
return;
}
);
native_data->running_on = g_list_append(native_data->running_on, node);
node->details->running_rsc = g_list_append(
node->details->running_rsc, rsc);
+ if(rsc->is_managed == FALSE) {
+ rsc2node_new(
+ "not_managed_default", rsc, INFINITY, node, data_set);
+ return;
+ }
+
if(g_list_length(native_data->running_on) > 1) {
pe_warn("Resource %s is (potentially) active on %d nodes."
" Latest: %s/%s", rsc->id,
g_list_length(native_data->running_on),
node->details->uname, node->details->id);
}
}
void native_unpack(resource_t *rsc, pe_working_set_t *data_set)
{
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_debug_3("Processing resource %s...", rsc->id);
crm_malloc0(native_data, sizeof(native_variant_data_t));
crm_malloc0(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 {
pe_err("Resource %s was not a \"native\" variant",
rsc->id);
return 0;
}
if(native_data->color) {
crm_debug_4("Colored case");
num_nodes = 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);
crm_debug_4("Candidate colors case");
num_nodes = num_allowed_nodes4color(color);
} else {
crm_debug_4("Default case");
slist_iter(
this_node, node_t, native_data->allowed_nodes, lpc,
crm_debug_3("Rsc %s Checking %s: %f",
rsc->id, this_node->details->uname,
this_node->weight);
if(this_node->details->shutdown
|| this_node->details->online == FALSE) {
this_node->weight = -INFINITY;
}
if(this_node->weight < 0) {
continue;
/* } else if(this_node->details->unclean) { */
/* continue; */
}
num_nodes++;
);
}
crm_debug_2("Resource %s can run on %d nodes", rsc->id, 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,
crm_debug_3("Checking %s: %f",
this_node->details->uname, this_node->weight);
if(this_node->details->shutdown
|| this_node->details->online == FALSE) {
this_node->weight = -INFINITY;
}
if(this_node->weight < 0) {
continue;
/* } else if(this_node->details->unclean) { */
/* continue; */
}
num_nodes++;
);
return num_nodes;
}
void native_color(resource_t *rsc, pe_working_set_t *data_set)
{
color_t *new_color = NULL;
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
if( native_choose_color(rsc, data_set->no_color) ) {
crm_debug_3("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(data_set, rsc,
native_data->allowed_nodes);
native_assign_color(rsc, new_color);
}
if(new_color == NULL) {
pe_warn("Resource %s cannot run anywhere", rsc->id);
print_resource("ERROR: No color", rsc, FALSE);
native_assign_color(rsc, data_set->no_color);
}
}
rsc->provisional = FALSE;
}
void
create_recurring_actions(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set)
{
action_t *mon = NULL;
char *key = NULL;
const char *name = NULL;
const char *value = NULL;
if(node == NULL || !node->details->online || node->details->unclean) {
crm_debug_3("Not creating recurring actions");
return;
}
xml_child_iter(
rsc->ops_xml, operation, "op",
name = crm_element_value(operation, "name");
value = crm_element_value(operation, "interval");
key = generate_op_key(rsc->id, name, crm_get_msec(value));
mon = custom_action(rsc, key, name, node, start->optional, data_set);
if(mon->optional == FALSE && node != NULL) {
crm_info(" %s:\t(%s)", mon->uuid, node->details->uname);
}
custom_action_order(rsc, start_key(rsc), NULL,
NULL, crm_strdup(key), mon,
pe_ordering_manditory, data_set);
);
}
void native_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
action_t *start = NULL;
action_t *stop = 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) {
start = start_action(rsc, chosen, TRUE);
if(start->runnable && data_set->have_quorum == FALSE
&& data_set->no_quorum_policy != no_quorum_ignore) {
crm_warn("Start resource %s\t(%s) (cancelled : quorum)",
rsc->id, chosen->details->uname);
start->runnable = FALSE;
} else {
crm_info("Start resource %s\t(%s)",
rsc->id, chosen->details->uname);
start->optional = FALSE;
start->rsc->start_pending = TRUE;
}
} else if(g_list_length(native_data->running_on) > 1) {
pe_err("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\t(%s) (recovery)",
rsc->id, node->details->uname);
stop = stop_action(rsc, node, FALSE);
);
}
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
*/
start = start_action(rsc, chosen, FALSE);
if(start->runnable) {
crm_info("Recover resource %s\t(%s)",
rsc->id, chosen->details->uname);
}
/* make the restart required */
order_stop_start(rsc, rsc, pe_ordering_manditory);
}
if(rsc->recovery_type == recovery_block) {
pe_warn("RESOURCE %s WILL REMAIN ACTIVE ON MULTIPLE"
" NODES PENDING MANUAL INTERVENTION", rsc->id);
slist_iter(
node, node_t, native_data->running_on, lpc,
pe_warn("Resource %s active on %s",
rsc->id, node->details->uname);
);
}
} else if(g_list_length(native_data->running_on) == 1) {
node_t *node = native_data->running_on->data;
crm_debug_2("Stop%s of %s", chosen?" and restart":"", rsc->id);
CRM_DEV_ASSERT(node != NULL);
if(chosen == NULL) {
crm_info("Stop resource %s\t(%s)",
rsc->id, node->details->uname);
stop_action(rsc, node, FALSE);
} else if(safe_str_eq(node->details->id, chosen->details->id)) {
stop = stop_action(rsc, node, TRUE);
start = start_action(rsc, chosen, TRUE);
if(start->runnable == FALSE) {
crm_info("Stop resource %s\t(%s)",
rsc->id, node->details->uname);
stop->optional = FALSE;
} else if(rsc->recover) {
crm_info("Restart resource %s\t(%s)",
rsc->id, node->details->uname);
/* make the restart required */
order_stop_start(rsc, rsc, pe_ordering_manditory);
start->optional = FALSE;
stop->optional = FALSE;
} else {
crm_info("Leave resource %s\t(%s)",
rsc->id, node->details->uname);
if(stop->optional == FALSE) {
start->optional = FALSE;
} else if(rsc->start_pending) {
start->optional = FALSE;
}
}
} else {
/* move */
stop = stop_action(rsc, node, FALSE);
start = start_action(rsc, chosen, FALSE);
if(start->runnable) {
crm_info("Move resource %s\t(%s -> %s)", rsc->id,
node->details->uname,
chosen->details->uname);
} else {
crm_info("Stop resource %s\t(%s)", rsc->id,
node->details->uname);
}
/* make the restart required */
order_stop_start(rsc, rsc, pe_ordering_manditory);
}
}
if(start != NULL && start->runnable) {
create_recurring_actions(rsc, start, chosen, data_set);
}
}
void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
order_restart(rsc);
}
void native_rsc_colocation_lh(rsc_colocation_t *constraint)
{
resource_t *rsc = constraint->rsc_lh;
if(rsc == NULL) {
pe_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if(constraint->rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
} else {
crm_debug_4("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_debug_3("Processing RH of constraint %s", constraint->id);
crm_action_debug_3(print_resource("LHS", rsc_lh, TRUE));
crm_action_debug_3(print_resource("RHS", rsc_rh, TRUE));
if(constraint->strength == pecs_ignore
|| constraint->strength == pecs_startstop){
crm_debug_4("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_debug_4(
"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 {
pe_warn("Un-expected combination of inputs");
return;
}
if(update_lh) {
crm_debug_4("Updating LHS");
}
if(update_rh) {
crm_debug_4("Updating RHS");
}
if(do_check) {
if(native_constraint_violated(
rsc_lh, rsc_rh, constraint) == FALSE) {
crm_debug_4("Constraint satisfied");
return;
}
/* else constraint cant be satisified */
pe_warn("Constraint %s could not be satisfied",
constraint->id);
if(update_lh) {
pe_warn("Marking resource %s unrunnable as a result",
rsc_lh->id);
rsc_lh->runnable = FALSE;
}
if(update_rh) {
pe_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 */
pe_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_debug_3("Processing LH of ordering constraint %d", order->id);
if(lh_action != NULL) {
lh_actions = g_list_append(NULL, lh_action);
} else if(lh_action == NULL && lh_rsc != NULL) {
#if 0
/* this should be safe to remove */
if(order->strength == pecs_must) {
crm_debug_4("No LH-Side (%s/%s) found for constraint..."
" creating",
lh_rsc->id, order->lh_action_task);
pe_err("BROKEN CODE");
custom_action(
lh_rsc, order->lh_action_task, NULL, NULL);
}
#endif
lh_actions = find_actions(
lh_rsc->actions, order->lh_action_task, NULL);
if(lh_actions == NULL) {
crm_debug_4("No LH-Side (%s/%s) found for constraint",
lh_rsc->id, order->lh_action_task);
if(order->rh_rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL
&& order->rh_action->rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_action->rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL) {
crm_debug_4("RH-Side was: %s",
order->rh_action_task);
} else {
crm_debug_4("RH-Side was NULL");
}
return;
}
} else {
pe_warn("No LH-Side (%s) specified for constraint",
order->lh_action_task);
if(order->rh_rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL
&& order->rh_action->rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_action->rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL) {
crm_debug_4("RH-Side was: %s",
order->rh_action_task);
} else {
crm_debug_4("RH-Side was NULL");
}
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_debug_3("Processing RH of ordering constraint %d", order->id);
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_debug_4("No RH-Side (%s/%s) found for constraint..."
" ignoring",
rsc->id, order->rh_action_task);
crm_debug_4("LH-Side was: (%s/%s)",
order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
order->lh_action_task);
return;
}
} else if(rh_action == NULL) {
crm_debug_4("No RH-Side (%s) specified for constraint..."
" ignoring", order->rh_action_task);
crm_debug_4("LH-Side was: (%s/%s)",
order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
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_action_debug_3(print_rsc_to_node("Applying", constraint, FALSE));
/* take "lifetime" into account */
if(constraint == NULL) {
pe_err("Constraint is NULL");
return;
} else if(is_active(constraint) == FALSE) {
crm_debug_2("Constraint (%s) is not active", constraint->id);
return;
} else if(rsc == NULL) {
pe_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_2("RHS of constraint %s is NULL", constraint->id);
return;
}
crm_action_debug_3(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_action_debug_3(print_resource("after update", rsc, TRUE));
}
void native_expand(resource_t *rsc, pe_working_set_t *data_set)
{
slist_iter(
action, action_t, rsc->actions, lpc,
crm_debug_4("processing action %d for rsc=%s",
action->id, rsc->id);
graph_element_from_action(action, data_set);
);
}
void native_printw(resource_t *rsc, const char *pre_text, int *index)
{
#ifdef HAVE_LIBNCURSES
native_variant_data_t *native_data = NULL;
get_native_variant_data(native_data, rsc);
common_printw(rsc, pre_text, index);
if(g_list_length(native_data->running_on) == 0) {
printw("NOT ACTIVE\n");
} else if(g_list_length(native_data->running_on) == 1) {
node_t *node = native_data->running_on->data;
printw("%s (%s)\n", node->details->uname, node->details->id);
} else if(g_list_length(native_data->running_on) == 1) {
printw("[");
slist_iter(node, node_t, native_data->running_on, lpc,
if(lpc > 0) { printw(", "); }
printw("%s (%s)", node->details->uname, node->details->id);
);
printw("]\n");
}
#else
crm_err("printw support requires ncurses to be available during configure");
#endif
}
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_debug_4("\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_debug_4("\t=== Actions");
slist_iter(
action, action_t, rsc->actions, lpc,
print_action("\trsc action: ", action, FALSE);
);
crm_debug_4("\t=== Colors");
slist_iter(
color, color_t, rsc->candidate_colors, lpc,
print_color("\t", color, FALSE)
);
crm_debug_4("\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_debug_4("Freeing Allowed Nodes & Agent");
crm_free(native_data->color);
pe_free_shallow(native_data->allowed_nodes);
crm_free(native_data->agent);
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_DEV_ASSERT(native_data_lh->color != native_data_rh->color);
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_DEV_ASSERT(native_data_lh->color != native_data_rh->color);
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_debug_4("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_debug_4("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_debug_4("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_action_debug_3(
print_color("Removed LH", color_lh, FALSE));
crm_action_debug_3(
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_action_debug_3(
print_node("Removed LH", node_lh, FALSE));
crm_action_debug_3(
print_color("Modified LH", color_lh, FALSE));
crm_free(node_lh);
} else {
/* error, rsc marked as unrunnable above */
pe_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_action_debug_3(
print_color("Removed RH", color_rh, FALSE));
crm_action_debug_3(
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_action_debug_3(
print_node("Removed RH", node_rh, FALSE));
crm_action_debug_3(
print_color("Modified RH", color_rh, FALSE));
crm_free(node_rh);
} else {
/* error, rsc marked as unrunnable above */
pe_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_debug_5("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, color_t *no_color)
{
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_debug_3("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) {
pe_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 = copy_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_debug_3("Colored resource %s with new color %d",
rsc->id, native_data->color->id);
crm_action_debug_3(
print_resource("Colored Resource", rsc, TRUE));
} else {
pe_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) {
pe_err("Node not found - cant update");
return;
}
if(node_rh->weight >= INFINITY && cons->weight == -INFINITY) {
pe_err("Constraint %s mixes +/- INFINITY", cons->id);
} else if(node_rh->weight <= -INFINITY && cons->weight == INFINITY) {
pe_err("Constraint %s mixes +/- INFINITY", cons->id);
}
if(node_rh->fixed) {
/* warning */
crm_debug_2("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_debug_3("Constraint %s (%f): node %s weight %f.",
cons->id,
cons->weight,
node_rh->details->uname,
node_rh->weight);
} else if(cons->weight == -INFINITY) {
crm_debug_3("Constraint %s (-INFINITY): node %s weight %f.",
cons->id,
node_rh->details->uname,
node_rh->weight);
} else {
crm_debug_3("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_action_debug_3(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_action_debug_3(print_resource("Filtering nodes for", rsc, FALSE));
slist_iter(
node, node_t, native_data->allowed_nodes, lpc,
if(node == NULL) {
pe_err("Invalid NULL node");
} else if(node->weight < 0.0
|| node->details->shutdown
|| node->details->online == FALSE
|| node->details->type == node_ping) {
crm_action_debug_3(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.c b/crm/pengine/pengine.c
index 3a6092ebfa..f7dabf3fde 100755
--- a/crm/pengine/pengine.c
+++ b/crm/pengine/pengine.c
@@ -1,307 +1,307 @@
-/* $Id: pengine.c,v 1.81 2005/06/29 10:36:54 andrew Exp $ */
+/* $Id: pengine.c,v 1.82 2005/06/29 16:43: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 <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>
crm_data_t * do_calculations(pe_working_set_t *data_set, crm_data_t *xml_input);
gboolean was_processing_error = FALSE;
gboolean was_processing_warning = FALSE;
gboolean
process_pe_message(HA_Message *msg, crm_data_t * xml_data, IPC_Channel *sender)
{
const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO);
const char *op = cl_get_string(msg, F_CRM_TASK);
const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE);
crm_debug_3("Processing %s op (ref=%s)...", op, ref);
if(op == NULL){
/* error */
} else if(strcmp(op, CRM_OP_HELLO) == 0) {
/* ignore */
} else if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE),
XML_ATTR_RESPONSE)) {
/* ignore */
} else if(sys_to == NULL || strcmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
crm_debug_3("Bad sys-to %s", crm_str(sys_to));
return FALSE;
} else if(strcmp(op, CRM_OP_PECALC) == 0) {
pe_working_set_t data_set;
crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB);
crm_data_t *status = get_object_root(
XML_CIB_TAG_STATUS, xml_data);
crm_data_t *log_input = status;
log_input = xml_data;
copy_in_properties(generation, xml_data);
crm_log_xml_info(generation, "[generation]");
#if 0
char *xml_buffer = NULL;
char *xml_buffer_ptr = NULL;
int max_xml = MAXLINE - 8;
xml_buffer = dump_xml_unformatted(generation);
LogToCircularBuffer(input_buffer, LOG_INFO,
"Generation: %s", xml_buffer);
crm_free(xml_buffer);
xml_buffer = dump_xml_unformatted(status);
xml_buffer_ptr = xml_buffer;
while(xml_buffer_ptr != NULL) {
LogToCircularBuffer(input_buffer, LOG_INFO,
"PE xml: %s", xml_buffer_ptr);
if(strlen(xml_buffer_ptr) > max_xml) {
xml_buffer_ptr = xml_buffer_ptr + max_xml;
} else {
xml_buffer_ptr = NULL;;
}
}
crm_free(xml_buffer);
#endif
was_processing_error = FALSE;
was_processing_warning = FALSE;
crm_zero_mem_stats(NULL);
do_calculations(&data_set, xml_data);
crm_log_xml_debug_3(data_set.graph, "[out]");
if (send_ipc_reply(sender, msg, data_set.graph) ==FALSE) {
crm_err("Answer could not be sent");
}
cleanup_calculations(&data_set);
if(is_ipc_empty(sender) && crm_mem_stats(NULL)) {
pe_warn("Unfree'd memory");
}
if(was_processing_error) {
crm_info("ERRORs found during PE processing."
" Input follows:");
crm_log_xml_info(log_input, "[input]");
} else if(was_processing_warning) {
crm_debug_2("WARNINGs found during PE processing."
" Input follows:");
crm_log_xml_debug(log_input, "[input]");
} else if(crm_log_level == LOG_DEBUG) {
crm_log_xml_debug(status, "[status]");
} else {
crm_log_xml_debug_2(log_input, "[input]");
}
free_xml(generation);
} else if(strcmp(op, CRM_OP_QUIT) == 0) {
crm_warn("Received quit message, terminating");
exit(0);
}
return TRUE;
}
-#define MEMCHECK_STAGE_0 0
+#define MEMCHECK_STAGE_8 0
crm_data_t *
do_calculations(pe_working_set_t *data_set, crm_data_t *xml_input)
{
/* pe_debug_on(); */
set_working_set_defaults(data_set);
data_set->input = xml_input;
crm_debug_5("unpack");
stage0(data_set);
#if MEMCHECK_STAGE_0
check_and_exit(0);
#endif
crm_debug_5("apply placement constraints");
stage1(data_set);
#if MEMCHECK_STAGE_1
check_and_exit(1);
#endif
crm_debug_5("color resources");
stage2(data_set);
#if MEMCHECK_STAGE_2
check_and_exit(2);
#endif
/* unused */
stage3(data_set);
#if MEMCHECK_STAGE_3
check_and_exit(3);
#endif
crm_debug_5("assign nodes to colors");
stage4(data_set);
#if MEMCHECK_STAGE_4
check_and_exit(4);
#endif
crm_debug_5("creating actions and internal ording constraints");
stage5(data_set);
#if MEMCHECK_STAGE_5
check_and_exit(5);
#endif
crm_debug_5("processing fencing and shutdown cases");
stage6(data_set);
#if MEMCHECK_STAGE_6
check_and_exit(6);
#endif
crm_debug_5("applying ordering constraints");
stage7(data_set);
#if MEMCHECK_STAGE_7
check_and_exit(7);
#endif
crm_debug_2("=#=#=#=#= Summary =#=#=#=#=");
crm_debug_2("========= All Actions =========");
slist_iter(action, action_t, data_set->actions, lpc,
log_action(LOG_DEBUG_2, "\t", action, TRUE)
);
crm_debug_2("\t========= Set %d (Un-runnable) =========", -1);
crm_action_debug_2(
slist_iter(action, action_t, data_set->actions, lpc,
if(action->optional == FALSE
&& action->runnable == FALSE
&& action->pseudo == FALSE) {
log_action(LOG_DEBUG_2, "\t", action, TRUE);
}
)
);
crm_debug_5("creating transition graph");
stage8(data_set);
#if MEMCHECK_STAGE_8
check_and_exit(8);
#endif
return data_set->graph;
}
void
cleanup_calculations(pe_working_set_t *data_set)
{
GListPtr iterator = NULL;
if(data_set == NULL) {
return;
}
crm_free(data_set->dc_uuid);
crm_debug_3("deleting order cons");
pe_free_ordering(data_set->ordering_constraints);
crm_debug_3("deleting actions");
pe_free_actions(data_set->actions);
crm_debug_3("deleting resources");
pe_free_resources(data_set->resources);
crm_debug_3("deleting nodes");
pe_free_nodes(data_set->nodes);
crm_debug_3("deleting colors");
pe_free_colors(data_set->colors);
crm_debug_3("deleting node cons");
iterator = data_set->placement_constraints;
while(iterator) {
pe_free_rsc_to_node(iterator->data);
iterator = iterator->next;
}
if(data_set->placement_constraints != NULL) {
g_list_free(data_set->placement_constraints);
}
free_xml(data_set->graph);
}
void
set_working_set_defaults(pe_working_set_t *data_set)
{
data_set->input = NULL;
data_set->graph = NULL;
data_set->dc_uuid = NULL;
data_set->dc_node = NULL;
data_set->have_quorum = FALSE;
data_set->stonith_enabled = FALSE;
data_set->symmetric_cluster = TRUE;
data_set->no_quorum_policy = no_quorum_freeze;
data_set->nodes = NULL;
data_set->resources = NULL;
data_set->ordering_constraints = NULL;
data_set->placement_constraints = NULL;
data_set->no_color = NULL;
data_set->colors = NULL;
data_set->actions = NULL;
data_set->num_synapse = 0;
data_set->max_valid_nodes = 0;
data_set->order_id = 1;
data_set->action_id = 1;
data_set->color_id = 0;
}
diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h
index 9374950de7..4ae25a1a11 100644
--- a/crm/pengine/pengine.h
+++ b/crm/pengine/pengine.h
@@ -1,396 +1,396 @@
-/* $Id: pengine.h,v 1.72 2005/06/29 09:03:52 andrew Exp $ */
+/* $Id: pengine.h,v 1.73 2005/06/29 16:43: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 <linux-ha/config.h>
#ifdef HAVE_LIBNCURSES
# include <curses.h>
#endif
typedef enum no_quorum_policy_e {
no_quorum_freeze,
no_quorum_stop,
no_quorum_ignore
} no_quorum_policy_t;
typedef struct pe_working_set_s
{
crm_data_t *input;
/* options extracted from the input */
char *dc_uuid;
node_t *dc_node;
gboolean have_quorum;
gboolean stonith_enabled;
gboolean symmetric_cluster;
int default_resource_stickiness;
no_quorum_policy_t no_quorum_policy;
/* intermediate steps */
color_t *no_color;
GListPtr nodes;
GListPtr resources;
GListPtr placement_constraints;
GListPtr ordering_constraints;
GListPtr colors;
GListPtr actions;
/* stats */
int num_synapse;
int max_valid_nodes;
int order_id;
int action_id;
int color_id;
/* final output */
crm_data_t *graph;
} pe_working_set_t;
#include <crm/pengine/complex.h>
enum con_type {
type_none,
rsc_colocation,
rsc_to_node,
rsc_to_attr,
base_weight
};
enum node_type {
node_ping,
node_member
};
enum con_strength {
pecs_ignore,
pecs_must,
pecs_must_not,
pecs_startstop
};
enum action_tasks {
no_action,
monitor_rsc,
stop_rsc,
stopped_rsc,
start_rsc,
started_rsc,
shutdown_crm,
stonith_node
};
enum rsc_recovery_type {
recovery_stop_start,
recovery_stop_only,
recovery_block
};
enum rsc_start_requirement {
rsc_req_nothing,
rsc_req_quorum,
rsc_req_stonith
};
enum pe_stop_fail {
pesf_block,
pesf_stonith,
pesf_ignore
};
enum pe_restart {
pe_restart_restart,
pe_restart_ignore
};
enum pe_ordering {
pe_ordering_manditory,
pe_ordering_restart,
pe_ordering_recover,
pe_ordering_optional
};
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* */
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;
enum rsc_recovery_type recovery_type;
enum pe_restart restart_type;
float priority;
float effective_priority;
+ gboolean is_managed;
gboolean start_pending;
gboolean recover;
gboolean starting;
gboolean stopping;
- gboolean is_stonith;
gboolean runnable;
gboolean provisional;
gboolean unclean;
GListPtr candidate_colors; /* color_t* */
GListPtr rsc_cons; /* rsc_colocation_t* */
GListPtr actions; /* action_t* */
GHashTable * parameters;
};
struct action_wrapper_s
{
enum pe_ordering type;
action_t *action;
};
enum action_fail_response {
action_fail_nothing,
action_fail_block,
action_fail_stop,
action_fail_fence
};
struct action_s
{
int id;
resource_t *rsc;
void *rsc_opaque;
node_t *node;
const char *task;
char *uuid;
crm_data_t *op_entry;
gboolean pseudo;
gboolean runnable;
gboolean optional;
gboolean failure_is_fatal;
enum rsc_start_requirement needs;
enum action_fail_response on_fail;
gboolean dumped;
gboolean processed;
int seen_count;
/* 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 pe_ordering type;
void *lh_opaque;
resource_t *lh_rsc;
action_t *lh_action;
char *lh_action_task;
void *rh_opaque;
resource_t *rh_rsc;
action_t *rh_action;
char *rh_action_task;
/* (soon to be) variant specific */
/* int lh_rsc_incarnation; */
/* int rh_rsc_incarnation; */
};
extern gboolean stage0(pe_working_set_t *data_set);
extern gboolean stage1(pe_working_set_t *data_set);
extern gboolean stage2(pe_working_set_t *data_set);
extern gboolean stage3(pe_working_set_t *data_set);
extern gboolean stage4(pe_working_set_t *data_set);
extern gboolean stage5(pe_working_set_t *data_set);
extern gboolean stage6(pe_working_set_t *data_set);
extern gboolean stage7(pe_working_set_t *data_set);
extern gboolean stage8(pe_working_set_t *data_set);
extern gboolean summary(GListPtr resources);
extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data);
extern gboolean process_pe_message(
HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender);
extern gboolean unpack_constraints(
crm_data_t *xml_constraints, pe_working_set_t *data_set);
extern gboolean unpack_resources(
crm_data_t *xml_resources, pe_working_set_t *data_set);
extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set);
extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set);
extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set);
extern gboolean apply_placement_constraints(pe_working_set_t *data_set);
extern void color_resource(resource_t *lh_resource, pe_working_set_t *data_set);
extern gboolean choose_node_from_list(color_t *color);
extern gboolean update_action_states(GListPtr actions);
extern gboolean shutdown_constraints(
node_t *node, action_t *shutdown_op, pe_working_set_t *data_set);
extern gboolean stonith_constraints(
node_t *node, action_t *stonith_op, action_t *shutdown_op,
pe_working_set_t *data_set);
extern gboolean custom_action_order(
resource_t *lh_rsc, char *lh_task, action_t *lh_action,
resource_t *rh_rsc, char *rh_task, action_t *rh_action,
enum pe_ordering type, pe_working_set_t *data_set);
#define order_start_start(rsc1,rsc2, type) \
custom_action_order(rsc1, start_key(rsc1), NULL, \
rsc2, start_key(rsc2) ,NULL, \
type, data_set)
#define order_stop_stop(rsc1, rsc2, type) \
custom_action_order(rsc1, stop_key(rsc1), NULL, \
rsc2, stop_key(rsc2) ,NULL, \
type, data_set)
#define order_restart(rsc1) \
custom_action_order(rsc1, stop_key(rsc1), NULL, \
rsc1, start_key(rsc1), NULL, \
pe_ordering_restart, data_set)
#define order_stop_start(rsc1, rsc2, type) \
custom_action_order(rsc1, stop_key(rsc1), NULL, \
rsc2, start_key(rsc2) ,NULL, \
type, data_set)
#define order_start_stop(rsc1, rsc2, type) \
custom_action_order(rsc1, start_key(rsc1), NULL, \
rsc2, stop_key(rsc2) ,NULL, \
type, data_set)
#define pe_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); }
#define pe_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); }
#define check_and_exit(stage) cleanup_calculations(data_set); \
crm_mem_stats(NULL); \
crm_err("Exiting: stage %d", stage); \
exit(1);
extern gboolean process_colored_constraints(resource_t *rsc);
extern void graph_element_from_action(
action_t *action, pe_working_set_t *data_set);
extern void set_working_set_defaults(pe_working_set_t *data_set);
extern void cleanup_calculations(pe_working_set_t *data_set);
extern const char* transition_idle_timeout;
extern gboolean was_processing_error;
extern gboolean was_processing_warning;
#endif
diff --git a/crm/pengine/regression.core.sh b/crm/pengine/regression.core.sh
index 95565c4825..4ab088e36c 100755
--- a/crm/pengine/regression.core.sh
+++ b/crm/pengine/regression.core.sh
@@ -1,140 +1,149 @@
#!/bin/bash
# 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
#
verbose=$1
io_dir=testcases
diff_opts="--ignore-all-space -U 1 -u"
failed=.regression.failed
# zero out the error log
> $failed
function do_test {
base=$1;
name=$2;
input=$io_dir/${base}.xml
output=$io_dir/${base}.pe.out
te_output=$io_dir/${base}.te.out
expected=$io_dir/${base}.exp
te_expected=$io_dir/${base}.te.exp
if [ ! -f $input ]; then
echo "Test $name ($base)... Error ($input)";
return;
fi
if [ "$create_mode" != "true" -a ! -f $expected ]; then
echo "Test $name ($base)... Error ($expected)";
# return;
fi
./ptest -V -X $input > $output
if [ -s core ]; then
echo "Test $name ($base)... Moved core to core.${base}";
rm -f core.$base
mv core core.$base
return;
fi
if [ ! -s $output ]; then
echo "Test $name ($base)... Error ($output)";
rm $output
return;
fi
if [ ! -s $output ]; then
echo "Test $name ($base)... Error (fixed $output)";
rm $output
return;
fi
if [ "$create_mode" = "true" ]; then
cp "$output" "$expected"
fi
if [ -f $expected ]; then
diff $diff_opts -q $expected $output >/dev/null
rc=$?
fi
if [ "$create_mode" = "true" ]; then
echo "Test $name ($base)... Created expected output (PE)"
elif [ ! -f $expected ]; then
echo "==== Raw results for PE test ($base) ====" >> $failed
cat $output 2>/dev/null >> $failed
elif [ "$rc" = 0 ]; then
echo "Test $name ($base)... Passed (PE)";
elif [ "$rc" = 1 ]; then
echo "Test $name ($base)... * Failed (PE)";
diff $diff_opts $expected $output 2>/dev/null >> $failed
else
echo "Test $name ($base)... Error PE (diff: $rc)";
echo "==== Raw results for test ($base) ====" >> $failed
cat $output 2>/dev/null >> $failed
fi
if [ "$test_te" = "true" ]; then
../tengine/ttest -X $output 2> $te_output
# if [ "$create_mode" = "true" ]; then
if [ "$create_mode" = "true" -a ! -f $te_expected ]; then
cp "$te_output" "$te_expected"
fi
if [ -f $te_expected ]; then
diff $diff_opts -q $te_expected $te_output >/dev/null
rc=$?
fi
if [ "$create_mode" = "true" ]; then
echo "Test $name ($base)... Created expected output (PE)"
elif [ ! -f $te_expected ]; then
echo "==== Raw results for TE test ($base) ====" >> $failed
cat $te_output 2>/dev/null >> $failed
elif [ "$rc" = 0 ]; then
echo "Test $name ($base)... Passed (TE)";
elif [ "$rc" = 1 ]; then
echo "Test $name ($base)... * Failed (TE)";
diff $diff_opts $te_expected $te_output 2>/dev/null >> $failed
diff $diff_opts $te_expected $te_output
else
echo "Test $name ($base)... Error TE (diff: $rc)";
echo "==== Raw results for test ($base) TE ====" >> $failed
cat $te_output 2>/dev/null >> $failed
fi
fi
rm -f $output $te_output
}
+
+#function do_test {
+# base=$1;
+# input=$io_dir/${base}.xml
+# expected=$io_dir/${base}.exp
+# te_expected=$io_dir/${base}.te.exp
+# mv $input $expected $te_expected testcases.saved
+#}
+
function test_results {
if [ -s $failed ]; then
if [ "$verbose" = "-v" ]; then
echo "Results of failed tests...."
less $failed
else
echo "Results of failed tests are in $failed...."
echo "Use $0 -v to display them automatically."
fi
else
rm $failed
fi
}
diff --git a/crm/pengine/regression.sh b/crm/pengine/regression.sh
index 9749396a66..4771430dcc 100755
--- a/crm/pengine/regression.sh
+++ b/crm/pengine/regression.sh
@@ -1,157 +1,158 @@
#!/bin/bash
# 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
#
. regression.core.sh
create_mode="true"
echo Generating test outputs for these tests...
#do_test bad7
echo ""
echo Done.
echo ""
echo Performing the following tests...
create_mode="false"
do_test simple1 "Offline "
do_test simple2 "Start "
do_test simple3 "Start 2 "
do_test simple4 "Start Failed"
do_test simple6 "Stop Start "
do_test simple7 "Shutdown "
#do_test simple8 "Stonith "
#do_test simple9 "Lower version"
#do_test simple10 "Higher version"
do_test simple11 "Priority (ne)"
do_test simple12 "Priority (eq)"
echo ""
do_test rsc_dep1 "Must not "
do_test rsc_dep3 "Must "
do_test rsc_dep5 "Must not 3 "
do_test rsc_dep7 "Must 3 "
do_test rsc_dep10 "Must (but cant)"
do_test rsc_dep2 "Must (running) "
do_test rsc_dep8 "Must (running : alt) "
do_test rsc_dep4 "Must (running + move)"
do_test rsc_dep9 "Must (running + move : alt) *"
echo ""
do_test order1 "Order start 1 "
do_test order2 "Order start 2 "
do_test order3 "Order stop "
do_test order4 "Order (multiple) "
do_test order5 "Order (move) "
do_test order6 "Order (move w/ restart) "
#echo ""
#do_test agent1 "version: lt (empty)"
#do_test agent2 "version: eq "
#do_test agent3 "version: gt "
echo ""
do_test attrs1 "string: eq (and) "
do_test attrs2 "string: lt / gt (and)"
do_test attrs3 "string: ne (or) "
do_test attrs4 "string: exists "
do_test attrs5 "string: not_exists "
do_test attrs6 "is_dc: true "
do_test attrs7 "is_dc: false "
echo ""
do_test mon-rsc-1 "Schedule Monitor - start"
do_test mon-rsc-2 "Schedule Monitor - move "
do_test mon-rsc-3 "Schedule Monitor - pending start "
do_test mon-rsc-4 "Schedule Monitor - move/pending start"
echo ""
do_test rec-rsc-0 "Resource Recover - no start "
do_test rec-rsc-1 "Resource Recover - start "
do_test rec-rsc-2 "Resource Recover - monitor "
do_test rec-rsc-3 "Resource Recover - stop - ignore"
do_test rec-rsc-4 "Resource Recover - stop - block "
do_test rec-rsc-5 "Resource Recover - stop - fence "
do_test rec-rsc-6 "Resource Recover - multiple - restart"
do_test rec-rsc-7 "Resource Recover - multiple - stop "
do_test rec-rsc-8 "Resource Recover - multiple - block "
echo ""
do_test quorum-1 "No quorum - ignore"
do_test quorum-2 "No quorum - freeze"
do_test quorum-3 "No quorum - stop "
echo ""
do_test rec-node-1 "Node Recover - Startup - no fence"
do_test rec-node-2 "Node Recover - Startup - fence "
do_test rec-node-3 "Node Recover - HA down - no fence"
do_test rec-node-4 "Node Recover - HA down - fence "
do_test rec-node-5 "Node Recover - CRM down - no fence"
do_test rec-node-6 "Node Recover - CRM down - fence "
do_test rec-node-7 "Node Recover - no quorum - ignore "
do_test rec-node-8 "Node Recover - no quorum - freeze "
do_test rec-node-9 "Node Recover - no quorum - stop "
do_test rec-node-10 "Node Recover - no quorum - stop w/fence"
echo ""
-do_test rsc_location1 "Score (not running) "
-do_test rsc_location2 "Score (running) "
-do_test rsc_location3 "Score (not running/no swap)"
-do_test rsc_location4 "Score (running/swap) "
-do_test rsc_location5 "Score (running/swap 2) "
+echo "* rsc_location equivalents of rsc_colocation constraints disbaled until they are re-implemented"
+#do_test rsc_location1 "Score (not running) "
+#do_test rsc_location2 "Score (running) "
+#do_test rsc_location3 "Score (not running/no swap)"
+#do_test rsc_location4 "Score (running/swap) "
+#do_test rsc_location5 "Score (running/swap 2) "
echo ""
do_test multi1 "Multiple Active (stop/start)"
#echo ""
#do_test complex1 "Complex "
echo ""
do_test group1 "Group "
do_test group2 "Group + Native "
do_test group3 "Group + Group "
do_test group4 "Group + Native (nothing)"
do_test group5 "Group + Native (move) "
do_test group6 "Group + Group (move) "
echo ""
do_test inc0 "Incarnation start "
do_test inc1 "Incarnation start order "
do_test inc2 "Incarnation silent restart, stop, move "
do_test inc3 "Inter-incarnation ordering, silent restart, stop, move"
do_test inc4 "Inter-incarnation ordering, silent restart, stop, move (ordered)"
do_test inc5 "Inter-incarnation ordering, silent restart, stop, move (restart 1)"
do_test inc6 "Inter-incarnation ordering, silent restart, stop, move (restart 2) *"
#do_test inc7 "Inter-incarnation ordering, silent restart, stop, move (ordered subset)"
echo ""
do_test bad1 "Bad node "
do_test bad2 "Bad rsc "
do_test bad3 "No rsc class "
do_test bad4 "Bad data "
do_test bad5 "Bad data "
do_test bad6 "Bad lrm_rsc "
echo ""
do_test 594 "Bugzilla 594"
do_test 662 "Bugzilla 662"
echo ""
test_results
diff --git a/crm/pengine/unpack.c b/crm/pengine/unpack.c
index accaef3caf..1863496f1b 100644
--- a/crm/pengine/unpack.c
+++ b/crm/pengine/unpack.c
@@ -1,1212 +1,1219 @@
-/* $Id: unpack.c,v 1.100 2005/06/29 09:03:52 andrew Exp $ */
+/* $Id: unpack.c,v 1.101 2005/06/29 16:43: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>
gint sort_op_by_callid(gconstpointer a, gconstpointer b);
gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set);
gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set);
gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set);
gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set);
gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set);
gboolean unpack_lrm_rsc_state(
node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set);
gboolean add_node_attrs(
crm_data_t * attrs, node_t *node, pe_working_set_t *data_set);
gboolean unpack_rsc_op(
resource_t *rsc, node_t *node, crm_data_t *xml_op,
gboolean *running, int *max_call_id, pe_working_set_t *data_set);
gboolean determine_online_status(
crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set);
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, pe_working_set_t *data_set);
rsc_to_node_t *rsc2node_new(
const char *id, resource_t *rsc,
double weight, node_t *node, pe_working_set_t *data_set);
const char *param_value(crm_data_t * parent, const char *name);
gboolean
unpack_config(crm_data_t * config, pe_working_set_t *data_set)
{
const char *value = NULL;
value = param_value(config, "transition_idle_timeout");
if(value != NULL) {
long tmp = crm_get_msec(value);
if(tmp > 0) {
transition_idle_timeout = value;
} else {
crm_err("Invalid value for %s: %s",
"transition_idle_timeout", value);
}
}
crm_debug_4("%s set to: %s",
"transition_idle_timeout", transition_idle_timeout);
value = param_value(config, "default_resource_stickiness");
data_set->default_resource_stickiness = crm_atoi(value, "0");
switch (data_set->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;
}
value = param_value(config, "stonith_enabled");
if(value != NULL) {
crm_str_to_boolean(value, &data_set->stonith_enabled);
}
crm_info("STONITH of failed nodes is %s",
data_set->stonith_enabled?"enabled":"disabled");
value = param_value(config, "symmetric_cluster");
if(value != NULL) {
crm_str_to_boolean(value, &data_set->symmetric_cluster);
}
if(data_set->symmetric_cluster) {
crm_info("Cluster is symmetric"
" - resources can run anywhere by default");
}
value = param_value(config, "no_quorum_policy");
if(safe_str_eq(value, "ignore")) {
data_set->no_quorum_policy = no_quorum_ignore;
} else if(safe_str_eq(value, "freeze")) {
data_set->no_quorum_policy = no_quorum_freeze;
} else {
data_set->no_quorum_policy = no_quorum_stop;
}
switch (data_set->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);
}
if(a_default == NULL) {
crm_warn("Option %s not set", name);
return NULL;
}
return crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE);
}
gboolean
unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set)
{
node_t *new_node = NULL;
crm_data_t * attrs = NULL;
const char *id = NULL;
const char *uname = NULL;
const char *type = NULL;
crm_debug("Begining unpack... %s",
xml_nodes?crm_element_name(xml_nodes):"<none>");
xml_child_iter(
xml_nodes, xml_obj, XML_CIB_TAG_NODE,
new_node = NULL;
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_debug_3("Processing node %s/%s", uname, id);
attrs = find_xml_node(xml_obj, "attributes", FALSE);
if(id == NULL) {
pe_err("Must specify id tag in <node>");
continue;
}
if(type == NULL) {
pe_err("Must specify type tag in <node>");
continue;
}
crm_malloc0(new_node, sizeof(node_t));
if(new_node == NULL) {
return FALSE;
}
new_node->weight = 0;
new_node->fixed = FALSE;
crm_malloc0(new_node->details,
sizeof(struct node_shared_s));
if(new_node->details == NULL) {
crm_free(new_node);
return FALSE;
}
crm_debug_3("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->attrs = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy == no_quorum_stop) {
/* start shutting resources down */
new_node->weight = -INFINITY;
}
if(data_set->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, data_set);
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;
}
data_set->nodes = g_list_append(data_set->nodes, new_node);
crm_debug_3("Done with node %s",
crm_element_value(xml_obj, XML_ATTR_UNAME));
crm_action_debug_3(print_node("Added", new_node, FALSE));
);
data_set->nodes = g_list_sort(data_set->nodes, sort_node_weight);
return TRUE;
}
gboolean
unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set)
{
crm_debug("Begining unpack... %s",
xml_resources?crm_element_name(xml_resources):"<none>");
xml_child_iter(
xml_resources, xml_obj, NULL,
resource_t *new_rsc = NULL;
crm_debug_2("Begining unpack... %s",
xml_obj?crm_element_name(xml_obj):"<none>");
if(common_unpack(xml_obj, &new_rsc, data_set)) {
data_set->resources = g_list_append(
data_set->resources, new_rsc);
crm_action_debug_3(
print_resource("Added", new_rsc, FALSE));
} else {
pe_err("Failed unpacking %s %s",
crm_element_name(xml_obj),
crm_element_value(xml_obj, XML_ATTR_ID));
}
);
data_set->resources = g_list_sort(
data_set->resources, sort_rsc_priority);
return TRUE;
}
gboolean
unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set)
{
crm_debug("Begining unpack... %s",
xml_constraints?crm_element_name(xml_constraints):"<none>");
xml_child_iter(
xml_constraints, xml_obj, NULL,
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
if(id == NULL) {
pe_err("Constraint <%s...> must have an id",
crm_element_name(xml_obj));
continue;
}
crm_debug_3("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, data_set);
} else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND,
crm_element_name(xml_obj))) {
unpack_rsc_colocation(xml_obj, data_set);
} else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION,
crm_element_name(xml_obj))) {
unpack_rsc_location(xml_obj, data_set);
} else {
pe_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, node_t *node, pe_working_set_t *data_set)
{
rsc_to_node_t *new_con = NULL;
if(rsc == NULL || id == NULL) {
pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
return NULL;
}
crm_malloc0(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) {
node_t *copy = node_copy(node);
new_con->node_list_rh = g_list_append(NULL, copy);
}
data_set->placement_constraints = g_list_append(
data_set->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, pe_working_set_t *data_set)
{
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_debug_3("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_debug_3("Processing node %s", uname);
this_node = pe_find_node(data_set->nodes, uname);
if(uname == NULL) {
/* error */
continue;
} else if(this_node == NULL) {
pe_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_debug_3("Adding runtime node attrs");
add_node_attrs(node_state, this_node, data_set);
crm_debug_3("determining node state");
determine_online_status(node_state, this_node, data_set);
if(this_node->details->online || data_set->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_debug_3("Processing lrm resource entries");
unpack_lrm_rsc_state(this_node, lrm_rsc, data_set);
}
);
return TRUE;
}
gboolean
determine_online_status(
crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set)
{
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(data_set->stonith_enabled == FALSE) {
if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){
crm_debug_2("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_neq(join_state, CRMD_JOINSTATE_DOWN)
&& safe_str_eq(crm_state, ONLINESTATUS)) {
online = TRUE;
} else if(this_node->details->expected_up == FALSE) {
crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s",
crm_str(ha_state), crm_str(ccm_state));
crm_debug_2("\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;
pe_err("Node %s is partially & un-expectedly down",
uname);
crm_debug_2("\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(crm_state, ONLINESTATUS)
&& safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)) {
online = TRUE;
} else if(this_node->details->expected_up == FALSE) {
crm_debug_2("CRMd on %s is down: ha_state=%s, ccm_state=%s",
uname, crm_str(ha_state), crm_str(ccm_state));
crm_debug_2("\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;
pe_err("Node %s is un-expectedly down", uname);
crm_debug_2("\tha_state=%s, ccm_state=%s",
crm_str(ha_state), crm_str(ccm_state));
crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s",
crm_str(crm_state), crm_str(join_state),
crm_str(exp_state));
}
}
if(online) {
crm_debug_2("Node %s is online", uname);
this_node->details->online = TRUE;
} else {
/* remove node from contention */
crm_debug_2("Node %s is down", uname);
this_node->weight = -INFINITY;
this_node->fixed = TRUE;
}
if(this_node->details->unclean) {
pe_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_2("Node %s is due for shutdown", uname);
}
return online;
}
gboolean
unpack_lrm_rsc_state(node_t *node, crm_data_t * lrm_rsc_list,
pe_working_set_t *data_set)
{
const char *rsc_id = NULL;
const char *node_id = node->details->uname;
const char *rsc_state = NULL;
int max_call_id = -1;
gboolean running = FALSE;
resource_t *rsc = NULL;
GListPtr op_list = NULL;
GListPtr sorted_op_list = NULL;
CRM_DEV_ASSERT(node != NULL);
if(crm_assert_failed) {
return FALSE;
}
xml_child_iter(
lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE,
rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
rsc_state = crm_element_value(rsc_entry, XML_LRM_ATTR_RSCSTATE);
rsc = pe_find_resource(data_set->resources, rsc_id);
crm_debug_3("[%s] Processing %s on %s (%s)",
crm_element_name(rsc_entry),
rsc_id, node_id, rsc_state);
if(rsc == NULL) {
pe_err("Could not find a match for resource"
" %s in %s's status section",
rsc_id, node_id);
crm_log_xml_debug(rsc_entry, "Invalid status entry");
continue;
}
running = FALSE;
max_call_id = -1;
op_list = NULL;
sorted_op_list = NULL;
xml_child_iter(
rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
op_list = g_list_append(op_list, rsc_op);
);
if(op_list == NULL) {
continue;
}
sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
slist_iter(
rsc_op, crm_data_t, sorted_op_list, lpc,
unpack_rsc_op(rsc, node, rsc_op,
&running, &max_call_id, data_set);
);
/* no need to free the contents */
g_list_free(sorted_op_list);
if(running) {
- native_add_running(rsc, node);
+ native_add_running(rsc, node, data_set);
}
);
return TRUE;
}
gint
sort_op_by_callid(gconstpointer a, gconstpointer b)
{
const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID);
const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID);
/* if task id is NULL, then its a pending op
* put pending ops last
*/
int a_id = -1;
int b_id = -1;
if(a_task_id == NULL && b_task_id == NULL) { return 0; }
/* the reverse from normal so that NULLs appear last */
if(a_task_id == NULL) { return -1; }
if(b_task_id == NULL) { return 1; }
a_id = atoi(a_task_id);
b_id = atoi(b_task_id);
if(a_id < b_id) {
return -1;
} else if(a_id > b_id) {
return 1;
}
return 0;
}
gboolean
unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op,
gboolean *running, int *max_call_id, pe_working_set_t *data_set)
{
const char *id = NULL;
const char *task = NULL;
const char *task_id = NULL;
const char *task_status = NULL;
int task_id_i = -1;
int task_status_i = -2;
action_t *action = NULL;
gboolean is_stop_action = FALSE;
CRM_DEV_ASSERT(rsc != NULL); if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(xml_op != NULL); if(crm_assert_failed) { return FALSE; }
id = ID(xml_op);
task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
task_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
CRM_DEV_ASSERT(id != NULL);
if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(task != NULL);
if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(task_status != NULL);
if(crm_assert_failed) { return FALSE; }
task_status_i = atoi(task_status);
CRM_DEV_ASSERT(task_status_i <= LRM_OP_ERROR);
if(crm_assert_failed) {return FALSE;}
CRM_DEV_ASSERT(task_status_i >= LRM_OP_PENDING);
if(crm_assert_failed) {return FALSE;}
if(safe_str_eq(task, CRMD_ACTION_STOP)) {
is_stop_action = TRUE;
}
if(task_status_i != LRM_OP_PENDING) {
task_id_i = crm_atoi(task_id, "-1");
CRM_DEV_ASSERT(task_id != NULL);
if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(task_id_i >= 0);
if(crm_assert_failed) { return FALSE; }
if(task_id_i == *max_call_id) {
crm_debug_2("Already processed this call");
return TRUE;
}
CRM_DEV_ASSERT(task_id_i > *max_call_id);
if(crm_assert_failed) { return FALSE; }
}
if(*max_call_id < task_id_i) {
*max_call_id = task_id_i;
}
if(node->details->unclean) {
crm_debug_2("Node %s (where %s is running) is unclean."
" Further action depends on the value of %s",
node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL);
}
switch(task_status_i) {
case LRM_OP_PENDING:
/*
* 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(is_stop_action) {
/* re-issue the stop and return */
stop_action(rsc, node, FALSE);
*running = TRUE;
rsc->recover = TRUE;
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
rsc->start_pending = TRUE;
*running = TRUE;
/* make sure it is re-issued but,
* only if we have quorum
*/
if(data_set->have_quorum == TRUE
|| data_set->no_quorum_policy == no_quorum_ignore){
/* do not specify the node, we may want
* to start it elsewhere
*/
start_action(rsc, NULL, FALSE);
}
} else if(*running == TRUE) {
crm_debug_4("Re-issuing pending recurring task:"
" %s for %s on %s",
task, rsc->id, node->details->id);
custom_action(rsc, crm_strdup(id),
task, node, FALSE, data_set);
}
break;
case LRM_OP_DONE:
crm_debug_3("%s/%s completed on %s",
rsc->id, task, node->details->uname);
if(is_stop_action) {
*running = FALSE;
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
crm_debug_3("%s active on %s",
rsc->id, node->details->uname);
*running = TRUE;
}
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
crm_debug_2("Processing failed op (%s) for %s on %s",
task, rsc->id, node->details->uname);
action = custom_action(
rsc, crm_strdup(id), task, NULL, TRUE, data_set);
if(action->on_fail == action_fail_nothing) {
/* pretend the op completed */
if(is_stop_action) {
*running = FALSE;
} else {
*running = TRUE;
}
break;
}
if(task_status_i == LRM_OP_NOTSUPPORTED
|| is_stop_action
|| safe_str_eq(task, CRMD_ACTION_START) ) {
crm_warn("Handling failed %s for %s on %s",
task, rsc->id, node->details->uname);
rsc2node_new("dont_run__failed_stopstart",
rsc, -INFINITY, node, data_set);
}
if(action->on_fail == action_fail_fence) {
/* treat it as if it is still running
* but also mark the node as unclean
*/
rsc->unclean = TRUE;
node->details->unclean = TRUE;
stop_action(rsc, node, FALSE);
*running = TRUE;
} else if(action->on_fail == action_fail_block) {
/* let this depend on the stop action
* which will fail but make sure the
* transition continues...
*/
rsc->unclean = TRUE;
*running = TRUE;
} else if(action->on_fail == action_fail_stop) {
*running = TRUE;
stop_action(rsc, node, FALSE);
}
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
pe_err("Dont know what to do for cancelled ops yet");
break;
}
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_malloc0(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_debug_4("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_debug_4("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;
}
/* LHS before RHS */
gboolean
custom_action_order(
resource_t *lh_rsc, char *lh_action_task, action_t *lh_action,
resource_t *rh_rsc, char *rh_action_task, action_t *rh_action,
enum pe_ordering type, pe_working_set_t *data_set)
{
order_constraint_t *order = NULL;
if((lh_action == NULL && lh_rsc == NULL)
|| (rh_action == NULL && rh_rsc == NULL)){
pe_err("Invalid inputs lh_rsc=%p, lh_a=%p,"
" rh_rsc=%p, rh_a=%p",
lh_rsc, lh_action, rh_rsc, rh_action);
crm_free(lh_action_task);
crm_free(rh_action_task);
return FALSE;
}
crm_malloc0(order, sizeof(order_constraint_t));
if(order == NULL) { return FALSE; }
order->id = data_set->order_id++;
order->type = type;
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;
data_set->ordering_constraints = g_list_append(
data_set->ordering_constraints, order);
if(lh_rsc != NULL && rh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" %s/%s before %s/%s",
order->id, ordering_type2text(order->type),
lh_rsc->id, lh_action_task,
rh_rsc->id, rh_action_task);
} else if(lh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" %s/%s before action %d (%s)",
order->id, ordering_type2text(order->type),
lh_rsc->id, lh_action_task,
rh_action->id, rh_action_task);
} else if(rh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" action %d (%s) before %s/%s",
order->id, ordering_type2text(order->type),
lh_action->id, lh_action_task,
rh_rsc->id, rh_action_task);
} else {
crm_debug_4("Created ordering constraint %d (%s):"
" action %d (%s) before action %d (%s)",
order->id, ordering_type2text(order->type),
lh_action->id, lh_action_task,
rh_action->id, rh_action_task);
}
return TRUE;
}
gboolean
unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set)
{
enum con_strength strength_e = pecs_ignore;
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 *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh);
resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh);
if(rsc_lh == NULL) {
pe_err("No resource (con=%s, rsc=%s)", id, id_lh);
return FALSE;
} else if(rsc_rh == NULL) {
pe_err("No resource (con=%s, rsc=%s)", id, id_rh);
return FALSE;
}
/* the docs indicate that only +/- INFINITY are allowed,
* but no-one ever reads the docs so all positive values will
* count as "must" and negative values as "must not"
*/
if(score == NULL || score[0] != '-') {
strength_e = pecs_must;
} else {
strength_e = pecs_must_not;
}
return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh);
}
gboolean
unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set)
{
gboolean type_is_after = TRUE;
gboolean action_is_start = TRUE;
gboolean symmetrical_bool = TRUE;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE);
const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
const char *symmetrical = crm_element_value(
xml_obj, XML_CONS_ATTR_SYMMETRICAL);
resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh);
resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh);
if(xml_obj == NULL) {
pe_err("No constraint object to process.");
return FALSE;
} else if(id == NULL) {
pe_err("%s constraint must have an id",
crm_element_name(xml_obj));
return FALSE;
} else if(rsc_lh == NULL || rsc_rh == NULL) {
pe_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, task2text(stop_rsc))) {
action_is_start = FALSE;
}
if((type_is_after && action_is_start)
|| (type_is_after == FALSE && action_is_start == FALSE)){
if(symmetrical_bool || action_is_start == FALSE) {
if(rsc_lh->restart_type == pe_restart_restart){
order_stop_stop(rsc_lh, rsc_rh, pe_ordering_recover);
}
order_stop_stop(rsc_lh, rsc_rh, pe_ordering_optional);
}
if(symmetrical_bool || action_is_start) {
if(rsc_lh->restart_type == pe_restart_restart){
order_start_start(rsc_rh, rsc_lh, pe_ordering_recover);
}
order_start_start(rsc_rh, rsc_lh, pe_ordering_optional);
}
} else {
if(symmetrical_bool || action_is_start == FALSE) {
if(rsc_rh->restart_type == pe_restart_restart){
order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover);
}
order_stop_stop(rsc_rh, rsc_lh, pe_ordering_optional);
}
if(symmetrical_bool || action_is_start) {
if(rsc_rh->restart_type == pe_restart_restart){
order_start_start(rsc_lh, rsc_rh, pe_ordering_recover);
}
order_start_start(rsc_lh, rsc_rh, pe_ordering_optional);
}
}
return TRUE;
}
gboolean
add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set)
{
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, data_set->dc_uuid)) {
data_set->dc_node = node;
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, pe_working_set_t *data_set)
{
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(data_set->resources, id_lh);
if(rsc_lh == NULL) {
pe_warn("No resource (con=%s, rsc=%s)", id, id_lh);
return FALSE;
+
+ } else if(rsc_lh->is_managed == FALSE) {
+ crm_debug_2(
+ "Ignoring constraint %s: resource %s is not managed",
+ id, id_lh);
+ return FALSE;
}
+
xml_child_iter(
xml_obj, rule, XML_TAG_RULE,
gboolean first_expr = TRUE;
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;
}
new_con = rsc2node_new(rule_id, rsc_lh, score_f,NULL,data_set);
if(new_con == NULL) {
continue;
}
crm_debug_5("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_debug_5("processing expression: %s",
crm_element_value(expr, XML_ATTR_ID));
match_L = apply_node_expression(
attr, op, value, type, data_set->nodes);
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_debug_5("do_and");
new_con->node_list_rh = node_list_and(
old_list, match_L, FALSE);
} else {
crm_debug_5("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
&& data_set->symmetric_cluster == FALSE) {
/* feels like a hack */
crm_debug_4("Rule %s had no expressions,"
" adding all nodes", crm_element_value(rule, XML_ATTR_ID));
new_con->node_list_rh = node_list_dup(
data_set->nodes, FALSE);
}
if(new_con->node_list_rh == NULL) {
crm_debug_2("No matching nodes for constraint/rule %s/%s",
id, crm_element_value(rule, XML_ATTR_ID));
}
crm_action_debug_3(print_rsc_to_node("Added", new_con, FALSE));
);
if(were_rules == FALSE) {
crm_debug_2("no rules for constraint %s", id);
}
return TRUE;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 3:10 AM (23 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009869
Default Alt Text
(130 KB)

Event Timeline