Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3687381
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/pengine/allocate.c b/crm/pengine/allocate.c
index 2a32d656b5..5760dfdfc1 100644
--- a/crm/pengine/allocate.c
+++ b/crm/pengine/allocate.c
@@ -1,1347 +1,1359 @@
/* $Id: allocate.c,v 1.12 2006/08/14 09:06:31 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <clplumbing/cl_misc.h>
#include <glib.h>
#include <crm/pengine/status.h>
#include <pengine.h>
#include <allocate.h>
#include <utils.h>
#include <lib/crm/pengine/utils.h>
void set_alloc_actions(pe_working_set_t *data_set);
resource_alloc_functions_t resource_class_alloc_functions[] = {
{
native_set_cmds,
native_num_allowed_nodes,
native_color,
native_create_actions,
native_create_probe,
native_internal_constraints,
native_agent_constraints,
native_rsc_colocation_lh,
native_rsc_colocation_rh,
native_rsc_order_lh,
native_rsc_order_rh,
native_rsc_location,
native_expand,
native_stonith_ordering,
native_create_notify_element,
},
{
group_set_cmds,
group_num_allowed_nodes,
group_color,
group_create_actions,
group_create_probe,
group_internal_constraints,
group_agent_constraints,
group_rsc_colocation_lh,
group_rsc_colocation_rh,
group_rsc_order_lh,
group_rsc_order_rh,
group_rsc_location,
group_expand,
group_stonith_ordering,
group_create_notify_element,
},
{
clone_set_cmds,
clone_num_allowed_nodes,
clone_color,
clone_create_actions,
clone_create_probe,
clone_internal_constraints,
clone_agent_constraints,
clone_rsc_colocation_lh,
clone_rsc_colocation_rh,
clone_rsc_order_lh,
clone_rsc_order_rh,
clone_rsc_location,
clone_expand,
clone_stonith_ordering,
clone_create_notify_element,
},
{
clone_set_cmds,
clone_num_allowed_nodes,
master_color,
master_create_actions,
clone_create_probe,
master_internal_constraints,
clone_agent_constraints,
clone_rsc_colocation_lh,
master_rsc_colocation_rh,
clone_rsc_order_lh,
clone_rsc_order_rh,
clone_rsc_location,
clone_expand,
clone_stonith_ordering,
clone_create_notify_element,
}
};
static gboolean
check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry,
pe_working_set_t *data_set)
{
int attr_lpc = 0;
gboolean force_restart = FALSE;
gboolean delete_resource = FALSE;
const char *value = NULL;
const char *old_value = NULL;
const char *attr_list[] = {
XML_ATTR_TYPE,
XML_AGENT_ATTR_CLASS,
XML_AGENT_ATTR_PROVIDER
};
for(; attr_lpc < DIMOF(attr_list); attr_lpc++) {
value = crm_element_value(rsc->xml, attr_list[attr_lpc]);
old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]);
if(safe_str_eq(value, old_value)) {
continue;
}
force_restart = TRUE;
crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s",
rsc->id, node->details->uname, attr_list[attr_lpc],
crm_str(old_value), crm_str(value));
}
if(force_restart) {
/* make sure the restart happens */
stop_action(rsc, node, FALSE);
rsc->start_pending = TRUE;
delete_resource = TRUE;
}
return delete_resource;
}
static gboolean
check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op,
pe_working_set_t *data_set)
{
char *key = NULL;
int interval = 0;
const char *interval_s = NULL;
gboolean did_change = FALSE;
crm_data_t *pnow = NULL;
GHashTable *local_rsc_params = NULL;
char *pnow_digest = NULL;
const char *param_digest = NULL;
char *local_param_digest = NULL;
#if CRM_DEPRECATED_SINCE_2_0_4
crm_data_t *params = NULL;
#endif
action_t *action = NULL;
const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
CRM_CHECK(active_node != NULL, return FALSE);
interval_s = get_interval(xml_op);
interval = crm_parse_int(interval_s, "0");
key = generate_op_key(rsc->id, task, interval);
if(interval > 0) {
crm_data_t *op_match = NULL;
crm_debug_2("Checking parameters for %s %s", key, task);
op_match = find_rsc_op_entry(rsc, key);
if(op_match == NULL && data_set->stop_action_orphans) {
/* create a cancel action */
action_t *cancel = NULL;
char *cancel_key = NULL;
crm_info("Orphan action will be stopped: %s on %s",
key, active_node->details->uname);
cancel_key = generate_op_key(rsc->id, CRMD_ACTION_CANCEL, interval);
cancel = custom_action(
rsc, cancel_key, CRMD_ACTION_CANCEL,
active_node, FALSE, TRUE, data_set);
add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task);
add_hash_param(cancel->meta,
XML_LRM_ATTR_INTERVAL, interval_s);
custom_action_order(
rsc, NULL, cancel,
rsc, stop_key(rsc), NULL,
pe_ordering_optional, data_set);
}
if(op_match == NULL) {
crm_debug("Orphan action detected: %s on %s",
key, active_node->details->uname);
crm_free(key); key = NULL;
return TRUE;
}
}
action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set);
local_rsc_params = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
unpack_instance_attributes(
rsc->xml, XML_TAG_ATTR_SETS, active_node->details->attrs,
local_rsc_params, NULL, data_set->now);
pnow = create_xml_node(NULL, XML_TAG_PARAMS);
g_hash_table_foreach(action->extra, hash2field, pnow);
g_hash_table_foreach(rsc->parameters, hash2field, pnow);
g_hash_table_foreach(local_rsc_params, hash2field, pnow);
filter_action_parameters(pnow, op_version);
pnow_digest = calculate_xml_digest(pnow, TRUE);
param_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
#if CRM_DEPRECATED_SINCE_2_0_4
if(param_digest == NULL) {
params = find_xml_node(xml_op, XML_TAG_PARAMS, TRUE);
}
if(params != NULL) {
crm_data_t *local_params = copy_xml(params);
crm_warn("Faking parameter digest creation for %s", ID(xml_op));
filter_action_parameters(local_params, op_version);
xml_remove_prop(local_params, "interval");
xml_remove_prop(local_params, "timeout");
crm_log_xml_warn(local_params, "params:used");
local_param_digest = calculate_xml_digest(local_params, TRUE);
param_digest = local_param_digest;
free_xml(local_params);
}
#endif
if(safe_str_neq(pnow_digest, param_digest)) {
did_change = TRUE;
crm_log_xml_info(pnow, "params:calc");
crm_warn("Parameters to %s on %s changed: recorded %s vs. calculated %s",
ID(xml_op), active_node->details->uname,
crm_str(param_digest), pnow_digest);
key = generate_op_key(rsc->id, task, interval);
custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
}
free_xml(pnow);
crm_free(pnow_digest);
crm_free(local_param_digest);
g_hash_table_destroy(local_rsc_params);
pe_free_action(action);
return did_change;
}
extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set);
static void
check_actions_for(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set)
{
const char *id = NULL;
const char *task = NULL;
int interval = 0;
const char *interval_s = NULL;
GListPtr op_list = NULL;
GListPtr sorted_op_list = NULL;
const char *rsc_id = ID(rsc_entry);
gboolean is_probe = FALSE;
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
CRM_CHECK(rsc_id != NULL, return);
if(rsc == NULL) {
crm_warn("Skipping param check for resource with no actions");
return;
} else if(rsc->orphan) {
crm_debug_2("Skipping param check for orphan: %s %s",
rsc->id, task);
return;
}
crm_debug_2("Processing %s on %s", rsc->id, node->details->uname);
if(check_rsc_parameters(rsc, node, rsc_entry, data_set)) {
DeleteRsc(rsc, node, data_set);
}
xml_child_iter_filter(
rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
op_list = g_list_append(op_list, rsc_op);
);
sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
slist_iter(
rsc_op, crm_data_t, sorted_op_list, lpc,
id = ID(rsc_op);
is_probe = FALSE;
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
interval_s = get_interval(rsc_op);
interval = crm_parse_int(interval_s, "0");
if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) {
is_probe = TRUE;
}
if(is_probe || safe_str_eq(task, CRMD_ACTION_START) || interval > 0) {
crm_debug_2("Checking resource definition: %s", rsc->id);
check_action_definition(rsc, node, rsc_op, data_set);
}
crm_debug_3("Ignoring %s params: %s", task, id);
);
g_list_free(sorted_op_list);
}
static void
check_actions(pe_working_set_t *data_set)
{
const char *id = NULL;
node_t *node = NULL;
crm_data_t *lrm_rscs = NULL;
crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
xml_child_iter_filter(
status, node_state, XML_CIB_TAG_STATE,
id = crm_element_value(node_state, XML_ATTR_ID);
lrm_rscs = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
lrm_rscs = find_xml_node(lrm_rscs, XML_LRM_TAG_RESOURCES, FALSE);
node = pe_find_node_id(data_set->nodes, id);
if(node == NULL) {
continue;
}
crm_debug("Processing node %s", node->details->uname);
if(node->details->online || data_set->stonith_enabled) {
xml_child_iter_filter(
lrm_rscs, rsc_entry, XML_LRM_TAG_RESOURCE,
check_actions_for(rsc_entry, node, data_set);
);
}
);
}
static gboolean
apply_placement_constraints(pe_working_set_t *data_set)
{
crm_debug_3("Applying constraints...");
slist_iter(
cons, rsc_to_node_t, data_set->placement_constraints, lpc,
cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons);
);
return TRUE;
}
void
set_alloc_actions(pe_working_set_t *data_set)
{
slist_iter(
rsc, resource_t, data_set->resources, lpc,
rsc->cmds = &resource_class_alloc_functions[rsc->variant];
rsc->cmds->set_cmds(rsc);
);
}
gboolean
stage0(pe_working_set_t *data_set)
{
crm_data_t * cib_constraints = get_object_root(
XML_CIB_TAG_CONSTRAINTS, data_set->input);
if(data_set->input == NULL) {
return FALSE;
}
cluster_status(data_set);
set_alloc_actions(data_set);
unpack_constraints(cib_constraints, data_set);
return TRUE;
}
/*
* Check nodes for resources started outside of the LRM
*/
gboolean
stage1(pe_working_set_t *data_set)
{
action_t *probe_complete = NULL;
action_t *probe_node_complete = NULL;
slist_iter(
node, node_t, data_set->nodes, lpc,
gboolean force_probe = FALSE;
const char *probed = g_hash_table_lookup(
node->details->attrs, CRM_OP_PROBED);
crm_debug_2("%s probed: %s", node->details->uname, probed);
if(node->details->online == FALSE) {
continue;
} else if(node->details->unclean) {
continue;
} else if(probe_complete == NULL) {
probe_complete = custom_action(
NULL, crm_strdup(CRM_OP_PROBED),
CRM_OP_PROBED, NULL, FALSE, TRUE,
data_set);
probe_complete->pseudo = TRUE;
probe_complete->optional = TRUE;
}
if(probed != NULL && crm_is_true(probed) == FALSE) {
force_probe = TRUE;
}
probe_node_complete = custom_action(
NULL, crm_strdup(CRM_OP_PROBED),
CRM_OP_PROBED, node, FALSE, TRUE, data_set);
probe_node_complete->optional = crm_is_true(probed);
probe_node_complete->priority = INFINITY;
add_hash_param(probe_node_complete->meta,
XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
custom_action_order(NULL, NULL, probe_node_complete,
NULL, NULL, probe_complete,
pe_ordering_optional, data_set);
slist_iter(
rsc, resource_t, data_set->resources, lpc2,
if(rsc->cmds->create_probe(
rsc, node, probe_node_complete,
force_probe, data_set)) {
probe_complete->optional = FALSE;
probe_node_complete->optional = FALSE;
custom_action_order(
NULL, NULL, probe_complete,
rsc, start_key(rsc), NULL,
pe_ordering_manditory, data_set);
}
);
);
return TRUE;
}
/*
* Count how many valid nodes we have (so we know the maximum number of
* colors we can resolve).
*
* Apply node constraints (ie. filter the "allowed_nodes" part of resources
*/
gboolean
stage2(pe_working_set_t *data_set)
{
crm_debug_3("Applying placement constraints");
slist_iter(
node, node_t, data_set->nodes, lpc,
if(node == NULL) {
/* error */
} else if(node->weight >= 0.0 /* global weight */
&& node->details->online
&& node->details->type == node_member) {
data_set->max_valid_nodes++;
}
);
apply_placement_constraints(data_set);
return TRUE;
}
/*
* Create internal resource constraints before allocation
*/
gboolean
stage3(pe_working_set_t *data_set)
{
slist_iter(
rsc, resource_t, data_set->resources, lpc,
rsc->cmds->internal_constraints(rsc, data_set);
);
return TRUE;
}
/*
* Check for orphaned or redefined actions
*/
gboolean
stage4(pe_working_set_t *data_set)
{
check_actions(data_set);
return TRUE;
}
gboolean
stage5(pe_working_set_t *data_set)
{
/* Take (next) highest resource, assign it and create its actions */
slist_iter(
rsc, resource_t, data_set->resources, lpc,
rsc->cmds->color(rsc, data_set);
rsc->cmds->create_actions(rsc, data_set);
);
return TRUE;
}
/*
* Create dependacies for stonith and shutdown operations
*/
gboolean
stage6(pe_working_set_t *data_set)
{
action_t *dc_down = NULL;
action_t *stonith_op = NULL;
action_t *last_stonith = NULL;
gboolean integrity_lost = FALSE;
crm_debug_3("Processing fencing and shutdown cases");
slist_iter(
node, node_t, data_set->nodes, lpc,
stonith_op = NULL;
if(node->details->unclean && data_set->stonith_enabled
&& (data_set->have_quorum
|| data_set->no_quorum_policy == no_quorum_ignore)) {
pe_warn("Scheduling Node %s for STONITH",
node->details->uname);
stonith_op = custom_action(
NULL, crm_strdup(CRM_OP_FENCE),
CRM_OP_FENCE, node, FALSE, TRUE, data_set);
add_hash_param(
stonith_op->meta, XML_LRM_ATTR_TARGET,
node->details->uname);
add_hash_param(
stonith_op->meta, XML_LRM_ATTR_TARGET_UUID,
node->details->id);
add_hash_param(
stonith_op->meta, "stonith_action",
data_set->stonith_action);
stonith_constraints(node, stonith_op, data_set);
if(node->details->is_dc) {
dc_down = stonith_op;
} else {
if(last_stonith) {
order_actions(last_stonith, stonith_op, pe_ordering_manditory);
}
last_stonith = stonith_op;
}
} else if(node->details->online && node->details->shutdown) {
action_t *down_op = NULL;
crm_info("Scheduling Node %s for shutdown",
node->details->uname);
down_op = custom_action(
NULL, crm_strdup(CRM_OP_SHUTDOWN),
CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set);
shutdown_constraints(node, down_op, data_set);
if(node->details->is_dc) {
dc_down = down_op;
}
}
if(node->details->unclean && stonith_op == NULL) {
integrity_lost = TRUE;
pe_warn("Node %s is unclean!", node->details->uname);
}
);
if(integrity_lost) {
if(data_set->have_quorum == FALSE) {
crm_notice("Cannot fence unclean nodes until quorum is"
" attained (or no_quorum_policy is set to ignore)");
} else if(data_set->stonith_enabled == FALSE) {
pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED");
pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE");
}
}
if(dc_down != NULL) {
GListPtr shutdown_matches = find_actions(
data_set->actions, CRM_OP_SHUTDOWN, NULL);
crm_debug_2("Ordering shutdowns before %s on %s (DC)",
dc_down->task, dc_down->node->details->uname);
add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT,
XML_BOOLEAN_TRUE);
slist_iter(
node_stop, action_t, shutdown_matches, lpc,
if(node_stop->node->details->is_dc) {
continue;
}
crm_debug("Ordering shutdown on %s before %s on %s",
node_stop->node->details->uname,
dc_down->task, dc_down->node->details->uname);
order_actions(node_stop, dc_down, pe_ordering_manditory);
);
if(last_stonith && dc_down != last_stonith) {
order_actions(last_stonith, dc_down, pe_ordering_manditory);
}
}
return TRUE;
}
/*
* Determin the sets of independant actions and the correct order for the
* actions in each set.
*
* Mark dependencies of un-runnable actions un-runnable
*
*/
gboolean
stage7(pe_working_set_t *data_set)
{
crm_debug_3("Applying ordering constraints");
slist_iter(
order, order_constraint_t, data_set->ordering_constraints, lpc,
- /* try rsc_action-to-rsc_action */
resource_t *rsc = order->lh_rsc;
- if(rsc == NULL && order->lh_action) {
- rsc = order->lh_action->rsc;
- }
+ crm_debug_2("Applying ordering constraint: %d", order->id);
if(rsc != NULL) {
+ crm_debug_3("rsc_action-to-*");
rsc->cmds->rsc_order_lh(rsc, order);
continue;
}
- /* try action-to-rsc_action */
-
- /* que off the rh resource */
rsc = order->rh_rsc;
- if(rsc == NULL && order->rh_action) {
- rsc = order->rh_action->rsc;
- }
-
if(rsc != NULL) {
+ crm_debug_3("action-to-rsc_action");
rsc->cmds->rsc_order_rh(order->lh_action, rsc, order);
+
} else {
- /* fall back to action-to-action */
+ crm_debug_3("action-to-action");
order_actions(
order->lh_action, order->rh_action, order->type);
}
-
);
update_action_states(data_set->actions);
return TRUE;
}
int transition_id = -1;
/*
* Create a dependency graph to send to the transitioner (via the CRMd)
*/
gboolean
stage8(pe_working_set_t *data_set)
{
const char *value = NULL;
char *transition_id_s = NULL;
transition_id++;
transition_id_s = crm_itoa(transition_id);
value = pe_pref(data_set->config_hash, "network-delay");
crm_debug("Creating transition graph %d.", transition_id);
data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
crm_xml_add(data_set->graph, "network-delay", value);
crm_xml_add(data_set->graph, "transition_id", transition_id_s);
crm_free(transition_id_s);
/* errors...
slist_iter(action, action_t, action_list, lpc,
if(action->optional == FALSE && action->runnable == FALSE) {
print_action("Ignoring", action, TRUE);
}
);
*/
slist_iter(
rsc, resource_t, data_set->resources, lpc,
crm_debug_4("processing actions for rsc=%s", rsc->id);
rsc->cmds->expand(rsc, data_set);
);
crm_log_xml_debug_3(
data_set->graph, "created resource-driven action list");
/* catch any non-resource specific actions */
crm_debug_4("processing non-resource actions");
slist_iter(
action, action_t, data_set->actions, lpc,
graph_element_from_action(action, data_set);
);
crm_log_xml_debug_3(data_set->graph, "created generic action list");
crm_notice("Created transition graph %d.", transition_id);
return TRUE;
}
void
cleanup_alloc_calculations(pe_working_set_t *data_set)
{
if(data_set == NULL) {
return;
}
crm_debug_3("deleting order cons: %p", data_set->ordering_constraints);
pe_free_ordering(data_set->ordering_constraints);
data_set->ordering_constraints = NULL;
crm_debug_3("deleting node cons: %p", data_set->placement_constraints);
pe_free_rsc_to_node(data_set->placement_constraints);
data_set->placement_constraints = NULL;
cleanup_calculations(data_set);
}
gboolean
unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set)
{
crm_data_t *lifetime = NULL;
crm_debug_2("Begining unpack... %s",
xml_constraints?crm_element_name(xml_constraints):"<none>");
xml_child_iter(
xml_constraints, xml_obj,
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
if(id == NULL) {
crm_config_err("Constraint <%s...> must have an id",
crm_element_name(xml_obj));
continue;
}
crm_debug_3("Processing constraint %s %s",
crm_element_name(xml_obj),id);
lifetime = cl_get_struct(xml_obj, "lifetime");
if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) {
crm_info("Constraint %s %s is not active",
crm_element_name(xml_obj), id);
} else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER,
crm_element_name(xml_obj))) {
unpack_rsc_order(xml_obj, data_set);
} else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND,
crm_element_name(xml_obj))) {
unpack_rsc_colocation(xml_obj, data_set);
} else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION,
crm_element_name(xml_obj))) {
unpack_rsc_location(xml_obj, data_set);
} else {
pe_err("Unsupported constraint type: %s",
crm_element_name(xml_obj));
}
);
return TRUE;
}
static const char *
invert_action(const char *action)
{
if(safe_str_eq(action, CRMD_ACTION_START)) {
return CRMD_ACTION_STOP;
} else if(safe_str_eq(action, CRMD_ACTION_STOP)) {
return CRMD_ACTION_START;
} else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) {
return CRMD_ACTION_DEMOTE;
} else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) {
return CRMD_ACTION_PROMOTE;
+ } else if(safe_str_eq(action, CRMD_ACTION_PROMOTED)) {
+ return CRMD_ACTION_DEMOTED;
+
+ } else if(safe_str_eq(action, CRMD_ACTION_DEMOTED)) {
+ return CRMD_ACTION_PROMOTED;
+
} else if(safe_str_eq(action, CRMD_ACTION_STARTED)) {
return CRMD_ACTION_STOPPED;
} else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) {
return CRMD_ACTION_STARTED;
}
pe_err("Unknown action: %s", action);
return NULL;
}
gboolean
unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set)
{
+ resource_t *rsc_lh = NULL;
+ resource_t *rsc_rh = NULL;
gboolean symmetrical_bool = TRUE;
enum pe_ordering cons_weight = pe_ordering_optional;
+
+ const char *id_rh = NULL;
+ const char *id_lh = NULL;
+ const char *action = NULL;
+ const char *action_rh = NULL;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE);
- const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
- const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
- const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
- const char *action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION);
-
const char *symmetrical = crm_element_value(
xml_obj, XML_CONS_ATTR_SYMMETRICAL);
- resource_t *rsc_lh = NULL;
- resource_t *rsc_rh = NULL;
-
+ cl_str_to_boolean(symmetrical, &symmetrical_bool);
+
if(xml_obj == NULL) {
crm_config_err("No constraint object to process.");
return FALSE;
} else if(id == NULL) {
crm_config_err("%s constraint must have an id",
crm_element_name(xml_obj));
return FALSE;
- } else if(id_lh == NULL || id_rh == NULL) {
- crm_config_err("Constraint %s needs two sides lh: %s rh: %s",
- id, crm_str(id_lh), crm_str(id_rh));
- return FALSE;
}
- if(action == NULL) {
- action = CRMD_ACTION_START;
- }
- if(action_rh == NULL) {
- action_rh = action;
- }
- CRM_CHECK(action != NULL, return FALSE);
- CRM_CHECK(action_rh != NULL, return FALSE);
-
if(safe_str_eq(type, "before")) {
id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
+ action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
+ action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION);
+
+ } else {
+ type="after";
+ id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
+ id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
action = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION);
action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
- if(action_rh == NULL) {
- action_rh = CRMD_ACTION_START;
- }
if(action == NULL) {
action = action_rh;
}
}
- CRM_CHECK(action != NULL, return FALSE);
- CRM_CHECK(action_rh != NULL, return FALSE);
+ if(id_lh == NULL || id_rh == NULL) {
+ crm_config_err("Constraint %s needs two sides lh: %s rh: %s",
+ id, crm_str(id_lh), crm_str(id_rh));
+ return FALSE;
+ }
+
+ if(action == NULL) {
+ action = CRMD_ACTION_START;
+ }
+ if(action_rh == NULL) {
+ action_rh = action;
+ }
rsc_lh = pe_find_resource(data_set->resources, id_rh);
rsc_rh = pe_find_resource(data_set->resources, id_lh);
+ crm_debug("%s: %s.%s %s %s.%s%s",
+ id, rsc_lh->id, action, type, rsc_rh->id, action_rh,
+ symmetrical_bool?" (symmetrical)":"");
+
if(rsc_lh == NULL) {
crm_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh);
return FALSE;
} else if(rsc_rh == NULL) {
crm_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh);
return FALSE;
}
if(crm_atoi(score, "0") > 0) {
/* the name seems weird but the effect is correct */
cons_weight = pe_ordering_restart;
}
custom_action_order(
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
cons_weight, data_set);
if(rsc_rh->restart_type == pe_restart_restart
&& safe_str_eq(action, action_rh)) {
if(safe_str_eq(action, CRMD_ACTION_START)) {
crm_debug_2("Recover %s.%s-%s.%s",
rsc_lh->id, action, rsc_rh->id, action_rh);
/* order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); */
custom_action_order(
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
pe_ordering_recover, data_set);
+
} else if(safe_str_eq(action, CRMD_ACTION_STOP)) {
crm_debug_2("Recover %s.%s-%s.%s",
rsc_rh->id, action_rh, rsc_lh->id, action);
/* order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); */
custom_action_order(
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
pe_ordering_recover, data_set);
}
}
- cl_str_to_boolean(symmetrical, &symmetrical_bool);
if(symmetrical_bool == FALSE) {
return TRUE;
}
action = invert_action(action);
action_rh = invert_action(action_rh);
if(action == NULL || action_rh == NULL) {
crm_config_err("Cannot invert rsc_order constraint %s."
" Please specify the inverse manually.", id);
return TRUE;
}
custom_action_order(
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
cons_weight, data_set);
if(rsc_lh->restart_type == pe_restart_restart
&& safe_str_eq(action, action_rh)) {
if(safe_str_eq(action, CRMD_ACTION_START)) {
crm_debug_2("Recover start-start (2): %s-%s",
rsc_lh->id, rsc_rh->id);
/* order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); */
custom_action_order(
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
pe_ordering_recover, data_set);
} else if(safe_str_eq(action, CRMD_ACTION_STOP)) {
crm_debug_2("Recover stop-stop (2): %s-%s",
rsc_rh->id, rsc_lh->id);
/* order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); */
custom_action_order(
rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL,
rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL,
pe_ordering_recover, data_set);
}
}
return TRUE;
}
gboolean
unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set)
{
gboolean empty = TRUE;
const char *id_lh = crm_element_value(xml_obj, "rsc");
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh);
if(rsc_lh == NULL) {
/* only a warn as BSC adds the constraint then the resource */
crm_config_warn("No resource (con=%s, rsc=%s)", id, id_lh);
return FALSE;
} else if(rsc_lh->is_managed == FALSE) {
crm_debug_2("Ignoring constraint %s: resource %s not managed",
id, id_lh);
return FALSE;
}
xml_child_iter_filter(
xml_obj, rule_xml, XML_TAG_RULE,
empty = FALSE;
crm_debug_2("Unpacking %s/%s", id, ID(rule_xml));
generate_location_rule(rsc_lh, rule_xml, data_set);
);
if(empty) {
crm_config_err("Invalid location constraint %s:"
" rsc_location must contain at least one rule",
ID(xml_obj));
}
return TRUE;
}
static int
get_node_score(const char *rule, const char *score, gboolean raw, node_t *node)
{
int score_f = 0;
if(score == NULL) {
pe_err("Rule %s: no score specified. Assuming 0.", rule);
} else if(raw) {
score_f = char2score(score);
} else {
const char *attr_score = g_hash_table_lookup(
node->details->attrs, score);
if(attr_score == NULL) {
crm_debug("Rule %s: node %s did not have a value for %s",
rule, node->details->uname, score);
score_f = -INFINITY;
} else {
crm_debug("Rule %s: node %s had value %s for %s",
rule, node->details->uname, attr_score, score);
score_f = char2score(attr_score);
}
}
return score_f;
}
rsc_to_node_t *
generate_location_rule(
resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set)
{
const char *rule_id = NULL;
const char *score = NULL;
const char *boolean = NULL;
const char *role = NULL;
GListPtr match_L = NULL;
int score_f = 0;
gboolean do_and = TRUE;
gboolean accept = TRUE;
gboolean raw_score = TRUE;
rsc_to_node_t *location_rule = NULL;
rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
crm_debug_2("Processing rule: %s", rule_id);
if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) {
pe_err("Bad role specified for %s: %s", rule_id, role);
return NULL;
}
score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
if(score != NULL) {
score_f = char2score(score);
} else {
score = crm_element_value(
rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE);
if(score == NULL) {
score = crm_element_value(
rule_xml, XML_RULE_ATTR_SCORE_MANGLED);
}
if(score != NULL) {
raw_score = FALSE;
}
}
if(safe_str_eq(boolean, "or")) {
do_and = FALSE;
}
location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set);
if(location_rule == NULL) {
return NULL;
}
if(role != NULL) {
crm_debug_2("Setting role filter: %s", role);
location_rule->role_filter = text2role(role);
}
if(do_and) {
match_L = node_list_dup(data_set->nodes, TRUE, FALSE);
slist_iter(
node, node_t, match_L, lpc,
node->weight = get_node_score(rule_id, score, raw_score, node);
);
}
xml_child_iter(
rule_xml, expr,
enum expression_type type = find_expression_type(expr);
crm_debug_2("Processing expression: %s", ID(expr));
if(type == not_expr) {
pe_err("Expression <%s id=%s...> is not valid",
crm_element_name(expr), crm_str(ID(expr)));
continue;
}
slist_iter(
node, node_t, data_set->nodes, lpc,
if(type == nested_rule) {
accept = test_rule(
expr, node->details->attrs,
RSC_ROLE_UNKNOWN, data_set->now);
} else {
accept = test_expression(
expr, node->details->attrs,
RSC_ROLE_UNKNOWN, data_set->now);
}
score_f = get_node_score(rule_id, score, raw_score, node);
/* if(accept && score_f == -INFINITY) { */
/* accept = FALSE; */
/* } */
if(accept) {
node_t *local = pe_find_node_id(
match_L, node->details->id);
if(local == NULL && do_and) {
continue;
} else if(local == NULL) {
local = node_copy(node);
match_L = g_list_append(match_L, local);
}
if(do_and == FALSE) {
local->weight = merge_weights(
local->weight, score_f);
}
crm_debug_2("node %s now has weight %d",
node->details->uname, local->weight);
} else if(do_and && !accept) {
/* remove it */
node_t *delete = pe_find_node_id(
match_L, node->details->id);
if(delete != NULL) {
match_L = g_list_remove(match_L,delete);
crm_debug_5("node %s did not match",
node->details->uname);
}
crm_free(delete);
}
);
);
location_rule->node_list_rh = match_L;
if(location_rule->node_list_rh == NULL) {
crm_debug_2("No matching nodes for rule %s", rule_id);
return NULL;
}
crm_debug_3("%s: %d nodes matched",
rule_id, g_list_length(location_rule->node_list_rh));
return location_rule;
}
gboolean
rsc_colocation_new(const char *id, const char *node_attr, int score,
resource_t *rsc_lh, resource_t *rsc_rh,
const char *state_lh, const char *state_rh)
{
rsc_colocation_t *new_con = NULL;
if(rsc_lh == NULL){
crm_config_err("No resource found for LHS %s", id);
return FALSE;
} else if(rsc_rh == NULL){
crm_config_err("No resource found for RHS of %s", id);
return FALSE;
}
crm_malloc0(new_con, sizeof(rsc_colocation_t));
if(new_con == NULL) {
return FALSE;
}
if(state_lh == NULL
|| safe_str_eq(state_lh, RSC_ROLE_STARTED_S)) {
state_lh = RSC_ROLE_UNKNOWN_S;
}
if(state_rh == NULL
|| safe_str_eq(state_rh, RSC_ROLE_STARTED_S)) {
state_rh = RSC_ROLE_UNKNOWN_S;
}
new_con->id = id;
new_con->rsc_lh = rsc_lh;
new_con->rsc_rh = rsc_rh;
new_con->score = score;
new_con->role_lh = text2role(state_lh);
new_con->role_rh = text2role(state_rh);
new_con->node_attribute = node_attr;
crm_debug_4("Adding constraint %s (%p) to %s",
new_con->id, new_con, rsc_lh->id);
rsc_lh->rsc_cons = g_list_insert_sorted(
rsc_lh->rsc_cons, new_con, sort_cons_strength);
return TRUE;
}
/* LHS before RHS */
gboolean
custom_action_order(
resource_t *lh_rsc, char *lh_action_task, action_t *lh_action,
resource_t *rh_rsc, char *rh_action_task, action_t *rh_action,
enum pe_ordering type, pe_working_set_t *data_set)
{
order_constraint_t *order = NULL;
+ if(lh_rsc == NULL && lh_action) {
+ lh_rsc = lh_action->rsc;
+ }
+ if(rh_rsc == NULL && rh_action) {
+ rh_rsc = rh_action->rsc;
+ }
if((lh_action == NULL && lh_rsc == NULL)
|| (rh_action == NULL && rh_rsc == NULL)){
- crm_config_err("Invalid inputs lh_rsc=%p, lh_a=%p,"
- " rh_rsc=%p, rh_a=%p",
+ crm_config_err("Invalid inputs %p.%p %p.%p",
lh_rsc, lh_action, rh_rsc, rh_action);
crm_free(lh_action_task);
crm_free(rh_action_task);
return FALSE;
}
-
+
crm_malloc0(order, sizeof(order_constraint_t));
if(order == NULL) { return FALSE; }
+
+ crm_debug_2("Creating ordering constraint %d",
+ data_set->order_id);
order->id = data_set->order_id++;
order->type = type;
order->lh_rsc = lh_rsc;
order->rh_rsc = rh_rsc;
order->lh_action = lh_action;
order->rh_action = rh_action;
order->lh_action_task = lh_action_task;
order->rh_action_task = rh_action_task;
data_set->ordering_constraints = g_list_append(
data_set->ordering_constraints, order);
if(lh_rsc != NULL && rh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" %s/%s before %s/%s",
order->id, ordering_type2text(order->type),
lh_rsc->id, lh_action_task,
rh_rsc->id, rh_action_task);
} else if(lh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" %s/%s before action %d (%s)",
order->id, ordering_type2text(order->type),
lh_rsc->id, lh_action_task,
rh_action->id, rh_action_task);
} else if(rh_rsc != NULL) {
crm_debug_4("Created ordering constraint %d (%s):"
" action %d (%s) before %s/%s",
order->id, ordering_type2text(order->type),
lh_action->id, lh_action_task,
rh_rsc->id, rh_action_task);
} else {
crm_debug_4("Created ordering constraint %d (%s):"
" action %d (%s) before action %d (%s)",
order->id, ordering_type2text(order->type),
lh_action->id, lh_action_task,
rh_action->id, rh_action_task);
}
return TRUE;
}
gboolean
unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set)
{
int score_i = 0;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE);
const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE);
const char *attr = crm_element_value(xml_obj, "node_attribute");
resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh);
resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh);
if(rsc_lh == NULL) {
crm_config_err("No resource (con=%s, rsc=%s)", id, id_lh);
return FALSE;
} else if(rsc_rh == NULL) {
crm_config_err("No resource (con=%s, rsc=%s)", id, id_rh);
return FALSE;
}
if(score) {
score_i = char2score(score);
}
return rsc_colocation_new(
id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh);
}
gboolean is_active(rsc_to_node_t *cons)
{
return TRUE;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 21, 7:19 PM (12 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1665488
Default Alt Text
(37 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment