Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639565
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
130 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment