diff --git a/crm/pengine/testcases/inc10.exp b/crm/pengine/testcases/inc10.exp
index 5245497857..62a0d78078 100644
--- a/crm/pengine/testcases/inc10.exp
+++ b/crm/pengine/testcases/inc10.exp
@@ -1,235 +1,235 @@
-
+
-
+
-
+
diff --git a/lib/crm/pengine/status.c b/lib/crm/pengine/status.c
index e353a38378..c896446302 100644
--- a/lib/crm/pengine/status.c
+++ b/lib/crm/pengine/status.c
@@ -1,280 +1,281 @@
-/* $Id: status.c,v 1.4 2006/06/08 16:53:01 andrew Exp $ */
+/* $Id: status.c,v 1.5 2006/06/21 15:56:49 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
crm_data_t * do_calculations(
pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now);
unsigned int pengine_input_loglevel = LOG_INFO;
#define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine"
#define MEMCHECK_STAGE_0 0
#define check_and_exit(stage) cleanup_calculations(data_set); \
crm_mem_stats(NULL); \
crm_err("Exiting: stage %d", stage); \
exit(1);
/*
* Unpack everything
* At the end you'll have:
* - A list of nodes
* - A list of resources (each with any dependencies on other resources)
* - A list of constraints between resources and nodes
* - A list of constraints between start/stop actions
* - A list of nodes that need to be stonith'd
* - A list of nodes that need to be shutdown
* - A list of the possible stop/start actions (without dependencies)
*/
gboolean
cluster_status(pe_working_set_t *data_set)
{
crm_data_t * config = get_object_root(
XML_CIB_TAG_CRMCONFIG, data_set->input);
crm_data_t * cib_nodes = get_object_root(
XML_CIB_TAG_NODES, data_set->input);
crm_data_t * cib_resources = get_object_root(
XML_CIB_TAG_RESOURCES, data_set->input);
crm_data_t * cib_status = get_object_root(
XML_CIB_TAG_STATUS, data_set->input);
const char *value = crm_element_value(
data_set->input, XML_ATTR_HAVE_QUORUM);
crm_debug_3("Beginning unpack");
/* reset remaining global variables */
if(data_set->input == NULL) {
return FALSE;
}
if(data_set->input != NULL
&& crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) {
/* this should always be present */
data_set->dc_uuid = crm_element_value_copy(
data_set->input, XML_ATTR_DC_UUID);
}
unpack_config(config, data_set);
if(value != NULL) {
cl_str_to_boolean(value, &data_set->have_quorum);
}
if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy != no_quorum_ignore) {
crm_warn("We do not have quorum"
" - fencing and resource management disabled");
}
unpack_nodes(cib_nodes, data_set);
unpack_resources(cib_resources, data_set);
unpack_status(cib_status, data_set);
return TRUE;
}
static void
pe_free_resources(GListPtr resources)
{
resource_t *rsc = NULL;
GListPtr iterator = resources;
while(iterator != NULL) {
iterator = iterator;
rsc = (resource_t *)iterator->data;
iterator = iterator->next;
rsc->fns->free(rsc);
}
if(resources != NULL) {
g_list_free(resources);
}
}
static void
pe_free_actions(GListPtr actions)
{
GListPtr iterator = actions;
while(iterator != NULL) {
pe_free_action(iterator->data);
iterator = iterator->next;
}
if(actions != NULL) {
g_list_free(actions);
}
}
static void
pe_free_nodes(GListPtr nodes)
{
GListPtr iterator = nodes;
while(iterator != NULL) {
node_t *node = (node_t*)iterator->data;
struct node_shared_s *details = node->details;
iterator = iterator->next;
crm_debug_5("deleting node");
crm_debug_5("%s is being deleted", details->uname);
print_node("delete", node, FALSE);
if(details != NULL) {
if(details->attrs != NULL) {
g_hash_table_destroy(details->attrs);
}
pe_free_shallow_adv(details->running_rsc, FALSE);
crm_free(details);
}
crm_free(node);
}
if(nodes != NULL) {
g_list_free(nodes);
}
}
void
cleanup_calculations(pe_working_set_t *data_set)
{
if(data_set == NULL) {
return;
}
if(data_set->config_hash != NULL) {
g_hash_table_destroy(data_set->config_hash);
}
crm_free(data_set->dc_uuid);
crm_free(data_set->transition_idle_timeout);
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);
free_xml(data_set->graph);
free_ha_date(data_set->now);
free_xml(data_set->input);
data_set->stonith_action = NULL;
CRM_CHECK(data_set->colors == NULL, ;);
CRM_CHECK(data_set->ordering_constraints == NULL, ;);
CRM_CHECK(data_set->placement_constraints == NULL, ;);
}
void
set_working_set_defaults(pe_working_set_t *data_set)
{
data_set->input = NULL;
data_set->now = NULL;
data_set->graph = NULL;
data_set->transition_idle_timeout = crm_strdup("60s");
data_set->dc_uuid = NULL;
data_set->dc_node = NULL;
data_set->have_quorum = FALSE;
data_set->stonith_enabled = FALSE;
data_set->stonith_action = NULL;
data_set->symmetric_cluster = TRUE;
data_set->is_managed_default = TRUE;
data_set->no_quorum_policy = no_quorum_freeze;
data_set->remove_after_stop = FALSE;
data_set->stop_action_orphans = TRUE;
data_set->stop_rsc_orphans = TRUE;
data_set->config_hash = NULL;
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;
data_set->default_resource_stickiness = 0;
data_set->default_resource_fail_stickiness = 0;
}
resource_t *
pe_find_resource(GListPtr rsc_list, const char *id)
{
unsigned lpc = 0;
resource_t *rsc = NULL;
resource_t *child_rsc = NULL;
if(id == NULL) {
return NULL;
}
crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list));
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
if(rsc == NULL) {
} else if(safe_str_eq(rsc->id, id)){
crm_debug_4("Found a match for %s", id);
return rsc;
} else if(safe_str_eq(rsc->long_name, id)) {
crm_debug_4("Found a match for %s", id);
return rsc;
+
+ } else if(safe_str_eq(rsc->clone_name, id)) {
+ crm_debug_4("Found a match for %s", id);
+ return rsc;
}
}
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
child_rsc = rsc->fns->find_child(rsc, id);
if(child_rsc != NULL) {
- crm_debug_4("Found a match for %s in %s",
- id, rsc->id);
-
return child_rsc;
}
}
crm_debug_2("No match for %s", id);
return NULL;
}
diff --git a/lib/crm/pengine/unpack.c b/lib/crm/pengine/unpack.c
index f06ea0bcca..5b7d5e8b30 100644
--- a/lib/crm/pengine/unpack.c
+++ b/lib/crm/pengine/unpack.c
@@ -1,1216 +1,1222 @@
-/* $Id: unpack.c,v 1.8 2006/06/21 14:48:01 andrew Exp $ */
+/* $Id: unpack.c,v 1.9 2006/06/21 15:56:49 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include /* for ONLINESTATUS */
#include
#include
#include
#include
#define get_cluster_pref(pref) value = g_hash_table_lookup(config_hash, pref); \
if(value == NULL) { \
pe_config_warn("No value specified for cluster preference: %s", pref); \
}
gboolean
unpack_config(crm_data_t * config, pe_working_set_t *data_set)
{
const char *name = NULL;
const char *value = NULL;
GHashTable *config_hash = g_hash_table_new_full(
g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str);
data_set->config_hash = config_hash;
unpack_instance_attributes(
config, XML_CIB_TAG_PROPSET, NULL, config_hash,
CIB_OPTIONS_FIRST, data_set->now);
#if CRM_DEPRECATED_SINCE_2_0_1
xml_child_iter_filter(
config, a_child, XML_CIB_TAG_NVPAIR,
name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME);
value = crm_element_value(a_child, XML_NVPAIR_ATTR_VALUE);
if(g_hash_table_lookup(config_hash, name) == NULL) {
g_hash_table_insert(
config_hash,crm_strdup(name),crm_strdup(value));
}
pe_config_err("Creating directly"
"beneath has been depreciated since"
" 2.0.1", ID(a_child), name);
);
#else
xml_child_iter_filter(
config, a_child, XML_CIB_TAG_NVPAIR,
name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME);
pe_config_err("Creating directly"
"beneath has been depreciated since"
" 2.0.1 and is now disabled", ID(a_child), name);
);
#endif
get_cluster_pref("default_action_timeout");
if(value == NULL) {
get_cluster_pref("transition_idle_timeout");
}
if(value != NULL) {
long tmp = crm_get_msec(value);
if(tmp > 0) {
crm_free(data_set->transition_idle_timeout);
data_set->transition_idle_timeout = crm_strdup(value);
} else {
crm_err("Invalid value for default_action_timeout: %s",
value);
}
}
crm_debug("default_action_timeout set to: %s", data_set->transition_idle_timeout);
get_cluster_pref("default_"XML_RSC_ATTR_STICKINESS);
data_set->default_resource_stickiness = char2score(value);
crm_info("Default stickiness: %d",
data_set->default_resource_stickiness);
get_cluster_pref("default_"XML_RSC_ATTR_FAIL_STICKINESS);
data_set->default_resource_fail_stickiness = char2score(value);
crm_info("Default failure stickiness: %d",
data_set->default_resource_fail_stickiness);
get_cluster_pref("stonith_enabled");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->stonith_enabled);
}
crm_info("STONITH of failed nodes is %s",
data_set->stonith_enabled?"enabled":"disabled");
get_cluster_pref("stonith_action");
if(value == NULL || safe_str_neq(value, "poweroff")) {
value = "reboot";
}
data_set->stonith_action = value;
crm_info("STONITH will %s nodes", data_set->stonith_action);
get_cluster_pref("symmetric_cluster");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->symmetric_cluster);
}
if(data_set->symmetric_cluster) {
crm_info("Cluster is symmetric"
" - resources can run anywhere by default");
}
get_cluster_pref("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_notice("On loss of CCM Quorum: Ignore");
break;
}
get_cluster_pref("stop_orphan_resources");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->stop_rsc_orphans);
}
crm_info("Orphan resources are %s",
data_set->stop_rsc_orphans?"stopped":"ignored");
get_cluster_pref("stop_orphan_actions");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->stop_action_orphans);
}
crm_info("Orphan resource actions are %s",
data_set->stop_action_orphans?"stopped":"ignored");
get_cluster_pref("remove_after_stop");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->remove_after_stop);
}
crm_info("Stopped resources are removed from the status section: %s",
data_set->remove_after_stop?"true":"false");
get_cluster_pref("is_managed_default");
if(value != NULL) {
cl_str_to_boolean(value, &data_set->is_managed_default);
}
crm_info("By default resources are %smanaged",
data_set->is_managed_default?"":"not ");
return TRUE;
}
gboolean
unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set)
{
node_t *new_node = NULL;
const char *id = NULL;
const char *uname = NULL;
const char *type = NULL;
crm_debug_2("Begining unpack... %s",
xml_nodes?crm_element_name(xml_nodes):"");
xml_child_iter_filter(
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);
if(id == NULL) {
pe_config_err("Must specify id tag in ");
continue;
}
if(type == NULL) {
pe_config_err("Must specify type tag in ");
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(type == NULL
|| safe_str_eq(type, "member")
|| safe_str_eq(type, NORMALNODE)) {
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;
new_node->details->standby = TRUE;
}
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));
);
return TRUE;
}
gboolean
unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set)
{
crm_debug_2("Begining unpack... %s",
xml_resources?crm_element_name(xml_resources):"");
xml_child_iter(
xml_resources, xml_obj,
resource_t *new_rsc = NULL;
crm_debug_2("Begining unpack... %s",
xml_obj?crm_element_name(xml_obj):"");
if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) {
data_set->resources = g_list_append(
data_set->resources, new_rsc);
print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE);
} else {
pe_config_err("Failed unpacking %s %s",
crm_element_name(xml_obj),
crm_element_value(xml_obj, XML_ATTR_ID));
if(new_rsc != NULL && new_rsc->fns != NULL) {
new_rsc->fns->free(new_rsc);
}
}
);
data_set->resources = g_list_sort(
data_set->resources, sort_rsc_priority);
return TRUE;
}
/* 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 *id = NULL;
const char *uname = NULL;
crm_data_t * lrm_rsc = NULL;
crm_data_t * attrs = NULL;
node_t *this_node = NULL;
crm_debug_3("Begining unpack");
xml_child_iter_filter(
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_TAG_TRANSIENT_NODEATTRS, FALSE);
lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, 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_id(data_set->nodes, id);
if(uname == NULL) {
/* error */
continue;
} else if(this_node == NULL) {
pe_config_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(attrs, 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_resources(this_node, lrm_rsc, data_set);
}
);
return TRUE;
}
static gboolean
determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node)
{
gboolean online = FALSE;
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 *exp_state = crm_element_value(node_state,
XML_CIB_ATTR_EXPSTATE);
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;
crm_warn("Node %s is partially & un-expectedly down",
this_node->details->uname);
crm_info("\tha_state=%s, ccm_state=%s,"
" crm_state=%s, join_state=%s, expected=%s",
crm_str(ha_state), crm_str(ccm_state),
crm_str(crm_state), crm_str(join_state),
crm_str(exp_state));
}
return online;
}
static gboolean
determine_online_status_fencing(crm_data_t * node_state, node_t *this_node)
{
gboolean online = FALSE;
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 *exp_state = crm_element_value(node_state,
XML_CIB_ATTR_EXPSTATE);
if(crm_is_true(ccm_state)
&& (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS))
&& safe_str_eq(crm_state, ONLINESTATUS)
&& safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
online = TRUE;
} else if(crm_is_true(ccm_state) == FALSE
/* && safe_str_eq(ha_state, DEADSTATUS) */
&& safe_str_eq(crm_state, OFFLINESTATUS)
&& this_node->details->expected_up == FALSE) {
crm_debug("Node %s is down: join_state=%s, expected=%s",
this_node->details->uname,
crm_str(join_state), crm_str(exp_state));
} else if(this_node->details->expected_up == FALSE) {
crm_info("Node %s is comming up", this_node->details->uname);
crm_debug("\tha_state=%s, ccm_state=%s,"
" crm_state=%s, join_state=%s, expected=%s",
crm_str(ha_state), crm_str(ccm_state),
crm_str(crm_state), crm_str(join_state),
crm_str(exp_state));
} else {
/* mark it unclean */
this_node->details->unclean = TRUE;
crm_warn("Node %s (%s) is un-expectedly down",
this_node->details->uname, this_node->details->id);
crm_info("\tha_state=%s, ccm_state=%s,"
" crm_state=%s, join_state=%s, expected=%s",
crm_str(ha_state), crm_str(ccm_state),
crm_str(crm_state), crm_str(join_state),
crm_str(exp_state));
}
return online;
}
gboolean
determine_online_status(
crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set)
{
int shutdown = 0;
gboolean online = FALSE;
const char *exp_state =
crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE);
if(this_node == NULL) {
pe_config_err("No node to check");
return online;
}
ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown);
this_node->details->expected_up = FALSE;
if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) {
this_node->details->expected_up = TRUE;
}
this_node->details->shutdown = FALSE;
if(shutdown != 0) {
this_node->details->shutdown = TRUE;
this_node->details->expected_up = FALSE;
}
if(data_set->stonith_enabled == FALSE) {
online = determine_online_status_no_fencing(
node_state, this_node);
} else {
online = determine_online_status_fencing(
node_state, this_node);
}
if(online) {
this_node->details->online = TRUE;
} else {
/* remove node from contention */
this_node->fixed = TRUE;
this_node->weight = -INFINITY;
}
if(online && this_node->details->shutdown) {
/* dont run resources here */
this_node->fixed = TRUE;
this_node->weight = -INFINITY;
}
if(this_node->details->unclean) {
pe_proc_warn("Node %s is unclean", this_node->details->uname);
} else if(this_node->details->online) {
crm_info("Node %s is %s", this_node->details->uname,
this_node->details->shutdown?"shutting down":"online");
} else {
crm_debug_2("Node %s is offline", this_node->details->uname);
}
return online;
}
#define set_char(x) last_rsc_id[len] = x; complete = TRUE;
static void
increment_clone(char *last_rsc_id)
{
gboolean complete = FALSE;
int len = 0;
CRM_CHECK(last_rsc_id != NULL, return);
if(last_rsc_id != NULL) {
len = strlen(last_rsc_id);
}
len--;
while(complete == FALSE && len > 0) {
switch (last_rsc_id[len]) {
case 0:
len--;
break;
case '0':
set_char('1');
break;
case '1':
set_char('2');
break;
case '2':
set_char('3');
break;
case '3':
set_char('4');
break;
case '4':
set_char('5');
break;
case '5':
set_char('6');
break;
case '6':
set_char('7');
break;
case '7':
set_char('8');
break;
case '8':
set_char('9');
break;
case '9':
last_rsc_id[len] = '0';
len--;
break;
default:
crm_err("Unexpected char: %c (%d)",
last_rsc_id[len], len);
break;
}
}
}
static resource_t *
create_fake_resource(const char *rsc_id, crm_data_t *rsc_entry, pe_working_set_t *data_set)
{
resource_t *rsc = NULL;
crm_data_t *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE);
crm_log_xml_info(rsc_entry, "Orphan resource");
copy_in_properties(xml_rsc, rsc_entry);
crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
common_unpack(xml_rsc, &rsc, NULL, data_set);
rsc->orphan = TRUE;
data_set->resources = g_list_append(data_set->resources, rsc);
return rsc;
}
static resource_t *
unpack_find_resource(
pe_working_set_t *data_set, node_t *node, const char *rsc_id, crm_data_t *rsc_entry)
{
resource_t *rsc = NULL;
gboolean is_duped_clone = FALSE;
char *alt_rsc_id = crm_strdup(rsc_id);
while(rsc == NULL) {
crm_debug_3("looking for: %s", alt_rsc_id);
rsc = pe_find_resource(data_set->resources, alt_rsc_id);
/* no match */
if(rsc == NULL) {
crm_debug_2("%s not found: %d", alt_rsc_id, is_duped_clone);
if(is_duped_clone) {
/* create one */
rsc = create_fake_resource(alt_rsc_id, rsc_entry, data_set);
crm_info("Making sure orphan %s/%s is stopped on %s",
rsc_id, rsc->id, node->details->uname);
resource_location(rsc, NULL, -INFINITY, "__orphan_clone_dont_run__", data_set);
- rsc->clone_name = crm_strdup(rsc_id);
- crm_debug("Set clone name %s for orphan %s", rsc->clone_name, rsc->id);
}
break;
/* not running anywhere else */
} else if(rsc->running_on == NULL) {
crm_debug_3("not active yet");
break;
/* always unique */
} else if(rsc->globally_unique) {
crm_debug_3("unique");
break;
/* running somewhere already but we dont care
* find another clone instead
*/
} else {
crm_debug_2("find another one");
rsc = NULL;
is_duped_clone = TRUE;
increment_clone(alt_rsc_id);
}
}
crm_free(alt_rsc_id);
- if(is_duped_clone && rsc != NULL) {
- crm_info("Internally renamed %s on %s to %s",
- rsc_id, node->details->uname, rsc->id);
- rsc->clone_name = crm_strdup(rsc_id);
- crm_debug("Set clone name %s for %s", rsc->clone_name, rsc->id);
-
+ if(rsc != NULL) {
+ crm_free(rsc->clone_name);
+ rsc->clone_name = NULL;
+ if(is_duped_clone) {
+ crm_info("Internally renamed %s on %s to %s",
+ rsc_id, node->details->uname, rsc->id);
+ rsc->clone_name = crm_strdup(rsc_id);
+
+ } else {
+ crm_debug_2("Resetting clone_name %s for %s because of %s",
+ rsc->clone_name, rsc->id, rsc_id);
+ }
}
+
+
return rsc;
}
static resource_t *
process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set)
{
resource_t *rsc = NULL;
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
crm_log_xml_info(rsc_entry, "Orphan resource");
pe_config_warn("Nothing known about resource %s running on %s",
rsc_id, node->details->uname);
rsc = create_fake_resource(rsc_id, rsc_entry, data_set);
if(data_set->stop_rsc_orphans == FALSE) {
rsc->is_managed = FALSE;
} else {
crm_info("Making sure orphan %s is stopped", rsc_id);
print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE);
CRM_CHECK(rsc != NULL, return NULL);
resource_location(rsc, NULL, -INFINITY, "__orphan_dont_run__", data_set);
}
return rsc;
}
static void
process_rsc_state(resource_t *rsc, node_t *node,
enum action_fail_response on_fail,
pe_working_set_t *data_set)
{
crm_debug_2("Resource %s is %s on %s",
rsc->id, role2text(rsc->role),
node->details->uname);
rsc->known_on = g_list_append(rsc->known_on, node);
if(rsc->role != RSC_ROLE_STOPPED) {
if(on_fail != action_fail_ignore) {
rsc->failed = TRUE;
crm_debug_2("Force stop");
}
crm_debug_2("Adding %s to %s",
rsc->id, node->details->uname);
native_add_running(rsc, node, data_set);
if(on_fail == action_fail_ignore) {
/* nothing to do */
} else if(node->details->unclean) {
stop_action(rsc, node, FALSE);
} else if(on_fail == action_fail_fence) {
/* treat it as if it is still running
* but also mark the node as unclean
*/
node->details->unclean = TRUE;
stop_action(rsc, node, FALSE);
} else if(on_fail == action_fail_block) {
/* is_managed == FALSE will prevent any
* actions being sent for the resource
*/
rsc->is_managed = FALSE;
} else if(on_fail == action_fail_migrate) {
stop_action(rsc, node, FALSE);
/* make sure it comes up somewhere else
* or not at all
*/
resource_location(rsc, node, -INFINITY,
"__action_migration_auto__",data_set);
} else {
stop_action(rsc, node, FALSE);
}
} else {
char *key = stop_key(rsc);
GListPtr possible_matches = find_actions(rsc->actions, key, node);
slist_iter(stop, action_t, possible_matches, lpc,
stop->optional = TRUE;
);
crm_free(key);
}
}
static void
unpack_lrm_rsc_state(
node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set)
{
int fail_count = 0;
char *fail_attr = NULL;
const char *value = NULL;
const char *fail_val = NULL;
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
int max_call_id = -1;
GListPtr op_list = NULL;
GListPtr sorted_op_list = NULL;
enum action_fail_response on_fail = FALSE;
enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN;
resource_t *rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry);
crm_debug_3("[%s] Processing %s on %s",
crm_element_name(rsc_entry), rsc_id, node->details->uname);
if(rsc == NULL) {
rsc = process_orphan_resource(rsc_entry, node, data_set);
}
CRM_ASSERT(rsc != NULL);
/* process failure stickiness */
fail_count = 0;
fail_attr = crm_concat("fail-count", rsc->id, '-');
fail_val = g_hash_table_lookup(node->details->attrs, fail_attr);
if(fail_val != NULL) {
crm_debug("%s: %s", fail_attr, fail_val);
fail_count = crm_parse_int(fail_val, "0");
}
crm_free(fail_attr);
if(fail_count > 0 && rsc->fail_stickiness != 0) {
resource_location(rsc, node, fail_count * rsc->fail_stickiness,
"fail_stickiness", data_set);
crm_debug("Setting failure stickiness for %s on %s: %d",
rsc->id, node->details->uname,
fail_count * rsc->fail_stickiness);
}
/* process operations */
max_call_id = -1;
op_list = NULL;
sorted_op_list = NULL;
xml_child_iter_filter(
rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
op_list = g_list_append(op_list, rsc_op);
);
if(op_list != NULL) {
int stop_index = -1;
int start_index = -1;
const char *task = NULL;
const char *status = NULL;
saved_role = rsc->role;
on_fail = action_fail_ignore;
rsc->role = RSC_ROLE_STOPPED;
sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
slist_iter(
rsc_op, crm_data_t, sorted_op_list, lpc,
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS);
if(safe_str_eq(task, CRMD_ACTION_STOP)
&& safe_str_eq(status, "0")) {
stop_index = lpc;
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
start_index = lpc;
} else if(start_index <= stop_index
&& safe_str_eq(task, CRMD_ACTION_STATUS)) {
const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC);
if(safe_str_eq(rc, "0")
|| safe_str_eq(rc, "8")) {
start_index = lpc;
}
}
unpack_rsc_op(rsc, node, rsc_op,
&max_call_id, &on_fail, data_set);
);
crm_debug_2("%s: Start index %d, stop index = %d",
rsc->id, start_index, stop_index);
slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc,
int interval = 0;
char *key = NULL;
const char *id = ID(rsc_op);
const char *interval_s = NULL;
if(node->details->online == FALSE) {
crm_debug_4("Skipping %s/%s: node is offline",
rsc->id, node->details->uname);
break;
} else if(start_index < stop_index) {
crm_debug_4("Skipping %s/%s: not active",
rsc->id, node->details->uname);
break;
} else if(lpc <= start_index) {
crm_debug_4("Skipping %s/%s: old",
id, node->details->uname);
continue;
}
interval_s = get_interval(rsc_op);
interval = crm_parse_int(interval_s, "0");
if(interval == 0) {
crm_debug_4("Skipping %s/%s: non-recurring",
id, node->details->uname);
continue;
}
status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS);
if(safe_str_eq(status, "-1")) {
crm_debug_4("Skipping %s/%s: status",
id, node->details->uname);
continue;
}
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
/* create the action */
key = generate_op_key(rsc->id, task, interval);
crm_debug_3("Creating %s/%s", key, node->details->uname);
custom_action(rsc, key, task, node,
TRUE, TRUE, data_set);
);
/* no need to free the contents */
g_list_free(sorted_op_list);
process_rsc_state(rsc, node, on_fail, data_set);
}
value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
if(value != NULL && safe_str_neq("default", value)) {
enum rsc_role_e req_role = text2role(value);
if(req_role != RSC_ROLE_UNKNOWN && req_role != rsc->next_role){
if(rsc->next_role != RSC_ROLE_UNKNOWN) {
crm_debug("%s: Overwriting calculated next role %s"
" with requested next role %s",
rsc->id, role2text(rsc->next_role),
role2text(req_role));
}
rsc->next_role = req_role;
}
}
if(saved_role > rsc->role) {
rsc->role = saved_role;
}
}
gboolean
unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set)
{
CRM_CHECK(node != NULL, return FALSE);
crm_debug_3("Unpacking resources on %s", node->details->uname);
xml_child_iter_filter(
lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE,
unpack_lrm_rsc_state(node, rsc_entry, data_set);
);
return TRUE;
}
gboolean
unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op,
int *max_call_id, enum action_fail_response *on_fail,
pe_working_set_t *data_set)
{
const char *id = NULL;
const char *task = NULL;
const char *task_id = NULL;
const char *actual_rc = NULL;
/* const char *target_rc = NULL; */
const char *task_status = NULL;
const char *interval_s = NULL;
const char *op_digest = NULL;
int interval = 0;
int task_id_i = -1;
int task_status_i = -2;
int actual_rc_i = 0;
action_t *action = NULL;
gboolean is_probe = FALSE;
gboolean is_stop_action = FALSE;
CRM_CHECK(rsc != NULL, return FALSE);
CRM_CHECK(node != NULL, return FALSE);
CRM_CHECK(xml_op != NULL, 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);
op_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
CRM_CHECK(id != NULL, return FALSE);
CRM_CHECK(task != NULL, return FALSE);
CRM_CHECK(task_status != NULL, return FALSE);
task_status_i = crm_parse_int(task_status, NULL);
CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE);
CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE);
if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
/* safe to ignore these */
return TRUE;
}
crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)",
id, task, task_id, task_status, node->details->uname,
role2text(rsc->role));
interval_s = get_interval(xml_op);
interval = crm_parse_int(interval_s, "0");
if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) {
is_probe = TRUE;
} else if(interval > 0 && rsc->role < RSC_ROLE_STARTED) {
crm_debug_2("Skipping recurring action %s for stopped resource", id);
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_parse_int(task_id, "-1");
CRM_CHECK(task_id != NULL, return FALSE);
CRM_CHECK(task_id_i >= 0, return FALSE);
CRM_CHECK(task_id_i > *max_call_id, 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);
}
actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
CRM_CHECK(actual_rc != NULL, return FALSE);
actual_rc_i = crm_parse_int(actual_rc, NULL);
if(EXECRA_NOT_RUNNING == actual_rc_i) {
if(is_probe) {
/* treat these like stops */
is_stop_action = TRUE;
}
if(is_stop_action) {
task_status_i = LRM_OP_DONE;
} else {
CRM_CHECK(task_status_i == LRM_OP_ERROR,
task_status_i = LRM_OP_ERROR);
}
} else if(EXECRA_RUNNING_MASTER == actual_rc_i) {
if(is_probe
|| (rsc->role == RSC_ROLE_MASTER
&& safe_str_eq(task, CRMD_ACTION_STATUS))) {
task_status_i = LRM_OP_DONE;
} else {
if(rsc->role != RSC_ROLE_MASTER) {
crm_err("%s reported %s in master mode on %s",
id, rsc->id,
node->details->uname);
}
CRM_CHECK(task_status_i == LRM_OP_ERROR,
task_status_i = LRM_OP_ERROR);
}
rsc->role = RSC_ROLE_MASTER;
} else if(EXECRA_FAILED_MASTER == actual_rc_i) {
rsc->role = RSC_ROLE_MASTER;
task_status_i = LRM_OP_ERROR;
} else if(EXECRA_OK == actual_rc_i
&& interval > 0
&& rsc->role == RSC_ROLE_MASTER) {
/* catch status ops that return 0 instead of 8 while they
* are supposed to be in master mode
*/
task_status_i = LRM_OP_ERROR;
}
if(task_status_i == LRM_OP_ERROR
|| task_status_i == LRM_OP_TIMEOUT
|| task_status_i == LRM_OP_NOTSUPPORTED) {
action = custom_action(rsc, crm_strdup(id), task, NULL,
TRUE, FALSE, data_set);
if(action->on_fail == action_fail_ignore) {
task_status_i = LRM_OP_DONE;
}
}
switch(task_status_i) {
case LRM_OP_PENDING:
if(safe_str_eq(task, CRMD_ACTION_START)) {
rsc->start_pending = TRUE;
rsc->role = RSC_ROLE_STARTED;
} else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
rsc->role = RSC_ROLE_MASTER;
}
break;
case LRM_OP_DONE:
crm_debug_3("%s/%s completed on %s",
rsc->id, task, node->details->uname);
if(is_stop_action) {
rsc->role = RSC_ROLE_STOPPED;
/* clear any previous failure actions */
*on_fail = action_fail_ignore;
rsc->next_role = RSC_ROLE_UNKNOWN;
} else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
rsc->role = RSC_ROLE_MASTER;
} else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
rsc->role = RSC_ROLE_SLAVE;
} else if(rsc->role < RSC_ROLE_STARTED) {
crm_debug_3("%s active on %s",
rsc->id, node->details->uname);
rsc->role = RSC_ROLE_STARTED;
}
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
crm_warn("Processing failed op (%s) for %s on %s",
id, rsc->id, node->details->uname);
if(*on_fail < action->on_fail) {
*on_fail = action->on_fail;
}
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);
resource_location(rsc, node, -INFINITY,
"__dont_run__failed_stopstart__",
data_set);
}
if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
rsc->role = RSC_ROLE_MASTER;
} else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
rsc->role = RSC_ROLE_MASTER;
} else if(rsc->role < RSC_ROLE_STARTED) {
rsc->role = RSC_ROLE_STARTED;
}
crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s",
rsc->id, role2text(rsc->role),
node->details->unclean?"true":"false",
fail2text(action->on_fail),
role2text(action->fail_role));
if(action->fail_role != RSC_ROLE_STARTED
&& rsc->next_role < action->fail_role) {
rsc->next_role = action->fail_role;
}
if(action->fail_role == RSC_ROLE_STOPPED) {
crm_err("Making sure %s doesn't come up again", rsc->id);
/* make sure it doesnt come up again */
pe_free_shallow_adv(rsc->allowed_nodes, TRUE);
rsc->allowed_nodes = node_list_dup(
data_set->nodes, FALSE, FALSE);
slist_iter(
node, node_t, rsc->allowed_nodes, lpc,
node->weight = -INFINITY;
);
}
pe_free_action(action);
action = NULL;
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
pe_err("Dont know what to do for cancelled ops yet");
break;
}
crm_debug_3("Resource %s after %s: role=%s",
rsc->id, task, role2text(rsc->role));
pe_free_action(action);
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, XML_TAG_ATTR_SETS, NULL,
node->details->attrs, NULL, data_set->now);
return TRUE;
}