Page MenuHomeClusterLabs Projects

unpack.c
No OneTemporary

unpack.c

/* $Id: unpack.c,v 1.45 2004/11/12 17:18:05 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 <libxml/tree.h>
#include <heartbeat.h> /* for ONLINESTATUS */
#include <pengine.h>
#include <pe_utils.h>
int max_valid_nodes = 0;
int order_id = 1;
GListPtr agent_defaults = NULL;
gboolean stonith_enabled = FALSE;
const char* transition_timeout = "60000"; /* 1 minute */
GListPtr match_attrs(const char *attr, const char *op, const char *value,
const char *type, GListPtr node_list);
gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj,
GListPtr rsc_list,
GListPtr node_list,
GListPtr *placement_constraints);
gboolean unpack_rsc_to_node(xmlNodePtr xml_obj,
GListPtr rsc_list,
GListPtr node_list,
GListPtr *placement_constraints);
gboolean unpack_rsc_order(
xmlNodePtr xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints);
gboolean unpack_rsc_dependancy(
xmlNodePtr xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints);
gboolean unpack_rsc_location(
xmlNodePtr xml_obj, GListPtr rsc_list, GListPtr node_list,
GListPtr *ordering_constraints);
gboolean unpack_lrm_rsc_state(
node_t *node, xmlNodePtr lrm_state,
GListPtr rsc_list, GListPtr nodes,
GListPtr *actions, GListPtr *placement_constraints);
gboolean add_node_attrs(xmlNodePtr attrs, node_t *node);
gboolean unpack_healthy_resource(GListPtr *placement_constraints, GListPtr *actions,
xmlNodePtr rsc_entry, resource_t *rsc_lh, node_t *node);
gboolean unpack_failed_resource(GListPtr *placement_constraints,
xmlNodePtr rsc_entry, resource_t *rsc_lh, node_t *node);
gboolean determine_online_status(xmlNodePtr node_state, node_t *this_node);
gboolean unpack_lrm_agents(node_t *node, xmlNodePtr agent_list);
gboolean is_node_unclean(xmlNodePtr node_state);
gboolean rsc_dependancy_new(
const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh);
gboolean create_ordering(
const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh, GListPtr *ordering_constraints);
rsc_to_node_t *rsc2node_new(
const char *id, resource_t *rsc,
double weight, gboolean can_run, node_t *node,
GListPtr *placement_constraints);
const char *get_agent_param(resource_t *rsc, const char *param);
const char *get_agent_param_rsc(resource_t *rsc, const char *param);
const void *get_agent_param_metadata(resource_t *rsc, const char *param);
const char *get_agent_param_global(resource_t *rsc, const char *param);
const char *param_value(xmlNodePtr parent, const char *name);
gboolean
unpack_config(xmlNodePtr config)
{
const char *value = NULL;
value = param_value(config, "failed_nodes");
if(safe_str_eq(value, "stonith")) {
crm_debug("Enabling STONITH of failed nodes");
stonith_enabled = TRUE;
} else {
stonith_enabled = FALSE;
}
value = param_value(config, "transition_timeout");
if(value != NULL) {
int tmp = atoi(value);
if(tmp > 0) {
transition_timeout = value;
} else {
crm_warn("Invalid value for %s: %s",
"transition_timeout", value);
}
}
crm_info("%s set to: %s",
"transition_timeout", transition_timeout);
return TRUE;
}
const char *
param_value(xmlNodePtr parent, const char *name)
{
xmlNodePtr a_default = find_entity(
parent, XML_CIB_TAG_NVPAIR, name, FALSE);
return xmlGetProp(a_default, XML_NVPAIR_ATTR_VALUE);
}
const char *
get_agent_param(resource_t *rsc, const char *param)
{
const char *value = NULL;
if(param == NULL) {
return NULL;
}
value = get_agent_param_rsc(rsc, param);
if(value == NULL) {
value = get_agent_param_metadata(rsc, param);
}
if(value == NULL) {
value = get_agent_param_global(rsc, param);
}
return value;
}
const char *
get_agent_param_rsc(resource_t *rsc, const char *param)
{
xmlNodePtr xml_rsc = rsc->xml;
return xmlGetProp(xml_rsc, param);
}
const void *
get_agent_param_metadata(resource_t *rsc, const char *param)
{
return NULL;
}
const char *
get_agent_param_global(resource_t *rsc, const char *param)
{
const char * value = NULL;/*g_hashtable_lookup(agent_global_defaults, param); */
if(value == NULL) {
crm_err("No global value default for %s", param);
}
return value;
}
gboolean
unpack_global_defaults(xmlNodePtr defaults)
{
return TRUE;
}
gboolean
unpack_nodes(xmlNodePtr xml_nodes, GListPtr *nodes)
{
node_t *new_node = NULL;
xmlNodePtr attrs = NULL;
const char *id = NULL;
const char *uname = NULL;
const char *type = NULL;
crm_verbose("Begining unpack...");
xml_child_iter(
xml_nodes, xml_obj, XML_CIB_TAG_NODE,
attrs = xml_obj->children;
id = xmlGetProp(xml_obj, XML_ATTR_ID);
uname = xmlGetProp(xml_obj, XML_ATTR_UNAME);
type = xmlGetProp(xml_obj, XML_ATTR_TYPE);
crm_verbose("Processing node %s/%s", uname, id);
if(attrs != NULL) {
attrs = attrs->children;
}
if(id == NULL) {
crm_err("Must specify id tag in <node>");
continue;
}
if(type == NULL) {
crm_err("Must specify type tag in <node>");
continue;
}
crm_malloc(new_node, sizeof(node_t));
if(new_node == NULL) {
return FALSE;
}
new_node->weight = 1.0;
new_node->fixed = FALSE;
crm_malloc(new_node->details,
sizeof(struct node_shared_s));
if(new_node->details == NULL) {
crm_free(new_node);
return FALSE;
}
crm_verbose("Creaing node for entry %s/%s", uname, id);
new_node->details->id = id;
new_node->details->uname = uname;
new_node->details->type = node_ping;
new_node->details->online = FALSE;
new_node->details->unclean = FALSE;
new_node->details->shutdown = FALSE;
new_node->details->running_rsc = NULL;
new_node->details->agents = NULL;
new_node->details->attrs = g_hash_table_new(
g_str_hash, g_str_equal);
if(safe_str_eq(type, "member")) {
new_node->details->type = node_member;
}
add_node_attrs(attrs, new_node);
*nodes = g_list_append(*nodes, new_node);
crm_verbose("Done with node %s", xmlGetProp(xml_obj, "uname"));
crm_debug_action(print_node("Added", new_node, FALSE));
);
*nodes = g_list_sort(*nodes, sort_node_weight);
return TRUE;
}
gboolean
unpack_resources(xmlNodePtr xml_resources,
GListPtr *resources,
GListPtr *actions,
GListPtr *ordering_constraints,
GListPtr all_nodes)
{
crm_verbose("Begining unpack...");
xml_child_iter(
xml_resources, xml_obj, NULL,
resource_t *new_rsc = NULL;
if(common_unpack(xml_obj, &new_rsc)) {
*resources = g_list_append(*resources, new_rsc);
crm_debug_action(
print_resource("Added", new_rsc, FALSE));
} else {
crm_err("Failed unpacking resource %s",
xmlGetProp(xml_obj, XML_ATTR_ID));
}
);
*resources = g_list_sort(*resources, sort_rsc_priority);
return TRUE;
}
gboolean
unpack_constraints(xmlNodePtr xml_constraints,
GListPtr nodes, GListPtr resources,
GListPtr *placement_constraints,
GListPtr *ordering_constraints)
{
crm_verbose("Begining unpack...");
xml_child_iter(
xml_constraints, xml_obj, NULL,
const char *id = xmlGetProp(xml_obj, XML_ATTR_ID);
if(id == NULL) {
crm_err("Constraint <%s...> must have an id",
xml_obj->name);
continue;
}
crm_verbose("Processing constraint %s %s", xml_obj->name,id);
if(safe_str_eq("rsc_order", xml_obj->name)) {
unpack_rsc_order(
xml_obj, resources, ordering_constraints);
} else if(safe_str_eq("rsc_dependancy", xml_obj->name)) {
unpack_rsc_dependancy(
xml_obj, resources, ordering_constraints);
} else if(safe_str_eq("rsc_location", xml_obj->name)) {
unpack_rsc_location(
xml_obj, resources, nodes, placement_constraints);
} else {
crm_err("Unsupported constraint type: %s", xml_obj->name);
}
);
return TRUE;
}
rsc_to_node_t *
rsc2node_new(const char *id, resource_t *rsc,
double weight, gboolean can, node_t *node,
GListPtr *placement_constraints)
{
rsc_to_node_t *new_con = NULL;
if(rsc == NULL || id == NULL) {
crm_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
return NULL;
}
crm_malloc(new_con, sizeof(rsc_to_node_t));
if(new_con != NULL) {
new_con->id = id;
new_con->rsc_lh = rsc;
new_con->node_list_rh = NULL;
new_con->can = can;
if(can) {
new_con->weight = weight;
} else {
new_con->weight = -1;
}
if(node != NULL) {
new_con->node_list_rh = g_list_append(NULL, node);
}
*placement_constraints = g_list_append(*placement_constraints, new_con);
}
return new_con;
}
/* remove nodes that are down, stopping */
/* create +ve rsc_to_node constraints between resources and the nodes they are running on */
/* anything else? */
gboolean
unpack_status(xmlNodePtr status,
GListPtr nodes, GListPtr rsc_list,
GListPtr *actions, GListPtr *placement_constraints)
{
const char *uname = NULL;
xmlNodePtr lrm_rsc = NULL;
xmlNodePtr lrm_agents = NULL;
xmlNodePtr attrs = NULL;
node_t *this_node = NULL;
crm_verbose("Begining unpack");
xml_child_iter(
status, node_state, XML_CIB_TAG_STATE,
/* id = xmlGetProp(node_state, XML_ATTR_ID); */
uname = xmlGetProp(node_state, XML_ATTR_UNAME);
attrs = find_xml_node(node_state, "attributes");
lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM);
lrm_agents = find_xml_node(lrm_rsc, "lrm_agents");
lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES);
lrm_rsc = find_xml_node(lrm_rsc, "lrm_resource");
crm_verbose("Processing node %s", uname);
this_node = pe_find_node(nodes, uname);
if(uname == NULL) {
/* error */
continue;
} else if(this_node == NULL) {
crm_err("Node %s in status section no longer exists",
uname);
continue;
}
crm_verbose("Adding runtime node attrs");
add_node_attrs(attrs, this_node);
crm_verbose("determining node state");
determine_online_status(node_state, this_node);
crm_verbose("Processing lrm resource entries");
unpack_lrm_rsc_state(this_node, lrm_rsc, rsc_list, nodes,
actions, placement_constraints);
crm_verbose("Processing lrm agents");
unpack_lrm_agents(this_node, lrm_agents);
);
return TRUE;
}
gboolean
determine_online_status(xmlNodePtr node_state, node_t *this_node)
{
gboolean online = FALSE;
const char *uname = xmlGetProp(node_state,XML_ATTR_UNAME);
/* const char *state = xmlGetProp(node_state,XML_NODE_ATTR_STATE); */
const char *exp_state = xmlGetProp(node_state,XML_CIB_ATTR_EXPSTATE);
const char *join_state = xmlGetProp(node_state,XML_CIB_ATTR_JOINSTATE);
const char *crm_state = xmlGetProp(node_state,XML_CIB_ATTR_CRMDSTATE);
const char *ccm_state = xmlGetProp(node_state,XML_CIB_ATTR_INCCM);
const char *ha_state = xmlGetProp(node_state,XML_CIB_ATTR_HASTATE);
const char *shutdown = xmlGetProp(node_state,XML_CIB_ATTR_SHUTDOWN);
const char *unclean = NULL;/*xmlGetProp(node_state,XML_CIB_ATTR_STONITH); */
if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)
&& safe_str_eq(ccm_state, XML_BOOLEAN_YES)
&& (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS))
&& safe_str_eq(crm_state, ONLINESTATUS)
&& shutdown == NULL) {
if(this_node != NULL) {
this_node->details->online = TRUE;
}
crm_debug("Node %s is online", uname);
online = TRUE;
} else if(this_node != NULL) {
/* remove node from contention */
this_node->weight = -1;
this_node->fixed = TRUE;
crm_verbose("join_state=%s, expected=%s, shutdown=%s",
crm_str(join_state), crm_str(exp_state),
crm_str(shutdown));
if(unclean != NULL) {
this_node->details->unclean = TRUE;
} else if(is_node_unclean(node_state)) {
/* report and or take remedial action */
this_node->details->unclean = TRUE;
}
if(shutdown != NULL) {
this_node->details->shutdown = TRUE;
}
if(this_node->details->unclean) {
crm_warn("Node %s is due for STONITH", uname);
}
if(this_node->details->shutdown) {
crm_info("Node %s is due for shutdown", uname);
}
}
return online;
}
gboolean
is_node_unclean(xmlNodePtr node_state)
{
/* const char *state = xmlGetProp(node_state,XML_NODE_ATTR_STATE); */
const char *uname = xmlGetProp(node_state,XML_ATTR_UNAME);
const char *exp_state = xmlGetProp(node_state,XML_CIB_ATTR_EXPSTATE);
const char *join_state = xmlGetProp(node_state,XML_CIB_ATTR_JOINSTATE);
const char *crm_state = xmlGetProp(node_state,XML_CIB_ATTR_CRMDSTATE);
const char *ha_state = xmlGetProp(node_state,XML_CIB_ATTR_HASTATE);
const char *ccm_state = xmlGetProp(node_state,XML_CIB_ATTR_INCCM);
if(safe_str_eq(exp_state, CRMD_STATE_INACTIVE)) {
crm_debug("Node %s is safely inactive", uname);
return FALSE;
/* do an actual calculation once STONITH is available */
} else if(safe_str_neq(exp_state, CRMD_JOINSTATE_DOWN)) {
if(safe_str_eq(crm_state, OFFLINESTATUS)
|| (ha_state != NULL && safe_str_eq(ha_state, DEADSTATUS))
|| safe_str_eq(join_state, CRMD_JOINSTATE_DOWN)
|| safe_str_eq(ccm_state, XML_BOOLEAN_NO)) {
crm_warn("Node %s is un-expectedly down", uname);
return TRUE;
}
crm_debug("Node %s: ha=%s, join=%s, crm=%s, ccm=%s",
uname, ha_state, join_state, crm_state, ccm_state);
} else {
crm_debug("Node %s was expected to be down", uname);
}
return FALSE;
}
gboolean
unpack_lrm_agents(node_t *node, xmlNodePtr agent_list)
{
/* if the agent is not listed, remove the node from
* the resource's list of allowed_nodes
*/
lrm_agent_t *agent = NULL;
const char *version = NULL;
if(agent_list == NULL) {
return FALSE;
}
xml_child_iter(
agent_list, xml_agent, XML_LRM_TAG_AGENT,
crm_malloc(agent, sizeof(lrm_agent_t));
if(agent == NULL) {
continue;
}
agent->class = xmlGetProp(xml_agent, "class");
agent->type = xmlGetProp(xml_agent, "type");
version = xmlGetProp(xml_agent, "version");
agent->version = version?version:"0.0";
crm_trace("Adding agent %s/%s v%s to node %s",
agent->class,
agent->type,
agent->version,
node->details->uname);
node->details->agents = g_list_append(
node->details->agents, agent);
);
return TRUE;
}
gboolean
unpack_lrm_rsc_state(node_t *node, xmlNodePtr lrm_rsc,
GListPtr rsc_list, GListPtr nodes,
GListPtr *actions, GListPtr *placement_constraints)
{
xmlNodePtr rsc_entry = NULL;
const char *rsc_id = NULL;
const char *node_id = NULL;
const char *rsc_state = NULL;
const char *op_status = NULL;
const char *last_rc = NULL;
const char *last_op = NULL;
resource_t *rsc_lh = NULL;
op_status_t action_status_i = LRM_OP_ERROR;
while(lrm_rsc != NULL) {
rsc_entry = lrm_rsc;
lrm_rsc = lrm_rsc->next;
rsc_id = xmlGetProp(rsc_entry, XML_ATTR_ID);
node_id = xmlGetProp(rsc_entry, XML_LRM_ATTR_TARGET);
rsc_state = xmlGetProp(rsc_entry, XML_LRM_ATTR_RSCSTATE);
op_status = xmlGetProp(rsc_entry, XML_LRM_ATTR_OPSTATUS);
last_rc = xmlGetProp(rsc_entry, XML_LRM_ATTR_RC);
last_op = xmlGetProp(rsc_entry, XML_LRM_ATTR_LASTOP);
rsc_lh = pe_find_resource(rsc_list, rsc_id);
crm_verbose("[%s] Processing %s on %s (%s)",
rsc_entry->name, rsc_id, node_id, rsc_state);
if(rsc_lh == NULL) {
crm_err("Could not find a match for resource"
" %s in %s's status section",
rsc_id, node_id);
continue;
} else if(op_status == NULL) {
crm_err("Invalid resource status entry for %s in %s",
rsc_id, node_id);
continue;
}
action_status_i = atoi(op_status);
if(node->details->unclean) {
crm_info("Node %s (where %s is running) is unclean."
"Further action depends on the value of on_stopfail",
node->details->uname, rsc_lh->id);
/* map the status to an error and then handle as a
* failed resource.
*/
action_status_i = LRM_OP_ERROR;
} else if(action_status_i == -1) {
/*
* TODO: this may need some more thought
* Some cases:
* - PE reinvoked with pending action that will succeed
* - PE reinvoked with pending action that will fail
* - After DC election
* - After startup
*
* pending start - required start
* pending stop - required stop
* pending <any> on unavailable node - stonith
*
* For now this should do
*/
if(safe_str_eq(last_op, "stop")) {
/* map this to a timeout so it is re-issued */
action_status_i = LRM_OP_TIMEOUT;
} else {
/* map this to a "done" so it is not marked
* as failed, then make sure it is re-issued
*/
action_new(rsc_lh, start_rsc, NULL);
action_status_i = LRM_OP_DONE;
}
}
switch(action_status_i) {
case LRM_OP_DONE:
unpack_healthy_resource(
placement_constraints, actions,
rsc_entry, rsc_lh,node);
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
unpack_failed_resource(placement_constraints,
rsc_entry, rsc_lh,node);
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
crm_warn("Dont know what to do for cancelled ops yet");
break;
}
}
return TRUE;
}
gboolean
unpack_failed_resource(GListPtr *placement_constraints,
xmlNodePtr rsc_entry, resource_t *rsc_lh, node_t *node)
{
const char *last_op = xmlGetProp(rsc_entry, "last_op");
crm_debug("Unpacking failed action %s on %s", last_op, rsc_lh->id);
/* make sure we dont allocate the resource here again*/
rsc2node_new("dont_run__generated",
rsc_lh, -1.0, FALSE, node, placement_constraints);
if(safe_str_eq(last_op, "start")) {
/* the resource is not actually running... nothing more to do*/
return TRUE;
}
switch(rsc_lh->stopfail_type) {
case pesf_stonith:
/* treat it as if it is still running
* but also mark the node as unclean
*/
native_add_running(rsc_lh, node);
node->details->running_rsc = g_list_append(
node->details->running_rsc, rsc_lh);
if(node->details->online) {
node->details->shutdown = TRUE;
}
node->details->unclean = TRUE;
break;
case pesf_block:
/* let this depend on the stop action which will fail
* but make sure the transition continues...
*/
native_add_running(rsc_lh, node);
node->details->running_rsc = g_list_append(
node->details->running_rsc, rsc_lh);
/* rsc_lh->stop->timeout = NULL; /\* wait forever *\/ */
break;
case pesf_ignore:
/* pretend nothing happened */
break;
}
return TRUE;
}
gboolean
unpack_healthy_resource(GListPtr *placement_constraints, GListPtr *actions,
xmlNodePtr rsc_entry, resource_t *rsc_lh, node_t *node)
{
const char *last_op = xmlGetProp(rsc_entry, "last_op");
crm_debug("Unpacking healthy action %s on %s", last_op, rsc_lh->id);
if(safe_str_neq(last_op, "stop")) {
/* create the link between this node and the rsc */
crm_verbose("Setting cur_node = %s for rsc = %s",
node->details->uname, rsc_lh->id);
native_add_running(rsc_lh, node);
node->details->running_rsc = g_list_append(
node->details->running_rsc, rsc_lh);
}
return TRUE;
}
gboolean
rsc_dependancy_new(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh)
{
rsc_dependancy_t *new_con = NULL;
rsc_dependancy_t *inverted_con = NULL;
if(rsc_lh == NULL || rsc_rh == NULL){
/* error */
return FALSE;
}
crm_malloc(new_con, sizeof(rsc_dependancy_t));
if(new_con != NULL) {
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("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("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);
} else {
return FALSE;
}
return TRUE;
}
gboolean
order_new(resource_t *lh_rsc, enum action_tasks lh_action_task, action_t *lh_action,
resource_t *rh_rsc, enum action_tasks rh_action_task, action_t *rh_action,
enum con_strength strength, GListPtr *ordering_constraints)
{
order_constraint_t *order = NULL;
if((lh_action == NULL && lh_rsc == NULL)
|| (rh_action == NULL && rh_rsc == NULL)
|| ordering_constraints == NULL){
crm_err("Invalid inputs lh_rsc=%p, lh_a=%p,"
" rh_rsc=%p, rh_a=%p, l=%p",
lh_rsc, lh_action, rh_rsc, rh_action,
ordering_constraints);
return FALSE;
}
crm_malloc(order, sizeof(order_constraint_t));
if(order == NULL) {
return FALSE;
}
order->id = order_id++;
order->strength = strength;
order->lh_rsc = lh_rsc;
order->rh_rsc = rh_rsc;
order->lh_action = lh_action;
order->rh_action = rh_action;
order->lh_action_task = lh_action_task;
order->rh_action_task = rh_action_task;
*ordering_constraints = g_list_append(
*ordering_constraints, order);
if(lh_rsc != NULL && rh_rsc != NULL) {
crm_info("Created ordering constraint %d (%s):"
" %s/%s before %s/%s",
order->id, strength2text(order->strength),
lh_rsc->id, task2text(lh_action_task),
rh_rsc->id, task2text(rh_action_task));
} else if(lh_rsc != NULL) {
crm_info("Created ordering constraint %d (%s):"
" %s/%s before action %d (%s)",
order->id, strength2text(order->strength),
lh_rsc->id, task2text(lh_action_task),
rh_action->id, task2text(rh_action_task));
} else if(rh_rsc != NULL) {
crm_info("Created ordering constraint %d (%s):"
" action %d (%s) before %s/%s",
order->id, strength2text(order->strength),
lh_action->id, task2text(lh_action_task),
rh_rsc->id, task2text(rh_action_task));
} else {
crm_info("Created ordering constraint %d (%s):"
" action %d (%s) before action %d (%s)",
order->id, strength2text(order->strength),
lh_action->id, task2text(lh_action_task),
rh_action->id, task2text(rh_action_task));
}
return TRUE;
}
gboolean
unpack_rsc_dependancy(xmlNodePtr xml_obj,
GListPtr rsc_list,
GListPtr *ordering_constraints)
{
enum con_strength strength_e = pecs_ignore;
const char *id_lh = xmlGetProp(xml_obj, "from");
const char *id = xmlGetProp(xml_obj, XML_ATTR_ID);
const char *id_rh = xmlGetProp(xml_obj, "to");
const char *type = xmlGetProp(xml_obj, XML_ATTR_TYPE);
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh);
if(rsc_lh == NULL) {
crm_err("No resource (con=%s, rsc=%s)", id, id_lh);
return FALSE;
} else if(rsc_rh == NULL) {
crm_err("No resource (con=%s, rsc=%s)", id, id_rh);
return FALSE;
}
if(safe_str_eq(type, XML_STRENGTH_VAL_MUST)) {
strength_e = pecs_must;
} else if(safe_str_eq(type, XML_STRENGTH_VAL_SHOULD)) {
crm_err("Type %s is no longer supported", type);
strength_e = pecs_must;
} else if(safe_str_eq(type, XML_STRENGTH_VAL_SHOULDNOT)) {
crm_err("Type %s is no longer supported", type);
strength_e = pecs_must_not;
} else if(safe_str_eq(type, XML_STRENGTH_VAL_MUSTNOT)) {
strength_e = pecs_must_not;
} else {
crm_err("Unknown value for %s: %s", "type", type);
return FALSE;
}
return rsc_dependancy_new(id, strength_e, rsc_lh, rsc_rh);
}
gboolean
unpack_rsc_order(
xmlNodePtr xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints)
{
gboolean symetrical_bool = TRUE;
gboolean action_is_start = TRUE;
gboolean type_is_after = TRUE;
const char *id = xmlGetProp(xml_obj, XML_ATTR_ID);
const char *id_lh = xmlGetProp(xml_obj, "from");
const char *id_rh = xmlGetProp(xml_obj, "to");
const char *action = xmlGetProp(xml_obj, "action");
const char *symetrical = xmlGetProp(xml_obj, "symetrical");
const char *type = xmlGetProp(xml_obj, XML_ATTR_TYPE);
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh);
if(xml_obj == NULL) {
crm_err("No constraint object to process.");
return FALSE;
} else if(id == NULL) {
crm_err("%s constraint must have an id", xml_obj->name);
return FALSE;
} else if(rsc_lh == NULL || rsc_rh == NULL) {
crm_err("Constraint %s needs two sides lh: %p rh: %p"
" (NULL indicates missing side)",
id, rsc_lh, rsc_rh);
return FALSE;
}
if(safe_str_eq(symetrical, "false")) {
symetrical_bool = FALSE;
}
if(safe_str_eq(type, "before")) {
type_is_after = FALSE;
}
if(safe_str_eq(action, "stop")) {
action_is_start = FALSE;
}
#if 1
if(type_is_after && action_is_start) {
if(symetrical_bool || action_is_start == FALSE) {
order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL,
pecs_startstop, ordering_constraints);
}
if(symetrical_bool || action_is_start) {
order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL,
pecs_startstop, ordering_constraints);
}
} else if(action_is_start) {
if(symetrical_bool || action_is_start == FALSE) {
order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL,
pecs_startstop, ordering_constraints);
}
if(symetrical_bool || action_is_start) {
order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL,
pecs_startstop, ordering_constraints);
}
}
#else
if(type_is_after) {
order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL,
pecs_startstop, ordering_constraints);
order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL,
pecs_startstop, ordering_constraints);
} else {
order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL,
pecs_startstop, ordering_constraints);
order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL,
pecs_startstop, ordering_constraints);
}
#endif
return TRUE;
}
/* do NOT free the nodes returned here */
GListPtr
match_attrs(const char *attr, const char *op, const char *value,
const char *type, GListPtr node_list)
{
GListPtr result = NULL;
if(attr == NULL || op == NULL) {
crm_err("Invlaid attribute or operation in expression"
" (\'%s\' \'%s\' \'%s\')",
crm_str(attr), crm_str(op), crm_str(value));
return NULL;
}
slist_iter(
node, node_t, node_list, lpc,
gboolean accept = FALSE;
int cmp = 0;
const char *h_val = (const char*)g_hash_table_lookup(
node->details->attrs, attr);
if(value != NULL && h_val != NULL) {
if(type == NULL || (safe_str_eq(type, "string"))) {
cmp = strcmp(h_val, value);
} else if(safe_str_eq(type, "number")) {
float h_val_f = atof(h_val);
float value_f = atof(value);
if(h_val_f < value_f) {
cmp = -1;
} else if(h_val_f > value_f) {
cmp = 1;
} else {
cmp = 0;
}
} else if(safe_str_eq(type, "version")) {
cmp = compare_version(h_val, value);
}
} else if(value == NULL && h_val == NULL) {
cmp = 0;
} else if(value == NULL) {
cmp = 1;
} else {
cmp = -1;
}
if(safe_str_eq(op, "exists")) {
if(h_val != NULL) accept = TRUE;
} else if(safe_str_eq(op, "notexists")) {
if(h_val == NULL) accept = TRUE;
} else if(safe_str_eq(op, "running")) {
GListPtr rsc_list = node->details->running_rsc;
slist_iter(
rsc, resource_t, rsc_list, lpc2,
if(safe_str_eq(rsc->id, attr)) {
accept = TRUE;
}
);
} else if(safe_str_eq(op, "not_running")) {
GListPtr rsc_list = node->details->running_rsc;
accept = TRUE;
slist_iter(
rsc, resource_t, rsc_list, lpc2,
if(safe_str_eq(rsc->id, attr)) {
accept = FALSE;
break;
}
);
} else if(safe_str_eq(op, "eq")) {
if((h_val == value) || cmp == 0)
accept = TRUE;
} else if(safe_str_eq(op, "ne")) {
if((h_val == NULL && value != NULL)
|| (h_val != NULL && value == NULL)
|| cmp != 0)
accept = TRUE;
} else if(value == NULL || h_val == NULL) {
/* the comparision is meaningless from this point on */
accept = FALSE;
} else if(safe_str_eq(op, "lt")) {
if(cmp < 0) accept = TRUE;
} else if(safe_str_eq(op, "lte")) {
if(cmp <= 0) accept = TRUE;
} else if(safe_str_eq(op, "gt")) {
if(cmp > 0) accept = TRUE;
} else if(safe_str_eq(op, "gte")) {
if(cmp >= 0) accept = TRUE;
}
if(accept) {
crm_trace("node %s matched", node->details->uname);
result = g_list_append(result, node);
} else {
crm_trace("node %s did not match", node->details->uname);
}
);
return result;
}
gboolean
add_node_attrs(xmlNodePtr attrs, node_t *node)
{
const char *name = NULL;
const char *value = NULL;
while(attrs != NULL){
name = xmlGetProp(attrs, XML_NVPAIR_ATTR_NAME);
value = xmlGetProp(attrs, XML_NVPAIR_ATTR_VALUE);
if(name != NULL
&& value != NULL
&& safe_val(NULL, node, details) != NULL) {
crm_verbose("Adding %s => %s", name, value);
/* this is frustrating... no way to pass in const
* keys or values yet docs say:
* Note: If keys and/or values are dynamically
* allocated, you should free them first.
*/
g_hash_table_insert(node->details->attrs,
crm_strdup(name),
crm_strdup(value));
}
attrs = attrs->next;
}
g_hash_table_insert(node->details->attrs,
crm_strdup("uname"),
crm_strdup(node->details->uname));
g_hash_table_insert(node->details->attrs,
crm_strdup("id"),
crm_strdup(node->details->id));
return TRUE;
}
gboolean
unpack_rsc_location(
xmlNodePtr xml_obj,
GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints)
{
/*
<constraints>
<rsc_location rsc="Filesystem-whatever-1" timestamp="..." lifetime="...">
<rule score="+50.0" result="can">
<!ATTLIST node_expression
id CDATA #REQUIRED
attribute CDATA #REQUIRED
operation (lt|gt|lte|gte|eq|ne|exists|notexists)
value CDATA #IMPLIED
type (integer|string|version) 'string'>
</rule>
<rule score="+500.0">
<node_expression match="cpu:50GHz" />
</rule>
<rule result="cannot">
<node_expression not_match="san"/>
</rule>
...
Translation:
Further translation:
*/
gboolean were_rules = FALSE;
const char *id_lh = xmlGetProp(xml_obj, "rsc");
const char *id = xmlGetProp(xml_obj, XML_ATTR_ID);
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
if(rsc_lh == NULL) {
crm_err("No resource (con=%s, rsc=%s)",
id, id_lh);
return FALSE;
}
xml_child_iter(
xml_obj, rule, "rule",
gboolean first_expr = TRUE;
gboolean can_run = FALSE;
gboolean do_and = TRUE;
gboolean rule_has_expressions;
const char *rule_id = xmlGetProp(rule, XML_ATTR_ID);
const char *score = xmlGetProp(rule, "score");
const char *result = xmlGetProp(rule, "result");
const char *boolean = xmlGetProp(rule, "boolean_op");
GListPtr match_L = NULL;
GListPtr old_list = NULL;
float score_f = atof(score?score:"0.0");
rsc_to_node_t *new_con = NULL;
were_rules = TRUE;
if(safe_str_eq(boolean, "or")) {
do_and = FALSE;
}
if(result == NULL || (safe_str_eq(result, "can"))) {
can_run = TRUE;
}
new_con = rsc2node_new(rule_id, rsc_lh, score_f,
can_run, NULL, placement_constraints);
if(new_con == NULL) {
continue;
}
rule_has_expressions = FALSE;
xml_child_iter(
rule, expr, "expression",
const char *attr = xmlGetProp(expr, "attribute");
const char *op = xmlGetProp(expr, "operation");
const char *value = xmlGetProp(expr, "value");
const char *type = xmlGetProp(expr, "type");
rule_has_expressions = TRUE;
crm_trace("processing expression: %s",
xmlGetProp(expr, "id"));
match_L = match_attrs(
attr, op, value, type, node_list);
if(first_expr) {
new_con->node_list_rh = node_list_dup(
match_L, FALSE);
first_expr = FALSE;
continue;
}
old_list = new_con->node_list_rh;
if(do_and) {
crm_trace("do_and");
new_con->node_list_rh = node_list_and(
old_list, match_L, FALSE);
} else {
crm_trace("do_or");
new_con->node_list_rh = node_list_or(
old_list, match_L, FALSE);
}
pe_free_shallow_adv(match_L, FALSE);
pe_free_shallow_adv(old_list, TRUE);
);
if(rule_has_expressions == FALSE) {
/* feels like a hack */
crm_debug("Rule %s had no expressions,"
" adding all nodes", xmlGetProp(rule, "id"));
new_con->node_list_rh = node_list_dup(node_list,FALSE);
}
if(new_con->node_list_rh == NULL) {
crm_warn("No matching nodes for constraint/rule %s/%s",
id, xmlGetProp(rule, "id"));
}
crm_debug_action(print_rsc_to_node("Added", new_con, FALSE));
);
if(were_rules == FALSE) {
crm_err("no rules for constraint %s", id);
}
return TRUE;
}

File Metadata

Mime Type
text/x-c
Expires
Thu, Oct 16, 3:05 PM (11 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2536459
Default Alt Text
unpack.c (32 KB)

Event Timeline