Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842485
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
36 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/crm/pengine/unpack.c b/lib/crm/pengine/unpack.c
index 03373f86c8..cf8f0b70b6 100644
--- a/lib/crm/pengine/unpack.c
+++ b/lib/crm/pengine/unpack.c
@@ -1,1267 +1,1267 @@
/* $Id: unpack.c,v 1.18 2006/08/14 09:40:01 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 <clplumbing/cl_misc.h>
#include <lrm/lrm_api.h>
#include <glib.h>
#include <heartbeat.h> /* for ONLINESTATUS */
#include <crm/pengine/status.h>
#include <utils.h>
#include <crm/pengine/rules.h>
#include <unpack.h>
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));
}
crm_config_err("Creating <nvpair id=%s name=%s/> directly"
"beneath <crm_config> 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);
crm_config_err("Creating <nvpair id=%s name=%s/> directly"
"beneath <crm_config> has been depreciated since"
" 2.0.1 and is now disabled", ID(a_child), name);
);
#endif
verify_pe_options(data_set->config_hash);
value = pe_pref(data_set->config_hash, "default-action-timeout");
data_set->transition_idle_timeout = crm_strdup(value);
crm_debug("Default action timeout: %s", data_set->transition_idle_timeout);
value = pe_pref(data_set->config_hash, "default-resource-stickiness");
data_set->default_resource_stickiness = char2score(value);
crm_debug("Default stickiness: %d",
data_set->default_resource_stickiness);
value = pe_pref(data_set->config_hash, "default-resource-failure-stickiness");
data_set->default_resource_fail_stickiness = char2score(value);
crm_debug("Default failure stickiness: %d",
data_set->default_resource_fail_stickiness);
value = pe_pref(data_set->config_hash, "stonith-enabled");
cl_str_to_boolean(value, &data_set->stonith_enabled);
crm_debug("STONITH of failed nodes is %s",
data_set->stonith_enabled?"enabled":"disabled");
data_set->stonith_action = pe_pref(data_set->config_hash, "stonith-action");
crm_debug_2("STONITH will %s nodes", data_set->stonith_action);
value = pe_pref(data_set->config_hash, "symmetric-cluster");
cl_str_to_boolean(value, &data_set->symmetric_cluster);
if(data_set->symmetric_cluster) {
crm_debug("Cluster is symmetric"
" - resources can run anywhere by default");
}
value = pe_pref(data_set->config_hash, "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_debug("On loss of CCM Quorum: Freeze resources");
break;
case no_quorum_stop:
crm_debug("On loss of CCM Quorum: Stop ALL resources");
break;
case no_quorum_ignore:
crm_notice("On loss of CCM Quorum: Ignore");
break;
}
value = pe_pref(data_set->config_hash, "stop-orphan-resources");
cl_str_to_boolean(value, &data_set->stop_rsc_orphans);
crm_debug_2("Orphan resources are %s",
data_set->stop_rsc_orphans?"stopped":"ignored");
value = pe_pref(data_set->config_hash, "stop-orphan-actions");
cl_str_to_boolean(value, &data_set->stop_action_orphans);
crm_debug_2("Orphan resource actions are %s",
data_set->stop_action_orphans?"stopped":"ignored");
value = pe_pref(data_set->config_hash, "remove-after-stop");
cl_str_to_boolean(value, &data_set->remove_after_stop);
crm_debug_2("Stopped resources are removed from the status section: %s",
data_set->remove_after_stop?"true":"false");
value = pe_pref(data_set->config_hash, "is-managed-default");
cl_str_to_boolean(value, &data_set->is_managed_default);
crm_debug_2("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;
gboolean unseen_are_unclean = TRUE;
const char *blind_faith = pe_pref(
data_set->config_hash, "startup-fencing");
if(crm_is_true(blind_faith) == FALSE) {
unseen_are_unclean = FALSE;
crm_warn("Blind faith: not fencing unseen 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) {
crm_config_err("Must specify id tag in <node>");
continue;
}
if(type == NULL) {
crm_config_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 == FALSE || unseen_are_unclean == FALSE) {
/* blind faith... */
new_node->details->unclean = FALSE;
} else {
/* all nodes are unclean until we've seen their
* status entry
*/
new_node->details->unclean = TRUE;
}
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));
);
return TRUE;
}
gboolean
unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set)
{
xml_child_iter(
xml_resources, xml_obj,
resource_t *new_rsc = NULL;
crm_debug_3("Begining unpack... %s",
xml_obj?crm_element_name(xml_obj):"<none>");
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 {
crm_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) {
crm_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(ha_state == NULL) {
ha_state = DEADSTATUS;
}
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_eq(crm_state, ONLINESTATUS)) {
if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
online = TRUE;
} else {
crm_debug("Node is not ready to run resources: %s", join_state);
}
} 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(ha_state == NULL) {
ha_state = DEADSTATUS;
}
if(crm_is_true(ccm_state)
&& safe_str_eq(ha_state, ACTIVESTATUS)
&& safe_str_eq(crm_state, ONLINESTATUS)) {
online = TRUE;
if(safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) {
crm_debug("Node is not ready to run resources: %s", join_state);
this_node->details->standby = 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) {
/* 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));
} else {
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));
}
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) {
crm_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);
}
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(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);
}
}
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");
crm_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,
crm_data_t *migrate_op,
pe_working_set_t *data_set)
{
int fail_count = 0;
char *fail_attr = NULL;
const char *value = NULL;
GHashTable *meta_hash = NULL;
if(on_fail == action_migrate_failure) {
node_t *from = NULL;
const char *uuid = NULL;
uuid = crm_element_value(migrate_op, CRMD_ACTION_MIGRATED);
from = pe_find_node_id(data_set->nodes, uuid);
process_rsc_state(rsc, from, action_fail_recover,NULL,data_set);
on_fail = action_fail_recover;
}
crm_debug_2("Resource %s is %s on %s",
rsc->id, role2text(rsc->role),
node->details->uname);
meta_hash = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
get_meta_attributes(meta_hash, rsc, node, data_set);
/* update resource preferences that relate to the current node */
value = g_hash_table_lookup(meta_hash, "resource_stickiness");
if(value != NULL && safe_str_neq("default", value)) {
rsc->stickiness = char2score(value);
} else {
rsc->stickiness = data_set->default_resource_stickiness;
}
value = g_hash_table_lookup(meta_hash, XML_RSC_ATTR_FAIL_STICKINESS);
if(value != NULL && safe_str_neq("default", value)) {
rsc->fail_stickiness = char2score(value);
} else {
rsc->fail_stickiness = data_set->default_resource_fail_stickiness;
}
/* process failure stickiness */
fail_attr = crm_concat("fail-count", rsc->id, '-');
value = g_hash_table_lookup(node->details->attrs, fail_attr);
if(value != NULL) {
crm_debug("%s: %s", fail_attr, value);
fail_count = crm_parse_int(value, "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 current state */
if(rsc->role != RSC_ROLE_UNKNOWN) {
rsc->known_on = g_list_append(rsc->known_on, node);
}
if(rsc->role != RSC_ROLE_STOPPED
&& rsc->role != RSC_ROLE_UNKNOWN) {
if(on_fail != action_fail_ignore) {
rsc->failed = TRUE;
crm_debug_2("Force stop");
}
native_add_running(rsc, node, data_set);
if(rsc->is_managed && rsc->stickiness != 0) {
resource_location(rsc, node, rsc->stickiness,
"stickiness", data_set);
crm_debug("Resource %s: preferring current location"
" (node=%s, weight=%d)", rsc->id,
node->details->uname, rsc->stickiness);
}
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 if(rsc->clone_name) {
crm_debug_2("Resetting clone_name %s for %s (stopped)",
rsc->clone_name, rsc->id);
crm_free(rsc->clone_name);
rsc->clone_name = NULL;
} 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);
}
g_hash_table_destroy(meta_hash);
}
/* create active recurring operations as optional */
static void
process_recurring(node_t *node, resource_t *rsc,
int start_index, int stop_index,
GListPtr sorted_op_list, pe_working_set_t *data_set)
{
const char *task = NULL;
const char *status = NULL;
crm_debug_3("%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 = crm_element_value(rsc_op,XML_LRM_ATTR_INTERVAL);
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);
);
}
static void
unpack_lrm_rsc_state(
node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set)
{
int stop_index = -1;
int start_index = -1;
int max_call_id = -1;
const char *task = NULL;
const char *status = NULL;
const char *value = NULL;
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
resource_t *rsc = NULL;
GListPtr op_list = NULL;
GListPtr sorted_op_list = NULL;
crm_data_t *migrate_op = NULL;
enum action_fail_response on_fail = FALSE;
enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN;
crm_debug_3("[%s] Processing %s on %s",
crm_element_name(rsc_entry), rsc_id, node->details->uname);
/* extract operations */
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) {
/* if there are no operations, there is nothing to do */
return;
}
/* find the resource */
rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry);
if(rsc == NULL) {
rsc = process_orphan_resource(rsc_entry, node, data_set);
}
CRM_ASSERT(rsc != NULL);
/* process operations */
max_call_id = -1;
saved_role = rsc->role;
on_fail = action_fail_ignore;
rsc->role = RSC_ROLE_UNKNOWN;
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;
}
} else if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
migrate_op = rsc_op;
}
unpack_rsc_op(rsc, node, rsc_op,
&max_call_id, &on_fail, data_set);
);
/* create active recurring operations as optional */
process_recurring(node, rsc, start_index, stop_index,
sorted_op_list, data_set);
/* no need to free the contents */
g_list_free(sorted_op_list);
process_rsc_state(rsc, node, on_fail, migrate_op, 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 = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
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_3("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_INSTALLED == actual_rc_i) {
if(is_probe) {
/* treat these like stops */
is_stop_action = TRUE;
task_status_i = LRM_OP_DONE;
} else {
task_status_i = LRM_OP_ERROR;
}
} else 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 {
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 {
task_status_i = LRM_OP_ERROR;
if(rsc->role != RSC_ROLE_MASTER) {
crm_err("%s reported %s in master mode on %s",
id, rsc->id,
node->details->uname);
}
}
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);
+ crm_warn("Processing failed op (%s) on %s",
+ 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;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:49 PM (11 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1017895
Default Alt Text
(36 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment