Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/pengine/allocate.c b/pengine/allocate.c
index 932c91f416..0be5b35d77 100644
--- a/pengine/allocate.c
+++ b/pengine/allocate.c
@@ -1,2277 +1,2277 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <glib.h>
#include <crm/pengine/status.h>
#include <pengine.h>
#include <allocate.h>
#include <utils.h>
CRM_TRACE_INIT_DATA(pe_allocate);
void set_alloc_actions(pe_working_set_t * data_set);
void migrate_reload_madness(pe_working_set_t * data_set);
resource_alloc_functions_t resource_class_alloc_functions[] = {
{
native_merge_weights,
native_color,
native_create_actions,
native_create_probe,
native_internal_constraints,
native_rsc_colocation_lh,
native_rsc_colocation_rh,
native_rsc_location,
native_action_flags,
native_update_actions,
native_expand,
native_append_meta,
},
{
group_merge_weights,
group_color,
group_create_actions,
native_create_probe,
group_internal_constraints,
group_rsc_colocation_lh,
group_rsc_colocation_rh,
group_rsc_location,
group_action_flags,
group_update_actions,
group_expand,
group_append_meta,
},
{
- native_merge_weights,
+ clone_merge_weights,
clone_color,
clone_create_actions,
clone_create_probe,
clone_internal_constraints,
clone_rsc_colocation_lh,
clone_rsc_colocation_rh,
clone_rsc_location,
clone_action_flags,
clone_update_actions,
clone_expand,
clone_append_meta,
},
{
- native_merge_weights,
+ master_merge_weights,
master_color,
master_create_actions,
clone_create_probe,
master_internal_constraints,
clone_rsc_colocation_lh,
master_rsc_colocation_rh,
clone_rsc_location,
clone_action_flags,
clone_update_actions,
clone_expand,
master_append_meta,
}
};
static gboolean
check_rsc_parameters(resource_t * rsc, node_t * node, xmlNode * 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 (value == old_value /* ie. NULL */
|| crm_str_eq(value, old_value, TRUE)) {
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);
set_bit(rsc->flags, pe_rsc_start_pending);
delete_resource = TRUE;
}
return delete_resource;
}
static void
CancelXmlOp(resource_t * rsc, xmlNode * xml_op, node_t * active_node,
const char *reason, pe_working_set_t * data_set)
{
int interval = 0;
action_t *cancel = NULL;
char *key = NULL;
const char *task = NULL;
const char *call_id = NULL;
const char *interval_s = NULL;
CRM_CHECK(xml_op != NULL, return);
CRM_CHECK(active_node != NULL, return);
task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
interval = crm_parse_int(interval_s, "0");
/* we need to reconstruct the key because of the way we used to construct resource IDs */
key = generate_op_key(rsc->id, task, interval);
crm_info("Action %s on %s will be stopped: %s",
key, active_node->details->uname, reason ? reason : "unknown");
cancel = custom_action(rsc, strdup(key), RSC_CANCEL, active_node, FALSE, TRUE, data_set);
free(cancel->task);
cancel->task = strdup(RSC_CANCEL);
add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task);
add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID, call_id);
add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s);
custom_action_order(rsc, stop_key(rsc), NULL, rsc, NULL, cancel, pe_order_optional, data_set);
free(key);
key = NULL;
}
static gboolean
check_action_definition(resource_t * rsc, node_t * active_node, xmlNode * xml_op,
pe_working_set_t * data_set)
{
char *key = NULL;
int interval = 0;
const char *interval_s = NULL;
gboolean did_change = FALSE;
xmlNode *params_all = NULL;
xmlNode *params_restart = NULL;
GHashTable *local_rsc_params = NULL;
char *digest_all_calc = NULL;
const char *digest_all = NULL;
const char *restart_list = NULL;
const char *digest_restart = NULL;
char *digest_restart_calc = NULL;
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);
if (safe_str_eq(task, RSC_STOP)) {
return FALSE;
}
interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
interval = crm_parse_int(interval_s, "0");
/* we need to reconstruct the key because of the way we used to construct resource IDs */
key = generate_op_key(rsc->id, task, interval);
if (interval > 0) {
xmlNode *op_match = NULL;
crm_trace("Checking parameters for %s", key);
op_match = find_rsc_op_entry(rsc, key);
if (op_match == NULL && is_set(data_set->flags, pe_flag_stop_action_orphans)) {
CancelXmlOp(rsc, xml_op, active_node, "orphan", data_set);
free(key);
return TRUE;
} else if (op_match == NULL) {
crm_debug("Orphan action detected: %s on %s", key, active_node->details->uname);
free(key);
return TRUE;
}
}
action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set);
/* key is free'd by custom_action() */
local_rsc_params = g_hash_table_new_full(crm_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
get_rsc_attributes(local_rsc_params, rsc, active_node, data_set);
params_all = create_xml_node(NULL, XML_TAG_PARAMS);
g_hash_table_foreach(local_rsc_params, hash2field, params_all);
g_hash_table_foreach(action->extra, hash2field, params_all);
g_hash_table_foreach(rsc->parameters, hash2field, params_all);
g_hash_table_foreach(action->meta, hash2metafield, params_all);
filter_action_parameters(params_all, op_version);
digest_all_calc = calculate_operation_digest(params_all, op_version);
digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
if (interval == 0 && safe_str_eq(task, RSC_STATUS)) {
/* Reload based on the start action not a probe */
task = RSC_START;
} else if (interval == 0 && safe_str_eq(task, RSC_MIGRATED)) {
/* Reload based on the start action not a migrate */
task = RSC_START;
}
if (digest_restart) {
/* Changes that force a restart */
params_restart = copy_xml(params_all);
if (restart_list) {
filter_reload_parameters(params_restart, restart_list);
}
digest_restart_calc = calculate_operation_digest(params_restart, op_version);
if (safe_str_neq(digest_restart_calc, digest_restart)) {
did_change = TRUE;
key = generate_op_key(rsc->id, task, interval);
crm_log_xml_info(params_restart, "params:restart");
crm_info("Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
key, active_node->details->uname,
crm_str(digest_restart), digest_restart_calc,
op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
goto cleanup;
}
}
if (safe_str_neq(digest_all_calc, digest_all)) {
/* Changes that can potentially be handled by a reload */
did_change = TRUE;
crm_log_xml_info(params_all, "params:reload");
key = generate_op_key(rsc->id, task, interval);
crm_info("Parameters to %s on %s changed: was %s vs. now %s (reload:%s) %s",
key, active_node->details->uname,
crm_str(digest_all), digest_all_calc, op_version,
crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
if (interval > 0) {
action_t *op = NULL;
#if 0
/* Always reload/restart the entire resource */
op = custom_action(rsc, start_key(rsc), RSC_START, NULL, FALSE, TRUE, data_set);
update_action_flags(op, pe_action_allow_reload_conversion);
#else
/* Re-sending the recurring op is sufficient - the old one will be cancelled automatically */
op = custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
custom_action_order(rsc, start_key(rsc), NULL,
NULL, NULL, op, pe_order_runnable_left, data_set);
#endif
} else if (digest_restart) {
crm_trace("Reloading '%s' action for resource %s", task, rsc->id);
/* Allow this resource to reload - unless something else causes a full restart */
set_bit(rsc->flags, pe_rsc_try_reload);
/* Create these for now, it keeps the action IDs the same in the regression outputs */
custom_action(rsc, key, task, NULL, TRUE, TRUE, data_set);
} else {
crm_trace("Resource %s doesn't know how to reload", rsc->id);
/* Re-send the start/demote/promote op
* Recurring ops will be detected independantly
*/
custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
}
}
cleanup:
free_xml(params_all);
free_xml(params_restart);
free(digest_all_calc);
free(digest_restart_calc);
g_hash_table_destroy(local_rsc_params);
pe_free_action(action);
return did_change;
}
extern gboolean DeleteRsc(resource_t * rsc, node_t * node, gboolean optional,
pe_working_set_t * data_set);
static void
check_actions_for(xmlNode * rsc_entry, resource_t * rsc, node_t * node, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
int offset = -1;
int interval = 0;
int stop_index = 0;
int start_index = 0;
const char *task = NULL;
const char *interval_s = NULL;
xmlNode *rsc_op = NULL;
GListPtr op_list = NULL;
GListPtr sorted_op_list = NULL;
gboolean is_probe = FALSE;
gboolean did_change = FALSE;
CRM_CHECK(node != NULL, return);
if (is_set(rsc->flags, pe_rsc_orphan)) {
crm_trace("Skipping param check for %s: orphan", rsc->id);
return;
} else if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
crm_trace("Skipping param check for %s: no longer active on %s",
rsc->id, node->details->uname);
return;
}
crm_trace("Processing %s on %s", rsc->id, node->details->uname);
if (check_rsc_parameters(rsc, node, rsc_entry, data_set)) {
DeleteRsc(rsc, node, FALSE, data_set);
}
for (rsc_op = __xml_first_child(rsc_entry); rsc_op != NULL; rsc_op = __xml_next(rsc_op)) {
if (crm_str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
op_list = g_list_prepend(op_list, rsc_op);
}
}
sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
calculate_active_ops(sorted_op_list, &start_index, &stop_index);
for (gIter = sorted_op_list; gIter != NULL; gIter = gIter->next) {
xmlNode *rsc_op = (xmlNode *) gIter->data;
offset++;
if (start_index < stop_index) {
/* stopped */
continue;
} else if (offset < start_index) {
/* action occurred prior to a start */
continue;
}
is_probe = FALSE;
did_change = FALSE;
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
interval_s = crm_element_value(rsc_op, XML_LRM_ATTR_INTERVAL);
interval = crm_parse_int(interval_s, "0");
if (interval == 0 && safe_str_eq(task, RSC_STATUS)) {
is_probe = TRUE;
}
if (interval > 0 && is_set(data_set->flags, pe_flag_maintenance_mode)) {
CancelXmlOp(rsc, rsc_op, node, "maintenance mode", data_set);
} else if (is_probe || safe_str_eq(task, RSC_START) || interval > 0 || safe_str_eq(task, RSC_MIGRATED)) {
did_change = check_action_definition(rsc, node, rsc_op, data_set);
}
if (did_change && get_failcount(node, rsc, NULL, data_set)) {
char *key = NULL;
action_t *action_clear = NULL;
key = generate_op_key(rsc->id, CRM_OP_CLEAR_FAILCOUNT, 0);
action_clear = custom_action(rsc, key, CRM_OP_CLEAR_FAILCOUNT, node, FALSE, TRUE, data_set);
set_bit(action_clear->flags, pe_action_runnable);
}
}
g_list_free(sorted_op_list);
}
static GListPtr
find_rsc_list(GListPtr result, resource_t * rsc, const char *id, gboolean renamed_clones,
gboolean partial, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
gboolean match = FALSE;
if (id == NULL) {
return NULL;
} else if (rsc == NULL && data_set) {
for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
result = find_rsc_list(result, child, id, renamed_clones, partial, NULL);
}
return result;
} else if (rsc == NULL) {
return NULL;
}
if (partial) {
if (strstr(rsc->id, id)) {
match = TRUE;
} else if (renamed_clones && rsc->clone_name && strstr(rsc->clone_name, id)) {
match = TRUE;
}
} else {
if (strcmp(rsc->id, id) == 0) {
match = TRUE;
} else if (renamed_clones && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
match = TRUE;
}
}
if (match) {
result = g_list_prepend(result, rsc);
}
if (rsc->children) {
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
result = find_rsc_list(result, child, id, renamed_clones, partial, NULL);
}
}
return result;
}
static void
check_actions(pe_working_set_t * data_set)
{
const char *id = NULL;
node_t *node = NULL;
xmlNode *lrm_rscs = NULL;
xmlNode *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
xmlNode *node_state = NULL;
for (node_state = __xml_first_child(status); node_state != NULL;
node_state = __xml_next(node_state)) {
if (crm_str_eq((const char *)node_state->name, XML_CIB_TAG_STATE, TRUE)) {
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;
} else if (can_run_resources(node) == FALSE) {
crm_trace("Skipping param check for %s: cant run resources",
node->details->uname);
continue;
}
crm_trace("Processing node %s", node->details->uname);
if (node->details->online || is_set(data_set->flags, pe_flag_stonith_enabled)) {
xmlNode *rsc_entry = NULL;
for (rsc_entry = __xml_first_child(lrm_rscs); rsc_entry != NULL;
rsc_entry = __xml_next(rsc_entry)) {
if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) {
if (xml_has_children(rsc_entry)) {
GListPtr gIter = NULL;
GListPtr result = NULL;
const char *rsc_id = ID(rsc_entry);
CRM_CHECK(rsc_id != NULL, return);
result = find_rsc_list(NULL, NULL, rsc_id, TRUE, FALSE, data_set);
for (gIter = result; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
check_actions_for(rsc_entry, rsc, node, data_set);
}
g_list_free(result);
}
}
}
}
}
}
}
static gboolean
apply_placement_constraints(pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
crm_trace("Applying constraints...");
for (gIter = data_set->placement_constraints; gIter != NULL; gIter = gIter->next) {
rsc_to_node_t *cons = (rsc_to_node_t *) gIter->data;
cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons);
}
return TRUE;
}
static void
common_apply_stickiness(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
{
int fail_count = 0;
resource_t *failed = rsc;
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
common_apply_stickiness(child_rsc, node, data_set);
}
return;
}
if (is_set(rsc->flags, pe_rsc_managed)
&& rsc->stickiness != 0 && g_list_length(rsc->running_on) == 1) {
node_t *current = pe_find_node_id(rsc->running_on, node->details->id);
node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
if (current == NULL) {
} else if (match != NULL || is_set(data_set->flags, pe_flag_symmetric_cluster)) {
resource_t *sticky_rsc = rsc;
resource_location(sticky_rsc, node, rsc->stickiness, "stickiness", data_set);
crm_debug("Resource %s: preferring current location"
" (node=%s, weight=%d)", sticky_rsc->id,
node->details->uname, rsc->stickiness);
} else {
GHashTableIter iter;
node_t *nIter = NULL;
crm_debug("Ignoring stickiness for %s: the cluster is asymmetric"
" and node %s is not explicitly allowed", rsc->id, node->details->uname);
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&nIter)) {
crm_err("%s[%s] = %d", rsc->id, nIter->details->uname, nIter->weight);
}
}
}
if (is_not_set(rsc->flags, pe_rsc_unique)) {
failed = uber_parent(rsc);
}
fail_count = get_failcount(node, rsc, NULL, data_set);
if (fail_count > 0 && rsc->migration_threshold != 0) {
if (rsc->migration_threshold <= fail_count) {
resource_location(failed, node, -INFINITY, "__fail_limit__", data_set);
crm_warn("Forcing %s away from %s after %d failures (max=%d)",
failed->id, node->details->uname, fail_count, rsc->migration_threshold);
} else {
crm_notice("%s can fail %d more times on %s before being forced off",
failed->id, rsc->migration_threshold - fail_count, node->details->uname);
}
}
}
static void
complex_set_cmds(resource_t * rsc)
{
GListPtr gIter = rsc->children;
rsc->cmds = &resource_class_alloc_functions[rsc->variant];
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
complex_set_cmds(child_rsc);
}
}
void
set_alloc_actions(pe_working_set_t * data_set)
{
GListPtr gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
complex_set_cmds(rsc);
}
}
static void
calculate_system_health(gpointer gKey, gpointer gValue, gpointer user_data)
{
const char *key = (const char *)gKey;
const char *value = (const char *)gValue;
int *system_health = (int *)user_data;
if (!gKey || !gValue || !user_data) {
return;
}
/* Does it start with #health? */
if (0 == strncmp(key, "#health", 7)) {
int score;
/* Convert the value into an integer */
score = char2score(value);
/* Add it to the running total */
*system_health = merge_weights(score, *system_health);
}
}
static gboolean
apply_system_health(pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
const char *health_strategy = pe_pref(data_set->config_hash, "node-health-strategy");
if (health_strategy == NULL || safe_str_eq(health_strategy, "none")) {
/* Prevent any accidental health -> score translation */
node_score_red = 0;
node_score_yellow = 0;
node_score_green = 0;
return TRUE;
} else if (safe_str_eq(health_strategy, "migrate-on-red")) {
/* Resources on nodes which have health values of red are
* weighted away from that node.
*/
node_score_red = -INFINITY;
node_score_yellow = 0;
node_score_green = 0;
} else if (safe_str_eq(health_strategy, "only-green")) {
/* Resources on nodes which have health values of red or yellow
* are forced away from that node.
*/
node_score_red = -INFINITY;
node_score_yellow = -INFINITY;
node_score_green = 0;
} else if (safe_str_eq(health_strategy, "progressive")) {
/* Same as the above, but use the r/y/g scores provided by the user
* Defaults are provided by the pe_prefs table
*/
} else if (safe_str_eq(health_strategy, "custom")) {
/* Requires the admin to configure the rsc_location constaints for
* processing the stored health scores
*/
/* TODO: Check for the existance of appropriate node health constraints */
return TRUE;
} else {
crm_err("Unknown node health strategy: %s", health_strategy);
return FALSE;
}
crm_info("Applying automated node health strategy: %s", health_strategy);
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
int system_health = 0;
node_t *node = (node_t *) gIter->data;
/* Search through the node hash table for system health entries. */
g_hash_table_foreach(node->details->attrs, calculate_system_health, &system_health);
crm_info(" Node %s has an combined system health of %d",
node->details->uname, system_health);
/* If the health is non-zero, then create a new rsc2node so that the
* weight will be added later on.
*/
if (system_health != 0) {
GListPtr gIter2 = data_set->resources;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
resource_t *rsc = (resource_t *) gIter2->data;
rsc2node_new(health_strategy, rsc, system_health, node, data_set);
}
}
}
return TRUE;
}
gboolean
stage0(pe_working_set_t * data_set)
{
xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
if (data_set->input == NULL) {
return FALSE;
}
if (is_set(data_set->flags, pe_flag_have_status) == FALSE) {
crm_trace("Calculating status");
cluster_status(data_set);
}
set_alloc_actions(data_set);
apply_system_health(data_set);
unpack_constraints(cib_constraints, data_set);
return TRUE;
}
static void
wait_for_probe(resource_t * rsc, const char *action, action_t * probe_complete,
pe_working_set_t * data_set)
{
if (probe_complete == NULL) {
return;
}
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
wait_for_probe(child, action, probe_complete, data_set);
}
} else {
char *key = generate_op_key(rsc->id, action, 0);
custom_action_order(NULL, NULL, probe_complete, rsc, key, NULL,
pe_order_optional, data_set);
}
}
/*
* Check nodes for resources started outside of the LRM
*/
gboolean
probe_resources(pe_working_set_t * data_set)
{
action_t *probe_complete = NULL;
action_t *probe_node_complete = NULL;
GListPtr gIter = NULL;
GListPtr gIter2 = NULL;
gIter = data_set->nodes;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
const char *probed = g_hash_table_lookup(node->details->attrs, CRM_OP_PROBED);
if (node->details->online == FALSE) {
continue;
} else if (node->details->unclean) {
continue;
} else if (probe_complete == NULL) {
probe_complete = get_pseudo_op(CRM_OP_PROBED, data_set);
}
if (probed != NULL && crm_is_true(probed) == FALSE) {
action_t *probe_op = custom_action(NULL, strdup(CRM_OP_REPROBE),
CRM_OP_REPROBE, node, FALSE, TRUE, data_set);
add_hash_param(probe_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
continue;
}
probe_node_complete = custom_action(NULL, strdup(CRM_OP_PROBED),
CRM_OP_PROBED, node, FALSE, TRUE, data_set);
if (crm_is_true(probed)) {
crm_trace("unset");
update_action_flags(probe_node_complete, pe_action_optional);
} else {
crm_trace("set");
update_action_flags(probe_node_complete, pe_action_optional | pe_action_clear);
}
crm_trace("%s - %d", node->details->uname, probe_node_complete->flags & pe_action_optional);
probe_node_complete->priority = INFINITY;
add_hash_param(probe_node_complete->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
if (node->details->pending) {
update_action_flags(probe_node_complete, pe_action_runnable | pe_action_clear);
crm_info("Action %s on %s is unrunnable (pending)",
probe_node_complete->uuid, probe_node_complete->node->details->uname);
}
order_actions(probe_node_complete, probe_complete,
pe_order_runnable_left /*|pe_order_implies_then */ );
gIter2 = data_set->resources;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
resource_t *rsc = (resource_t *) gIter2->data;
if (rsc->cmds->create_probe(rsc, node, probe_node_complete, FALSE, data_set)) {
update_action_flags(probe_complete, pe_action_optional | pe_action_clear);
update_action_flags(probe_node_complete, pe_action_optional | pe_action_clear);
wait_for_probe(rsc, RSC_START, probe_complete, data_set);
}
}
}
gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
wait_for_probe(rsc, RSC_STOP, probe_complete, 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)
{
GListPtr gIter = NULL;
crm_trace("Applying placement constraints");
gIter = data_set->nodes;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
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);
gIter = data_set->nodes;
for (; gIter != NULL; gIter = gIter->next) {
GListPtr gIter2 = NULL;
node_t *node = (node_t *) gIter->data;
gIter2 = data_set->resources;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
resource_t *rsc = (resource_t *) gIter2->data;
common_apply_stickiness(rsc, node, data_set);
}
}
return TRUE;
}
/*
* Create internal resource constraints before allocation
*/
gboolean
stage3(pe_working_set_t * data_set)
{
GListPtr gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
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;
}
static gint
sort_rsc_process_order(gconstpointer a, gconstpointer b, gpointer data)
{
int rc = 0;
int r1_weight = -INFINITY;
int r2_weight = -INFINITY;
const char *reason = "existance";
const GListPtr nodes = (GListPtr) data;
resource_t *resource1 = (resource_t *) convert_const_pointer(a);
resource_t *resource2 = (resource_t *) convert_const_pointer(b);
node_t *node = NULL;
GListPtr gIter = NULL;
GHashTable *r1_nodes = NULL;
GHashTable *r2_nodes = NULL;
if (a == NULL && b == NULL) {
goto done;
}
if (a == NULL) {
return 1;
}
if (b == NULL) {
return -1;
}
reason = "priority";
r1_weight = resource1->priority;
r2_weight = resource2->priority;
if (r1_weight > r2_weight) {
rc = -1;
goto done;
}
if (r1_weight < r2_weight) {
rc = 1;
goto done;
}
reason = "no node list";
if (nodes == NULL) {
goto done;
}
r1_nodes =
rsc_merge_weights(resource1, resource1->id, NULL, NULL, 1,
pe_weights_forward | pe_weights_init);
dump_node_scores(LOG_TRACE, NULL, resource1->id, r1_nodes);
r2_nodes =
rsc_merge_weights(resource2, resource2->id, NULL, NULL, 1,
pe_weights_forward | pe_weights_init);
dump_node_scores(LOG_TRACE, NULL, resource2->id, r2_nodes);
/* Current location score */
reason = "current location";
r1_weight = -INFINITY;
r2_weight = -INFINITY;
if (resource1->running_on) {
node = g_list_nth_data(resource1->running_on, 0);
node = g_hash_table_lookup(r1_nodes, node->details->id);
r1_weight = node->weight;
}
if (resource2->running_on) {
node = g_list_nth_data(resource2->running_on, 0);
node = g_hash_table_lookup(r2_nodes, node->details->id);
r2_weight = node->weight;
}
if (r1_weight > r2_weight) {
rc = -1;
goto done;
}
if (r1_weight < r2_weight) {
rc = 1;
goto done;
}
reason = "score";
for (gIter = nodes; gIter != NULL; gIter = gIter->next) {
node_t *r1_node = NULL;
node_t *r2_node = NULL;
node = (node_t *) gIter->data;
r1_weight = -INFINITY;
if (r1_nodes) {
r1_node = g_hash_table_lookup(r1_nodes, node->details->id);
}
if (r1_node) {
r1_weight = r1_node->weight;
}
r2_weight = -INFINITY;
if (r2_nodes) {
r2_node = g_hash_table_lookup(r2_nodes, node->details->id);
}
if (r2_node) {
r2_weight = r2_node->weight;
}
if (r1_weight > r2_weight) {
rc = -1;
goto done;
}
if (r1_weight < r2_weight) {
rc = 1;
goto done;
}
}
done:
if (r1_nodes) {
g_hash_table_destroy(r1_nodes);
}
if (r2_nodes) {
g_hash_table_destroy(r2_nodes);
}
crm_trace( "%s (%d) %c %s (%d) on %s: %s",
resource1->id, r1_weight, rc < 0 ? '>' : rc > 0 ? '<' : '=',
resource2->id, r2_weight, node ? node->details->id : "n/a", reason);
return rc;
}
gboolean
stage5(pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
if (safe_str_neq(data_set->placement_strategy, "default")) {
GListPtr nodes = g_list_copy(data_set->nodes);
nodes = g_list_sort_with_data(nodes, sort_node_weight, NULL);
data_set->resources =
g_list_sort_with_data(data_set->resources, sort_rsc_process_order, nodes);
g_list_free(nodes);
}
gIter = data_set->nodes;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
dump_node_capacity(show_utilization ? 0 : utilization_log_level, "Original", node);
}
crm_trace("Allocating services");
/* Take (next) highest resource, assign it and create its actions */
gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
crm_trace("Allocating: %s", rsc->id);
rsc->cmds->allocate(rsc, NULL, data_set);
}
gIter = data_set->nodes;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
dump_node_capacity(show_utilization ? 0 : utilization_log_level, "Remaining", node);
}
if (is_set(data_set->flags, pe_flag_startup_probes)) {
crm_trace("Calculating needed probes");
/* This code probably needs optimization
* ptest -x with 100 nodes, 100 clones and clone-max=100:
With probes:
ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status
ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints
ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints
ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:292 Check actions
ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: do_calculations: pengine.c:299 Allocate resources
ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: stage5: allocate.c:881 Allocating services
ptest[14781]: 2010/09/27_17:56:49 notice: TRACE: stage5: allocate.c:894 Calculating needed probes
ptest[14781]: 2010/09/27_17:56:51 notice: TRACE: stage5: allocate.c:899 Creating actions
ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: stage5: allocate.c:905 Creating done
ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases
ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints
36s
ptest[14781]: 2010/09/27_17:57:28 notice: TRACE: do_calculations: pengine.c:320 Create transition graph
Without probes:
ptest[14637]: 2010/09/27_17:56:21 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status
ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints
ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints
ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:292 Check actions
ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: do_calculations: pengine.c:299 Allocate resources
ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: stage5: allocate.c:881 Allocating services
ptest[14637]: 2010/09/27_17:56:24 notice: TRACE: stage5: allocate.c:899 Creating actions
ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: stage5: allocate.c:905 Creating done
ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases
ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints
ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:320 Create transition graph
*/
probe_resources(data_set);
}
crm_trace("Creating actions");
gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
rsc->cmds->create_actions(rsc, data_set);
}
crm_trace("Creating done");
return TRUE;
}
static gboolean
is_managed(const resource_t * rsc)
{
GListPtr gIter = rsc->children;
if (is_set(rsc->flags, pe_rsc_managed)) {
return TRUE;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
if (is_managed(child_rsc)) {
return TRUE;
}
}
return FALSE;
}
static gboolean
any_managed_resouces(pe_working_set_t * data_set)
{
GListPtr gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
if (is_managed(rsc)) {
return TRUE;
}
}
return FALSE;
}
/*
* Create dependancies for stonith and shutdown operations
*/
gboolean
stage6(pe_working_set_t * data_set)
{
action_t *dc_down = NULL;
action_t *dc_fence = NULL;
action_t *stonith_op = NULL;
action_t *last_stonith = NULL;
gboolean integrity_lost = FALSE;
action_t *ready = get_pseudo_op(STONITH_UP, data_set);
action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);
action_t *done = get_pseudo_op(STONITH_DONE, data_set);
gboolean need_stonith = FALSE;
GListPtr gIter = data_set->nodes;
crm_trace("Processing fencing and shutdown cases");
if (is_set(data_set->flags, pe_flag_stonith_enabled)
&& (is_set(data_set->flags, pe_flag_have_quorum)
|| data_set->no_quorum_policy == no_quorum_ignore
|| data_set->no_quorum_policy == no_quorum_suicide)) {
need_stonith = TRUE;
}
if (need_stonith && any_managed_resouces(data_set) == FALSE) {
crm_notice("Delaying fencing operations until there are resources to manage");
need_stonith = FALSE;
}
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
stonith_op = NULL;
if (node->details->unclean && need_stonith) {
pe_warn("Scheduling Node %s for STONITH", node->details->uname);
stonith_op = custom_action(NULL, 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);
order_actions(ready, stonith_op, pe_order_runnable_left);
order_actions(stonith_op, all_stopped, pe_order_implies_then);
clear_bit(ready->flags, pe_action_optional);
if (node->details->is_dc) {
dc_down = stonith_op;
dc_fence = stonith_op;
} else {
if (last_stonith) {
order_actions(last_stonith, stonith_op, pe_order_optional);
}
last_stonith = stonith_op;
}
} else if (node->details->online && node->details->shutdown) {
action_t *down_op = NULL;
crm_notice("Scheduling Node %s for shutdown", node->details->uname);
down_op = custom_action(NULL, strdup(CRM_OP_SHUTDOWN),
CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set);
shutdown_constraints(node, down_op, data_set);
add_hash_param(down_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
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 (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED");
pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE");
} else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE) {
crm_notice("Cannot fence unclean nodes until quorum is"
" attained (or no-quorum-policy is set to ignore)");
}
}
if (dc_down != NULL) {
GListPtr shutdown_matches = find_actions(data_set->actions, CRM_OP_SHUTDOWN, NULL);
crm_trace("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);
gIter = shutdown_matches;
for (; gIter != NULL; gIter = gIter->next) {
action_t *node_stop = (action_t *) gIter->data;
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_order_optional);
}
if (last_stonith && dc_down != last_stonith) {
order_actions(last_stonith, dc_down, pe_order_optional);
}
g_list_free(shutdown_matches);
}
if (last_stonith) {
order_actions(last_stonith, done, pe_order_implies_then);
} else if (dc_fence) {
order_actions(dc_down, done, pe_order_implies_then);
}
order_actions(ready, done, pe_order_optional);
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
*
*/
static GListPtr
find_actions_by_task(GListPtr actions, resource_t * rsc, const char *original_key)
{
GListPtr list = NULL;
list = find_actions(actions, original_key, NULL);
if (list == NULL) {
/* we're potentially searching a child of the original resource */
char *key = NULL;
char *tmp = NULL;
char *task = NULL;
int interval = 0;
if (parse_op_key(original_key, &tmp, &task, &interval)) {
key = generate_op_key(rsc->id, task, interval);
/* crm_err("looking up %s instead of %s", key, original_key); */
/* slist_iter(action, action_t, actions, lpc, */
/* crm_err(" - %s", action->uuid)); */
list = find_actions(actions, key, NULL);
} else {
crm_err("search key: %s", original_key);
}
free(key);
free(tmp);
free(task);
}
return list;
}
static void
rsc_order_then(action_t * lh_action, resource_t * rsc, order_constraint_t * order)
{
GListPtr gIter = NULL;
GListPtr rh_actions = NULL;
action_t *rh_action = NULL;
enum pe_ordering type = order->type;
CRM_CHECK(rsc != NULL, return);
CRM_CHECK(order != NULL, return);
rh_action = order->rh_action;
crm_trace("Processing RH of ordering constraint %d", order->id);
if (rh_action != NULL) {
rh_actions = g_list_prepend(NULL, rh_action);
} else if (rsc != NULL) {
rh_actions = find_actions_by_task(rsc->actions, rsc, order->rh_action_task);
}
if (rh_actions == NULL) {
crm_trace("No RH-Side (%s/%s) found for constraint..."
" ignoring", rsc->id, order->rh_action_task);
if (lh_action) {
crm_trace("LH-Side was: %s", lh_action->uuid);
}
return;
}
if (lh_action && lh_action->rsc == rsc && is_set(lh_action->flags, pe_action_dangle)) {
crm_trace("Detected dangling operation %s -> %s", lh_action->uuid, order->rh_action_task);
clear_bit(type, pe_order_implies_then);
}
gIter = rh_actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *rh_action_iter = (action_t *) gIter->data;
if (lh_action) {
order_actions(lh_action, rh_action_iter, type);
} else if (type & pe_order_implies_then) {
update_action_flags(rh_action_iter, pe_action_runnable | pe_action_clear);
crm_warn("Unrunnable %s 0x%.6x", rh_action_iter->uuid, type);
} else {
crm_warn("neither %s 0x%.6x", rh_action_iter->uuid, type);
}
}
g_list_free(rh_actions);
}
static void
rsc_order_first(resource_t * lh_rsc, order_constraint_t * order, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
GListPtr lh_actions = NULL;
action_t *lh_action = order->lh_action;
resource_t *rh_rsc = order->rh_rsc;
crm_trace("Processing LH of ordering constraint %d", order->id);
CRM_ASSERT(lh_rsc != NULL);
if (lh_action != NULL) {
lh_actions = g_list_prepend(NULL, lh_action);
} else if (lh_action == NULL) {
lh_actions = find_actions_by_task(lh_rsc->actions, lh_rsc, order->lh_action_task);
}
if (lh_actions == NULL && lh_rsc != rh_rsc) {
char *key = NULL;
char *rsc_id = NULL;
char *op_type = NULL;
int interval = 0;
parse_op_key(order->lh_action_task, &rsc_id, &op_type, &interval);
key = generate_op_key(lh_rsc->id, op_type, interval);
if (lh_rsc->fns->state(lh_rsc, TRUE) != RSC_ROLE_STOPPED || safe_str_neq(op_type, RSC_STOP)) {
crm_trace("No LH-Side (%s/%s) found for constraint %d with %s - creating",
lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task);
lh_action = custom_action(lh_rsc, key, op_type, NULL, TRUE, TRUE, data_set);
lh_actions = g_list_prepend(NULL, lh_action);
} else {
free(key);
crm_trace("No LH-Side (%s/%s) found for constraint %d with %s - ignoring",
lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task);
}
free(op_type);
free(rsc_id);
}
gIter = lh_actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *lh_action_iter = (action_t *) gIter->data;
if (rh_rsc == NULL && order->rh_action) {
rh_rsc = order->rh_action->rsc;
}
if (rh_rsc) {
rsc_order_then(lh_action_iter, rh_rsc, order);
} else if (order->rh_action) {
order_actions(lh_action_iter, order->rh_action, order->type);
}
}
g_list_free(lh_actions);
}
extern gboolean update_action(action_t * action);
gboolean
stage7(pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
crm_trace("Applying ordering constraints");
/* Don't ask me why, but apparently they need to be processed in
* the order they were created in... go figure
*
* Also g_list_prepend() has horrendous performance characteristics
* So we need to use g_list_prepend() and then reverse the list here
*/
data_set->ordering_constraints = g_list_reverse(data_set->ordering_constraints);
gIter = data_set->ordering_constraints;
for (; gIter != NULL; gIter = gIter->next) {
order_constraint_t *order = (order_constraint_t *) gIter->data;
resource_t *rsc = order->lh_rsc;
crm_trace("Applying ordering constraint: %d", order->id);
if (rsc != NULL) {
crm_trace("rsc_action-to-*");
rsc_order_first(rsc, order, data_set);
continue;
}
rsc = order->rh_rsc;
if (rsc != NULL) {
crm_trace("action-to-rsc_action");
rsc_order_then(order->lh_action, rsc, order);
} else {
crm_trace("action-to-action");
order_actions(order->lh_action, order->rh_action, order->type);
}
}
crm_trace("Updating %d actions", g_list_length(data_set->actions));
gIter = data_set->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
update_action(action);
}
crm_trace("Processing migrations");
gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
rsc_migrate_reload(rsc, data_set);
LogActions(rsc, data_set, FALSE);
}
return TRUE;
}
static gint
sort_notify_entries(gconstpointer a, gconstpointer b)
{
int tmp;
const notify_entry_t *entry_a = a;
const notify_entry_t *entry_b = b;
if (entry_a == NULL && entry_b == NULL) {
return 0;
}
if (entry_a == NULL) {
return 1;
}
if (entry_b == NULL) {
return -1;
}
if (entry_a->rsc == NULL && entry_b->rsc == NULL) {
return 0;
}
if (entry_a->rsc == NULL) {
return 1;
}
if (entry_b->rsc == NULL) {
return -1;
}
tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
if (tmp != 0) {
return tmp;
}
if (entry_a->node == NULL && entry_b->node == NULL) {
return 0;
}
if (entry_a->node == NULL) {
return 1;
}
if (entry_b->node == NULL) {
return -1;
}
return strcmp(entry_a->node->details->id, entry_b->node->details->id);
}
static void
expand_list(GListPtr list, char **rsc_list, char **node_list)
{
GListPtr gIter = list;
const char *uname = NULL;
const char *rsc_id = NULL;
const char *last_rsc_id = NULL;
if (rsc_list) {
*rsc_list = NULL;
}
if (list == NULL) {
if (rsc_list) {
*rsc_list = strdup(" ");
}
if (node_list) {
*node_list = strdup(" ");
}
return;
}
if (node_list) {
*node_list = NULL;
}
for (; gIter != NULL; gIter = gIter->next) {
notify_entry_t *entry = (notify_entry_t *) gIter->data;
CRM_CHECK(entry != NULL, continue);
CRM_CHECK(entry->rsc != NULL, continue);
CRM_CHECK(node_list == NULL || entry->node != NULL, continue);
uname = NULL;
rsc_id = entry->rsc->id;
CRM_ASSERT(rsc_id != NULL);
/* filter dups */
if (safe_str_eq(rsc_id, last_rsc_id)) {
continue;
}
last_rsc_id = rsc_id;
if (rsc_list != NULL) {
int existing_len = 0;
int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */
if (rsc_list && *rsc_list) {
existing_len = strlen(*rsc_list);
}
crm_trace("Adding %s (%dc) at offset %d", rsc_id, len - 2, existing_len);
*rsc_list = realloc(*rsc_list, len + existing_len);
sprintf(*rsc_list + existing_len, "%s ", rsc_id);
}
if (entry->node != NULL) {
uname = entry->node->details->uname;
}
if (node_list != NULL && uname) {
int existing_len = 0;
int len = 2 + strlen(uname);
if (node_list && *node_list) {
existing_len = strlen(*node_list);
}
crm_trace("Adding %s (%dc) at offset %d", uname, len - 2, existing_len);
*node_list = realloc(*node_list, len + existing_len);
sprintf(*node_list + existing_len, "%s ", uname);
}
}
}
static void
dup_attr(gpointer key, gpointer value, gpointer user_data)
{
add_hash_param(user_data, key, value);
}
static action_t *
pe_notify(resource_t * rsc, node_t * node, action_t * op, action_t * confirm,
notify_data_t * n_data, pe_working_set_t * data_set)
{
char *key = NULL;
action_t *trigger = NULL;
const char *value = NULL;
const char *task = NULL;
if (op == NULL || confirm == NULL) {
crm_trace("Op=%p confirm=%p", op, confirm);
return NULL;
}
CRM_CHECK(node != NULL, return NULL);
if (node->details->online == FALSE) {
crm_trace("Skipping notification for %s: node offline", rsc->id);
return NULL;
} else if (is_set(op->flags, pe_action_runnable) == FALSE) {
crm_trace("Skipping notification for %s: not runnable", op->uuid);
return NULL;
}
value = g_hash_table_lookup(op->meta, "notify_type");
task = g_hash_table_lookup(op->meta, "notify_operation");
crm_trace("Creating notify actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task);
key = generate_notify_key(rsc->id, value, task);
trigger = custom_action(rsc, key, op->task, node,
is_set(op->flags, pe_action_optional), TRUE, data_set);
g_hash_table_foreach(op->meta, dup_attr, trigger->meta);
g_hash_table_foreach(n_data->keys, dup_attr, trigger->meta);
/* pseudo_notify before notify */
crm_trace("Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id, op->id);
order_actions(op, trigger, pe_order_optional);
order_actions(trigger, confirm, pe_order_optional);
return trigger;
}
static void
pe_post_notify(resource_t * rsc, node_t * node, notify_data_t * n_data, pe_working_set_t * data_set)
{
action_t *notify = NULL;
CRM_CHECK(rsc != NULL, return);
if (n_data->post == NULL) {
return; /* Nothing to do */
}
notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set);
if (notify != NULL) {
notify->priority = INFINITY;
}
if (n_data->post_done) {
GListPtr gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *mon = (action_t *) gIter->data;
const char *interval = g_hash_table_lookup(mon->meta, "interval");
if (interval == NULL || safe_str_eq(interval, "0")) {
crm_trace("Skipping %s: interval", mon->uuid);
continue;
} else if (safe_str_eq(mon->task, "cancel")) {
crm_trace("Skipping %s: cancel", mon->uuid);
continue;
}
order_actions(n_data->post_done, mon, pe_order_optional);
}
}
}
notify_data_t *
create_notification_boundaries(resource_t * rsc, const char *action, action_t * start,
action_t * end, pe_working_set_t * data_set)
{
/* Create the pseudo ops that preceed and follow the actual notifications */
/*
* Creates two sequences (conditional on start and end being supplied):
* pre_notify -> pre_notify_complete -> start, and
* end -> post_notify -> post_notify_complete
*
* 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones
*/
char *key = NULL;
notify_data_t *n_data = NULL;
if (is_not_set(rsc->flags, pe_rsc_notify)) {
return NULL;
}
n_data = calloc(1, sizeof(notify_data_t));
n_data->action = action;
n_data->keys =
g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
if (start) {
/* create pre-event notification wrappers */
key = generate_notify_key(rsc->id, "pre", start->task);
n_data->pre =
custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(start->flags, pe_action_optional),
TRUE, data_set);
update_action_flags(n_data->pre, pe_action_pseudo);
update_action_flags(n_data->pre, pe_action_runnable);
add_hash_param(n_data->pre->meta, "notify_type", "pre");
add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);
/* create pre_notify_complete */
key = generate_notify_key(rsc->id, "confirmed-pre", start->task);
n_data->pre_done =
custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(start->flags, pe_action_optional),
TRUE, data_set);
update_action_flags(n_data->pre_done, pe_action_pseudo);
update_action_flags(n_data->pre_done, pe_action_runnable);
add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);
add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);
order_actions(n_data->pre_done, start, pe_order_optional);
order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
}
if (end) {
/* create post-event notification wrappers */
key = generate_notify_key(rsc->id, "post", end->task);
n_data->post =
custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(end->flags, pe_action_optional), TRUE,
data_set);
n_data->post->priority = INFINITY;
update_action_flags(n_data->post, pe_action_pseudo);
if (is_set(end->flags, pe_action_runnable)) {
update_action_flags(n_data->post, pe_action_runnable);
} else {
update_action_flags(n_data->post, pe_action_runnable | pe_action_clear);
}
add_hash_param(n_data->post->meta, "notify_type", "post");
add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
add_hash_param(n_data->post->meta, "notify_key_type", "post");
add_hash_param(n_data->post->meta, "notify_key_operation", end->task);
/* create post_notify_complete */
key = generate_notify_key(rsc->id, "confirmed-post", end->task);
n_data->post_done =
custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(end->flags, pe_action_optional),
TRUE, data_set);
n_data->post_done->priority = INFINITY;
update_action_flags(n_data->post_done, pe_action_pseudo);
if (is_set(end->flags, pe_action_runnable)) {
update_action_flags(n_data->post_done, pe_action_runnable);
} else {
update_action_flags(n_data->post_done, pe_action_runnable | pe_action_clear);
}
add_hash_param(n_data->post_done->meta, "notify_type", "post");
add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);
add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);
order_actions(end, n_data->post, pe_order_implies_then);
order_actions(n_data->post, n_data->post_done, pe_order_implies_then);
}
if (start && end) {
order_actions(n_data->pre_done, n_data->post, pe_order_optional);
}
if (safe_str_eq(action, RSC_STOP)) {
action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);
order_actions(n_data->post_done, all_stopped, pe_order_optional);
}
return n_data;
}
void
collect_notification_data(resource_t * rsc, gboolean state, gboolean activity,
notify_data_t * n_data)
{
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
collect_notification_data(child, state, activity, n_data);
}
return;
}
if (state) {
notify_entry_t *entry = NULL;
entry = calloc(1, sizeof(notify_entry_t));
entry->rsc = rsc;
if (rsc->running_on) {
/* we only take the first one */
entry->node = rsc->running_on->data;
}
crm_trace("%s state: %s", rsc->id, role2text(rsc->role));
switch (rsc->role) {
case RSC_ROLE_STOPPED:
n_data->inactive = g_list_prepend(n_data->inactive, entry);
break;
case RSC_ROLE_STARTED:
n_data->active = g_list_prepend(n_data->active, entry);
break;
case RSC_ROLE_SLAVE:
n_data->slave = g_list_prepend(n_data->slave, entry);
break;
case RSC_ROLE_MASTER:
n_data->master = g_list_prepend(n_data->master, entry);
break;
default:
crm_err("Unsupported notify role");
free(entry);
break;
}
}
if (activity) {
notify_entry_t *entry = NULL;
enum action_tasks task;
GListPtr gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *op = (action_t *) gIter->data;
if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
entry = calloc(1, sizeof(notify_entry_t));
entry->node = op->node;
entry->rsc = rsc;
task = text2task(op->task);
switch (task) {
case start_rsc:
n_data->start = g_list_prepend(n_data->start, entry);
break;
case stop_rsc:
n_data->stop = g_list_prepend(n_data->stop, entry);
break;
case action_promote:
n_data->promote = g_list_prepend(n_data->promote, entry);
break;
case action_demote:
n_data->demote = g_list_prepend(n_data->demote, entry);
break;
default:
free(entry);
break;
}
}
}
}
}
gboolean
expand_notification_data(notify_data_t * n_data)
{
/* Expand the notification entries into a key=value hashtable
* This hashtable is later used in action2xml()
*/
gboolean required = FALSE;
char *rsc_list = NULL;
char *node_list = NULL;
if (n_data->stop) {
n_data->stop = g_list_sort(n_data->stop, sort_notify_entries);
}
expand_list(n_data->stop, &rsc_list, &node_list);
if (rsc_list != NULL && safe_str_neq(" ", rsc_list)) {
if (safe_str_eq(n_data->action, RSC_STOP)) {
required = TRUE;
}
}
g_hash_table_insert(n_data->keys, strdup("notify_stop_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_stop_uname"), node_list);
if (n_data->start) {
n_data->start = g_list_sort(n_data->start, sort_notify_entries);
if (rsc_list && safe_str_eq(n_data->action, RSC_START)) {
required = TRUE;
}
}
expand_list(n_data->start, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_start_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_start_uname"), node_list);
if (n_data->demote) {
n_data->demote = g_list_sort(n_data->demote, sort_notify_entries);
if (safe_str_eq(n_data->action, RSC_DEMOTE)) {
required = TRUE;
}
}
expand_list(n_data->demote, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_demote_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_demote_uname"), node_list);
if (n_data->promote) {
n_data->promote = g_list_sort(n_data->promote, sort_notify_entries);
if (safe_str_eq(n_data->action, RSC_PROMOTE)) {
required = TRUE;
}
}
expand_list(n_data->promote, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_promote_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_promote_uname"), node_list);
if (n_data->active) {
n_data->active = g_list_sort(n_data->active, sort_notify_entries);
}
expand_list(n_data->active, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_active_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_active_uname"), node_list);
if (n_data->slave) {
n_data->slave = g_list_sort(n_data->slave, sort_notify_entries);
}
expand_list(n_data->slave, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_slave_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_slave_uname"), node_list);
if (n_data->master) {
n_data->master = g_list_sort(n_data->master, sort_notify_entries);
}
expand_list(n_data->master, &rsc_list, &node_list);
g_hash_table_insert(n_data->keys, strdup("notify_master_resource"), rsc_list);
g_hash_table_insert(n_data->keys, strdup("notify_master_uname"), node_list);
if (n_data->inactive) {
n_data->inactive = g_list_sort(n_data->inactive, sort_notify_entries);
}
expand_list(n_data->inactive, &rsc_list, NULL);
g_hash_table_insert(n_data->keys, strdup("notify_inactive_resource"), rsc_list);
if (required && n_data->pre) {
update_action_flags(n_data->pre, pe_action_optional | pe_action_clear);
update_action_flags(n_data->pre_done, pe_action_optional | pe_action_clear);
}
if (required && n_data->post) {
update_action_flags(n_data->post, pe_action_optional | pe_action_clear);
update_action_flags(n_data->post_done, pe_action_optional | pe_action_clear);
}
return required;
}
void
create_notifications(resource_t * rsc, notify_data_t * n_data, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
action_t *stop = NULL;
action_t *start = NULL;
enum action_tasks task = text2task(n_data->action);
if (rsc->children) {
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
create_notifications(child, n_data, data_set);
}
return;
}
/* Copy notification details into standard ops */
gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *op = (action_t *) gIter->data;
if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
enum action_tasks t = text2task(op->task);
switch (t) {
case start_rsc:
case stop_rsc:
case action_promote:
case action_demote:
g_hash_table_foreach(n_data->keys, dup_attr, op->meta);
break;
default:
break;
}
}
}
crm_trace("Creating notificaitons for: %s.%s (%s->%s)",
n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
/* stop / demote */
if (rsc->role != RSC_ROLE_STOPPED) {
if (task == stop_rsc || task == action_demote) {
gIter = rsc->running_on;
for (; gIter != NULL; gIter = gIter->next) {
node_t *current_node = (node_t *) gIter->data;
pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
if (task == action_demote || stop == NULL
|| is_set(stop->flags, pe_action_optional)) {
pe_post_notify(rsc, current_node, n_data, data_set);
}
}
}
}
/* start / promote */
if (rsc->next_role != RSC_ROLE_STOPPED) {
if (rsc->allocated_to == NULL) {
pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
rsc->id);
} else if (task == start_rsc || task == action_promote) {
if (task != start_rsc || start == NULL || is_set(start->flags, pe_action_optional)) {
pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
}
pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
}
}
}
void
free_notification_data(notify_data_t * n_data)
{
if (n_data == NULL) {
return;
}
g_list_free_full(n_data->stop, free);
g_list_free_full(n_data->start, free);
g_list_free_full(n_data->demote, free);
g_list_free_full(n_data->promote, free);
g_list_free_full(n_data->master, free);
g_list_free_full(n_data->slave, free);
g_list_free_full(n_data->active, free);
g_list_free_full(n_data->inactive, free);
g_hash_table_destroy(n_data->keys);
free(n_data);
}
int transition_id = -1;
/*
* Create a dependency graph to send to the transitioner (via the CRMd)
*/
gboolean
stage8(pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
const char *value = NULL;
transition_id++;
crm_trace("Creating transition graph %d.", transition_id);
data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
value = pe_pref(data_set->config_hash, "cluster-delay");
crm_xml_add(data_set->graph, "cluster-delay", value);
value = pe_pref(data_set->config_hash, "stonith-timeout");
crm_xml_add(data_set->graph, "stonith-timeout", value);
crm_xml_add(data_set->graph, "failed-stop-offset", "INFINITY");
if (is_set(data_set->flags, pe_flag_start_failure_fatal)) {
crm_xml_add(data_set->graph, "failed-start-offset", "INFINITY");
} else {
crm_xml_add(data_set->graph, "failed-start-offset", "1");
}
value = pe_pref(data_set->config_hash, "batch-limit");
crm_xml_add(data_set->graph, "batch-limit", value);
crm_xml_add_int(data_set->graph, "transition_id", transition_id);
value = pe_pref(data_set->config_hash, "migration-limit");
if (crm_int_helper(value, NULL) > 0) {
crm_xml_add(data_set->graph, "migration-limit", value);
}
/* errors...
slist_iter(action, action_t, action_list, lpc,
if(action->optional == FALSE && action->runnable == FALSE) {
print_action("Ignoring", action, TRUE);
}
);
*/
gIter = data_set->resources;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
crm_trace("processing actions for rsc=%s", rsc->id);
rsc->cmds->expand(rsc, data_set);
}
crm_log_xml_trace(data_set->graph, "created resource-driven action list");
/* catch any non-resource specific actions */
crm_trace("processing non-resource actions");
gIter = data_set->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (action->rsc
&& action->node
&& action->node->details->shutdown
&& is_not_set(data_set->flags, pe_flag_maintenance_mode)
&& is_not_set(action->flags, pe_action_optional)
&& is_not_set(action->flags, pe_action_runnable)
&& crm_str_eq(action->task, RSC_STOP, TRUE)
) {
crm_crit("Cannot shut down node '%s' because of %s:%s%s",
action->node->details->uname, action->rsc->id,
is_not_set(action->rsc->flags, pe_rsc_managed)?" unmanaged":" blocked",
is_set(action->rsc->flags, pe_rsc_failed)?" failed":"");
}
graph_element_from_action(action, data_set);
}
crm_log_xml_trace(data_set->graph, "created generic action list");
crm_trace("Created transition graph %d.", transition_id);
return TRUE;
}
void
cleanup_alloc_calculations(pe_working_set_t * data_set)
{
if (data_set == NULL) {
return;
}
crm_trace("deleting %d order cons: %p",
g_list_length(data_set->ordering_constraints), data_set->ordering_constraints);
pe_free_ordering(data_set->ordering_constraints);
data_set->ordering_constraints = NULL;
crm_trace("deleting %d node cons: %p",
g_list_length(data_set->placement_constraints), data_set->placement_constraints);
pe_free_rsc_to_node(data_set->placement_constraints);
data_set->placement_constraints = NULL;
crm_trace("deleting %d inter-resource cons: %p",
g_list_length(data_set->colocation_constraints), data_set->colocation_constraints);
g_list_free_full(data_set->colocation_constraints, free);
data_set->colocation_constraints = NULL;
crm_trace("deleting %d ticket deps: %p",
g_list_length(data_set->ticket_constraints), data_set->ticket_constraints);
g_list_free_full(data_set->ticket_constraints, free);
data_set->ticket_constraints = NULL;
cleanup_calculations(data_set);
}
diff --git a/pengine/allocate.h b/pengine/allocate.h
index 6e0f220bb3..c550741e2a 100644
--- a/pengine/allocate.h
+++ b/pengine/allocate.h
@@ -1,193 +1,196 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CRM_PENGINE_COMPLEX_ALLOC__H
# define CRM_PENGINE_COMPLEX_ALLOC__H
# include <glib.h>
# include <crm/common/xml.h>
# include <crm/pengine/status.h>
# include <crm/pengine/complex.h>
# include <crm/pengine/internal.h>
# include <pengine.h>
typedef struct notify_entry_s {
resource_t *rsc;
node_t *node;
} notify_entry_t;
struct resource_alloc_functions_s {
- GHashTable *(*merge_weights) (resource_t *, const char *, GHashTable *, const char *, int,
- gboolean, gboolean);
+ GHashTable *(*merge_weights) (resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights);
node_t *(*allocate) (resource_t *, node_t *, pe_working_set_t *);
void (*create_actions) (resource_t *, pe_working_set_t *);
gboolean(*create_probe) (resource_t *, node_t *, action_t *, gboolean, pe_working_set_t *);
void (*internal_constraints) (resource_t *, pe_working_set_t *);
void (*rsc_colocation_lh) (resource_t *, resource_t *, rsc_colocation_t *);
void (*rsc_colocation_rh) (resource_t *, resource_t *, rsc_colocation_t *);
void (*rsc_location) (resource_t *, rsc_to_node_t *);
enum pe_action_flags (*action_flags) (action_t *, node_t *);
enum pe_graph_flags (*update_actions) (action_t *, action_t *, node_t *, enum pe_action_flags,
enum pe_action_flags, enum pe_ordering);
void (*expand) (resource_t *, pe_working_set_t *);
void (*append_meta) (resource_t * rsc, xmlNode * xml);
};
extern GHashTable *rsc_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes,
- const char *attr, int factor, enum pe_weights flags);
+ const char *attr, float factor, enum pe_weights flags);
+
+extern GHashTable *clone_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes,
+ const char *attr, float factor, enum pe_weights flags);
+
+extern GHashTable *master_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes,
+ const char *attr, float factor, enum pe_weights flags);
extern GHashTable *native_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes,
- const char *attr, int factor, gboolean allow_rollback,
- gboolean only_positive);
+ const char *attr, float factor, enum pe_weights flags);
extern GHashTable *group_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes,
- const char *attr, int factor, gboolean allow_rollback,
- gboolean only_positive);
+ const char *attr, float factor, enum pe_weights flags);
extern node_t *native_color(resource_t * rsc, node_t * preferred, pe_working_set_t * data_set);
extern void native_create_actions(resource_t * rsc, pe_working_set_t * data_set);
extern void native_internal_constraints(resource_t * rsc, pe_working_set_t * data_set);
extern void native_rsc_colocation_lh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void native_rsc_colocation_rh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void rsc_ticket_constraint(resource_t * lh_rsc, rsc_ticket_t * rsc_ticket,
pe_working_set_t * data_set);
extern enum pe_action_flags native_action_flags(action_t * action, node_t * node);
extern void native_rsc_location(resource_t * rsc, rsc_to_node_t * constraint);
extern void native_expand(resource_t * rsc, pe_working_set_t * data_set);
extern void native_dump(resource_t * rsc, const char *pre_text, gboolean details);
extern void create_notify_element(resource_t * rsc, action_t * op,
notify_data_t * n_data, pe_working_set_t * data_set);
extern gboolean native_create_probe(resource_t * rsc, node_t * node, action_t * complete,
gboolean force, pe_working_set_t * data_set);
extern void native_append_meta(resource_t * rsc, xmlNode * xml);
extern int group_num_allowed_nodes(resource_t * rsc);
extern node_t *group_color(resource_t * rsc, node_t * preferred, pe_working_set_t * data_set);
extern void group_create_actions(resource_t * rsc, pe_working_set_t * data_set);
extern void group_internal_constraints(resource_t * rsc, pe_working_set_t * data_set);
extern void group_rsc_colocation_lh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void group_rsc_colocation_rh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern enum pe_action_flags group_action_flags(action_t * action, node_t * node);
extern void group_rsc_location(resource_t * rsc, rsc_to_node_t * constraint);
extern void group_expand(resource_t * rsc, pe_working_set_t * data_set);
extern void group_append_meta(resource_t * rsc, xmlNode * xml);
extern int clone_num_allowed_nodes(resource_t * rsc);
extern node_t *clone_color(resource_t * rsc, node_t * preferred, pe_working_set_t * data_set);
extern void clone_create_actions(resource_t * rsc, pe_working_set_t * data_set);
extern void clone_internal_constraints(resource_t * rsc, pe_working_set_t * data_set);
extern void clone_rsc_colocation_lh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void clone_rsc_colocation_rh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void clone_rsc_location(resource_t * rsc, rsc_to_node_t * constraint);
extern enum pe_action_flags clone_action_flags(action_t * action, node_t * node);
extern void clone_expand(resource_t * rsc, pe_working_set_t * data_set);
extern gboolean clone_create_probe(resource_t * rsc, node_t * node, action_t * complete,
gboolean force, pe_working_set_t * data_set);
extern void clone_append_meta(resource_t * rsc, xmlNode * xml);
extern gboolean master_unpack(resource_t * rsc, pe_working_set_t * data_set);
extern node_t *master_color(resource_t * rsc, node_t * preferred, pe_working_set_t * data_set);
extern void master_create_actions(resource_t * rsc, pe_working_set_t * data_set);
extern void master_internal_constraints(resource_t * rsc, pe_working_set_t * data_set);
extern void master_rsc_colocation_rh(resource_t * lh_rsc, resource_t * rh_rsc,
rsc_colocation_t * constraint);
extern void master_append_meta(resource_t * rsc, xmlNode * xml);
/* extern resource_object_functions_t resource_variants[]; */
extern resource_alloc_functions_t resource_class_alloc_functions[];
extern gboolean is_active(rsc_to_node_t * cons);
extern gboolean native_constraint_violated(resource_t * rsc_lh, resource_t * rsc_rh,
rsc_colocation_t * constraint);
extern gboolean unpack_rsc_to_attr(xmlNode * xml_obj, pe_working_set_t * data_set);
extern gboolean unpack_rsc_to_node(xmlNode * xml_obj, pe_working_set_t * data_set);
extern gboolean unpack_rsc_order(xmlNode * xml_obj, pe_working_set_t * data_set);
extern gboolean unpack_rsc_colocation(xmlNode * xml_obj, pe_working_set_t * data_set);
extern gboolean unpack_rsc_location(xmlNode * xml_obj, pe_working_set_t * data_set);
extern gboolean unpack_rsc_ticket(xmlNode * xml_obj, pe_working_set_t * data_set);
extern void LogActions(resource_t * rsc, pe_working_set_t * data_set, gboolean terminal);
extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
extern notify_data_t *create_notification_boundaries(resource_t * rsc, const char *action,
action_t * start, action_t * end,
pe_working_set_t * data_set);
extern void collect_notification_data(resource_t * rsc, gboolean state, gboolean activity,
notify_data_t * n_data);
extern gboolean expand_notification_data(notify_data_t * n_data);
extern void create_notifications(resource_t * rsc, notify_data_t * n_data,
pe_working_set_t * data_set);
extern void free_notification_data(notify_data_t * n_data);
extern void rsc_migrate_reload(resource_t * rsc, pe_working_set_t * data_set);
extern void rsc_stonith_ordering(resource_t * rsc, action_t * stonith_op,
pe_working_set_t * data_set);
extern enum pe_graph_flags native_update_actions(action_t * first, action_t * then, node_t * node,
enum pe_action_flags flags,
enum pe_action_flags filter,
enum pe_ordering type);
extern enum pe_graph_flags group_update_actions(action_t * first, action_t * then, node_t * node,
enum pe_action_flags flags,
enum pe_action_flags filter, enum pe_ordering type);
extern enum pe_graph_flags clone_update_actions(action_t * first, action_t * then, node_t * node,
enum pe_action_flags flags,
enum pe_action_flags filter, enum pe_ordering type);
static inline gboolean
update_action_flags(action_t * action, enum pe_action_flags flags)
{
gboolean changed = FALSE;
gboolean clear = is_set(flags, pe_action_clear);
enum pe_action_flags last = action->flags;
if (clear) {
pe_clear_action_bit(action, flags);
} else {
pe_set_action_bit(action, flags);
}
if (last != action->flags) {
changed = TRUE;
clear_bit(flags, pe_action_clear);
crm_trace("%s on %s: %sset flags 0x%.6x (was 0x%.6x, now 0x%.6x)",
action->uuid, action->node ? action->node->details->uname : "[none]",
clear ? "un-" : "", flags, last, action->flags);
}
return changed;
}
#endif
diff --git a/pengine/clone.c b/pengine/clone.c
index 7c3168ff21..e616b598a1 100644
--- a/pengine/clone.c
+++ b/pengine/clone.c
@@ -1,1567 +1,1575 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define VARIANT_CLONE 1
#include <lib/pengine/variant.h>
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
static void append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all);
static node_t *
parent_node_instance(const resource_t * rsc, node_t * node)
{
node_t *ret = NULL;
if (node != NULL) {
ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id);
}
return ret;
}
static gboolean
did_fail(const resource_t * rsc)
{
GListPtr gIter = rsc->children;
if (is_set(rsc->flags, pe_rsc_failed)) {
return TRUE;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
if (did_fail(child_rsc)) {
return TRUE;
}
}
return FALSE;
}
gint
sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
{
int rc = 0;
node_t *node1 = NULL;
node_t *node2 = NULL;
gboolean can1 = TRUE;
gboolean can2 = TRUE;
const resource_t *resource1 = (const resource_t *)a;
const resource_t *resource2 = (const resource_t *)b;
CRM_ASSERT(resource1 != NULL);
CRM_ASSERT(resource2 != NULL);
/* allocation order:
* - active instances
* - instances running on nodes with the least copies
* - active instances on nodes that cant support them or are to be fenced
* - failed instances
* - inactive instances
*/
if (resource1->running_on && resource2->running_on) {
if (g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) {
crm_trace( "%s < %s: running_on", resource1->id, resource2->id);
return -1;
} else if (g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) {
crm_trace( "%s > %s: running_on", resource1->id, resource2->id);
return 1;
}
}
if (resource1->running_on) {
node1 = resource1->running_on->data;
}
if (resource2->running_on) {
node2 = resource2->running_on->data;
}
if (node1) {
node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id);
if (match == NULL || match->weight < 0) {
crm_trace( "%s: current location is unavailable", resource1->id);
node1 = NULL;
can1 = FALSE;
}
}
if (node2) {
node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id);
if (match == NULL || match->weight < 0) {
crm_trace( "%s: current location is unavailable", resource2->id);
node2 = NULL;
can2 = FALSE;
}
}
if (can1 != can2) {
if (can1) {
crm_trace( "%s < %s: availability of current location", resource1->id,
resource2->id);
return -1;
}
crm_trace( "%s > %s: availability of current location", resource1->id,
resource2->id);
return 1;
}
if (resource1->priority < resource2->priority) {
crm_trace( "%s < %s: priority", resource1->id, resource2->id);
return 1;
} else if (resource1->priority > resource2->priority) {
crm_trace( "%s > %s: priority", resource1->id, resource2->id);
return -1;
}
if (node1 == NULL && node2 == NULL) {
crm_trace( "%s == %s: not active", resource1->id, resource2->id);
return 0;
}
if (node1 != node2) {
if (node1 == NULL) {
crm_trace( "%s > %s: active", resource1->id, resource2->id);
return 1;
} else if (node2 == NULL) {
crm_trace( "%s < %s: active", resource1->id, resource2->id);
return -1;
}
}
can1 = can_run_resources(node1);
can2 = can_run_resources(node2);
if (can1 != can2) {
if (can1) {
crm_trace( "%s < %s: can", resource1->id, resource2->id);
return -1;
}
crm_trace( "%s > %s: can", resource1->id, resource2->id);
return 1;
}
node1 = parent_node_instance(resource1, node1);
node2 = parent_node_instance(resource2, node2);
if (node1 != NULL && node2 == NULL) {
crm_trace( "%s < %s: not allowed", resource1->id, resource2->id);
return -1;
} else if (node1 == NULL && node2 != NULL) {
crm_trace( "%s > %s: not allowed", resource1->id, resource2->id);
return 1;
}
if (node1 == NULL || node2 == NULL) {
crm_trace( "%s == %s: not allowed", resource1->id, resource2->id);
return 0;
}
if (node1->count < node2->count) {
crm_trace( "%s < %s: count", resource1->id, resource2->id);
return -1;
} else if (node1->count > node2->count) {
crm_trace( "%s > %s: count", resource1->id, resource2->id);
return 1;
}
can1 = did_fail(resource1);
can2 = did_fail(resource2);
if (can1 != can2) {
if (can1) {
crm_trace( "%s > %s: failed", resource1->id, resource2->id);
return 1;
}
crm_trace( "%s < %s: failed", resource1->id, resource2->id);
return -1;
}
if (node1 && node2) {
int lpc = 0;
int max = 0;
node_t *n = NULL;
GListPtr gIter = NULL;
GListPtr list1 = NULL;
GListPtr list2 = NULL;
GHashTable *hash1 =
g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
GHashTable *hash2 =
g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
n = node_copy(resource1->running_on->data);
g_hash_table_insert(hash1, (gpointer) n->details->id, n);
n = node_copy(resource2->running_on->data);
g_hash_table_insert(hash2, (gpointer) n->details->id, n);
for (gIter = resource1->parent->rsc_cons; gIter; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
crm_trace( "Applying %s to %s", constraint->id, resource1->id);
hash1 = native_merge_weights(constraint->rsc_rh, resource1->id, hash1,
constraint->node_attribute,
- constraint->score / INFINITY, FALSE, FALSE);
+ (float) constraint->score / INFINITY, 0);
}
for (gIter = resource1->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
crm_trace( "Applying %s to %s", constraint->id, resource1->id);
hash1 = native_merge_weights(constraint->rsc_lh, resource1->id, hash1,
constraint->node_attribute,
- constraint->score / INFINITY, FALSE, TRUE);
+ (float) constraint->score / INFINITY, pe_weights_positive);
}
for (gIter = resource2->parent->rsc_cons; gIter; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
crm_trace( "Applying %s to %s", constraint->id, resource2->id);
hash2 = native_merge_weights(constraint->rsc_rh, resource2->id, hash2,
constraint->node_attribute,
- constraint->score / INFINITY, FALSE, FALSE);
+ (float) constraint->score / INFINITY, 0);
}
for (gIter = resource2->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
crm_trace( "Applying %s to %s", constraint->id, resource2->id);
hash2 = native_merge_weights(constraint->rsc_lh, resource2->id, hash2,
constraint->node_attribute,
- constraint->score / INFINITY, FALSE, TRUE);
+ (float) constraint->score / INFINITY, pe_weights_positive);
}
/* Current location score */
node1 = g_list_nth_data(resource1->running_on, 0);
node1 = g_hash_table_lookup(hash1, node1->details->id);
node2 = g_list_nth_data(resource2->running_on, 0);
node2 = g_hash_table_lookup(hash2, node2->details->id);
if (node1->weight < node2->weight) {
if (node1->weight < 0) {
crm_trace( "%s > %s: current score", resource1->id, resource2->id);
rc = -1;
goto out;
} else {
crm_trace( "%s < %s: current score", resource1->id, resource2->id);
rc = 1;
goto out;
}
} else if (node1->weight > node2->weight) {
crm_trace( "%s > %s: current score", resource1->id, resource2->id);
rc = -1;
goto out;
}
/* All location scores */
list1 = g_hash_table_get_values(hash1);
list2 = g_hash_table_get_values(hash2);
list1 =
g_list_sort_with_data(list1, sort_node_weight,
g_list_nth_data(resource1->running_on, 0));
list2 =
g_list_sort_with_data(list2, sort_node_weight,
g_list_nth_data(resource2->running_on, 0));
max = g_list_length(list1);
if (max < g_list_length(list2)) {
max = g_list_length(list2);
}
for (; lpc < max; lpc++) {
node1 = g_list_nth_data(list1, lpc);
node2 = g_list_nth_data(list2, lpc);
if (node1 == NULL) {
crm_trace( "%s < %s: colocated score NULL", resource1->id,
resource2->id);
rc = 1;
break;
} else if (node2 == NULL) {
crm_trace( "%s > %s: colocated score NULL", resource1->id,
resource2->id);
rc = -1;
break;
}
if (node1->weight < node2->weight) {
crm_trace( "%s < %s: colocated score", resource1->id,
resource2->id);
rc = 1;
break;
} else if (node1->weight > node2->weight) {
crm_trace( "%s > %s: colocated score", resource1->id,
resource2->id);
rc = -1;
break;
}
}
/* Order by reverse uname - same as sort_node_weight() does? */
out:
g_hash_table_destroy(hash1); /* Free mem */
g_hash_table_destroy(hash2); /* Free mem */
g_list_free(list1);
g_list_free(list2);
if (rc != 0) {
return rc;
}
}
rc = strcmp(resource1->id, resource2->id);
crm_trace( "%s %c %s: default", resource1->id, rc < 0 ? '<' : '>',
resource2->id);
return rc;
}
static node_t *
can_run_instance(resource_t * rsc, node_t * node)
{
node_t *local_node = NULL;
clone_variant_data_t *clone_data = NULL;
if (can_run_resources(node) == FALSE) {
goto bail;
} else if (is_set(rsc->flags, pe_rsc_orphan)) {
goto bail;
}
local_node = parent_node_instance(rsc, node);
get_clone_variant_data(clone_data, rsc->parent);
if (local_node == NULL) {
crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
goto bail;
} else if (local_node->count < clone_data->clone_node_max) {
crm_trace("%s can run on %s: %d", rsc->id, node->details->uname, local_node->count);
return local_node;
} else {
crm_trace("%s cannot run on %s: node full (%d >= %d)",
rsc->id, node->details->uname, local_node->count, clone_data->clone_node_max);
}
bail:
if (node) {
common_update_score(rsc, node->details->id, -INFINITY);
}
return NULL;
}
static node_t *
color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, pe_working_set_t * data_set)
{
node_t *chosen = NULL;
node_t *local_node = NULL;
crm_trace("Processing %s", rsc->id);
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return rsc->fns->location(rsc, NULL, FALSE);
} else if (is_set(rsc->flags, pe_rsc_allocating)) {
crm_debug("Dependency loop detected involving %s", rsc->id);
return NULL;
}
/* Only include positive colocation preferences of dependant resources
* if not every node will get a copy of the clone
*/
append_parent_colocation(rsc->parent, rsc, all_coloc);
if (prefer) {
node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
if (local_prefer == NULL || local_prefer->weight < 0) {
crm_trace("Not pre-allocating %s to %s - unavailable", rsc->id, prefer->details->uname);
return NULL;
}
}
if (rsc->allowed_nodes) {
GHashTableIter iter;
node_t *try_node = NULL;
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&try_node)) {
can_run_instance(rsc, try_node);
}
}
chosen = rsc->cmds->allocate(rsc, prefer, data_set);
if (chosen) {
local_node = pe_hash_table_lookup(rsc->parent->allowed_nodes, chosen->details->id);
if (prefer && chosen && chosen->details != prefer->details) {
crm_err("Pre-allocation failed: got %s instead of %s",
chosen->details->uname, prefer->details->uname);
native_deallocate(rsc);
chosen = NULL;
} else if (local_node) {
local_node->count++;
} else if (is_set(rsc->flags, pe_rsc_managed)) {
/* what to do? we can't enforce per-node limits in this case */
crm_config_err("%s not found in %s (list=%d)",
chosen->details->id, rsc->parent->id,
g_hash_table_size(rsc->parent->allowed_nodes));
}
}
return chosen;
}
static void
append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all)
{
GListPtr gIter = NULL;
gIter = rsc->rsc_cons;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
if (all || cons->score < 0 || cons->score == INFINITY) {
child->rsc_cons = g_list_prepend(child->rsc_cons, cons);
}
}
gIter = rsc->rsc_cons_lhs;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
if (all || cons->score < 0) {
child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons);
}
}
}
node_t *
clone_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
int allocated = 0;
GHashTableIter iter;
GListPtr gIter = NULL;
node_t *node = NULL;
int available_nodes = 0;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return NULL;
} else if (is_set(rsc->flags, pe_rsc_allocating)) {
crm_debug("Dependency loop detected involving %s", rsc->id);
return NULL;
}
set_bit(rsc->flags, pe_rsc_allocating);
crm_trace("Processing %s", rsc->id);
/* this information is used by sort_clone_instance() when deciding in which
* order to allocate clone instances
*/
gIter = rsc->rsc_cons;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
crm_trace("%s: Coloring %s first", rsc->id, constraint->rsc_rh->id);
constraint->rsc_rh->cmds->allocate(constraint->rsc_rh, prefer, data_set);
}
gIter = rsc->rsc_cons_lhs;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
rsc->allowed_nodes =
constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
constraint->node_attribute,
- constraint->score / INFINITY, TRUE, TRUE);
+ (float) constraint->score / INFINITY,
+ (pe_weights_rollback | pe_weights_positive));
}
gIter = rsc->rsc_tickets;
for (; gIter != NULL; gIter = gIter->next) {
rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
if (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby) {
rsc_ticket_constraint(rsc, rsc_ticket, data_set);
}
}
dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes);
/* count now tracks the number of clones currently allocated */
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
node->count = 0;
if (can_run_resources(node)) {
available_nodes++;
}
}
rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set);
/* Pre-allocate as many instances as we can to their current location
*/
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (available_nodes
&& available_nodes <= clone_data->clone_max
&& g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
int lpc;
int loop_max = clone_data->clone_max / available_nodes;
if (loop_max < 1) {
loop_max = 1;
}
if (can_run_resources(node) == FALSE || node->weight < 0) {
crm_trace("Not Pre-allocatiing %s", node->details->uname);
continue;
}
crm_trace("Pre-allocatiing %s", node->details->uname);
for (lpc = 0;
allocated < clone_data->clone_max
&& node->count < clone_data->clone_node_max
&& lpc < clone_data->clone_node_max && lpc < loop_max; lpc++) {
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
if (child->running_on && is_set(child->flags, pe_rsc_provisional)
&& is_not_set(child->flags, pe_rsc_failed)) {
node_t *child_node = child->running_on->data;
if (child_node->details == node->details
&& color_instance(child, node, clone_data->clone_max < available_nodes,
data_set)) {
crm_trace("Pre-allocated %s to %s", child->id, node->details->uname);
allocated++;
break;
}
}
}
}
}
crm_trace("Done pre-allocating");
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
if (g_list_length(child->running_on) > 0) {
node_t *child_node = child->running_on->data;
node_t *local_node = parent_node_instance(child, child->running_on->data);
if (local_node == NULL) {
crm_err("%s is running on %s which isn't allowed",
child->id, child_node->details->uname);
}
}
if (is_not_set(child->flags, pe_rsc_provisional)) {
} else if (allocated >= clone_data->clone_max) {
crm_debug("Child %s not allocated - limit reached", child->id);
resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set);
} else if (color_instance(child, NULL, clone_data->clone_max < available_nodes, data_set)) {
allocated++;
}
}
crm_debug("Allocated %d %s instances of a possible %d",
allocated, rsc->id, clone_data->clone_max);
clear_bit(rsc->flags, pe_rsc_provisional);
clear_bit(rsc->flags, pe_rsc_allocating);
crm_trace("Done allocating %s", rsc->id);
return NULL;
}
static void
clone_update_pseudo_status(resource_t * rsc, gboolean * stopping, gboolean * starting,
gboolean * active)
{
GListPtr gIter = NULL;
if (rsc->children) {
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
clone_update_pseudo_status(child, stopping, starting, active);
}
return;
}
CRM_ASSERT(active != NULL);
CRM_ASSERT(starting != NULL);
CRM_ASSERT(stopping != NULL);
if (rsc->running_on) {
*active = TRUE;
}
gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (*starting && *stopping) {
return;
} else if (is_set(action->flags, pe_action_optional)) {
crm_trace("Skipping optional: %s", action->uuid);
continue;
} else if (is_set(action->flags, pe_action_pseudo) == FALSE
&& is_set(action->flags, pe_action_runnable) == FALSE) {
crm_trace("Skipping unrunnable: %s", action->uuid);
continue;
} else if (safe_str_eq(RSC_STOP, action->task)) {
crm_trace("Stopping due to: %s", action->uuid);
*stopping = TRUE;
} else if (safe_str_eq(RSC_START, action->task)) {
if (is_set(action->flags, pe_action_runnable) == FALSE) {
crm_trace("Skipping pseudo-op: %s run=%d, pseudo=%d",
action->uuid, is_set(action->flags, pe_action_runnable),
is_set(action->flags, pe_action_pseudo));
} else {
crm_trace("Starting due to: %s", action->uuid);
crm_trace("%s run=%d, pseudo=%d",
action->uuid, is_set(action->flags, pe_action_runnable),
is_set(action->flags, pe_action_pseudo));
*starting = TRUE;
}
}
}
}
static action_t *
find_rsc_action(resource_t * rsc, const char *key, gboolean active_only, GListPtr * list)
{
action_t *match = NULL;
GListPtr possible = NULL;
GListPtr active = NULL;
possible = find_actions(rsc->actions, key, NULL);
if (active_only) {
GListPtr gIter = possible;
for (; gIter != NULL; gIter = gIter->next) {
action_t *op = (action_t *) gIter->data;
if (is_set(op->flags, pe_action_optional) == FALSE) {
active = g_list_prepend(active, op);
}
}
if (active && g_list_length(active) == 1) {
match = g_list_nth_data(active, 0);
}
if (list) {
*list = active;
active = NULL;
}
} else if (possible && g_list_length(possible) == 1) {
match = g_list_nth_data(possible, 0);
}
if (list) {
*list = possible;
possible = NULL;
}
if (possible) {
g_list_free(possible);
}
if (active) {
g_list_free(active);
}
return match;
}
static void
child_ordering_constraints(resource_t * rsc, pe_working_set_t * data_set)
{
char *key = NULL;
action_t *stop = NULL;
action_t *start = NULL;
action_t *last_stop = NULL;
action_t *last_start = NULL;
GListPtr gIter = rsc->children;
gboolean active_only = TRUE; /* change to false to get the old behavior */
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (clone_data->ordered == FALSE) {
return;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
key = stop_key(child);
stop = find_rsc_action(child, key, active_only, NULL);
free(key);
key = start_key(child);
start = find_rsc_action(child, key, active_only, NULL);
free(key);
if (stop) {
if (last_stop) {
/* child/child relative stop */
order_actions(stop, last_stop, pe_order_optional);
}
last_stop = stop;
}
if (start) {
if (last_start) {
/* child/child relative start */
order_actions(last_start, start, pe_order_optional);
}
last_start = start;
}
}
}
void
clone_create_actions(resource_t * rsc, pe_working_set_t * data_set)
{
gboolean child_active = FALSE;
gboolean child_starting = FALSE;
gboolean child_stopping = FALSE;
action_t *stop = NULL;
action_t *stopped = NULL;
action_t *start = NULL;
action_t *started = NULL;
GListPtr gIter = rsc->children;
resource_t *last_start_rsc = NULL;
resource_t *last_stop_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_trace("Creating actions for %s", rsc->id);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->create_actions(child_rsc, data_set);
clone_update_pseudo_status(child_rsc, &child_stopping, &child_starting, &child_active);
if (is_set(child_rsc->flags, pe_rsc_starting)) {
last_start_rsc = child_rsc;
}
if (is_set(child_rsc->flags, pe_rsc_stopping)) {
last_stop_rsc = child_rsc;
}
}
/* start */
start = start_action(rsc, NULL, !child_starting);
started = custom_action(rsc, started_key(rsc),
RSC_STARTED, NULL, !child_starting, TRUE, data_set);
update_action_flags(start, pe_action_pseudo | pe_action_runnable);
update_action_flags(started, pe_action_pseudo);
started->priority = INFINITY;
if (child_active || child_starting) {
update_action_flags(started, pe_action_runnable);
}
child_ordering_constraints(rsc, data_set);
if (clone_data->start_notify == NULL) {
clone_data->start_notify =
create_notification_boundaries(rsc, RSC_START, start, started, data_set);
}
/* stop */
stop = stop_action(rsc, NULL, !child_stopping);
stopped = custom_action(rsc, stopped_key(rsc),
RSC_STOPPED, NULL, !child_stopping, TRUE, data_set);
stopped->priority = INFINITY;
update_action_flags(stop, pe_action_pseudo | pe_action_runnable);
update_action_flags(stopped, pe_action_pseudo | pe_action_runnable);
if (clone_data->stop_notify == NULL) {
clone_data->stop_notify =
create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
if (clone_data->stop_notify && clone_data->start_notify) {
order_actions(clone_data->stop_notify->post_done, clone_data->start_notify->pre,
pe_order_optional);
}
}
}
void
clone_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
{
resource_t *last_rsc = NULL;
GListPtr gIter = rsc->children;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_trace("Internal constraints for %s", rsc->id);
new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
if (rsc->variant == pe_master) {
new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->internal_constraints(child_rsc, data_set);
order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
data_set);
if (clone_data->ordered && last_rsc) {
order_start_start(last_rsc, child_rsc, pe_order_optional);
}
order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
data_set);
if (clone_data->ordered && last_rsc) {
order_stop_stop(child_rsc, last_rsc, pe_order_optional);
}
last_rsc = child_rsc;
}
}
static void
assign_node(resource_t * rsc, node_t * node, gboolean force)
{
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
native_assign_node(child_rsc, NULL, node, force);
}
return;
}
native_assign_node(rsc, NULL, node, force);
}
static resource_t *
find_compatible_child_by_node(resource_t * local_child, node_t * local_node, resource_t * rsc,
enum rsc_role_e filter, gboolean current)
{
node_t *node = NULL;
GListPtr gIter = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (local_node == NULL) {
crm_err("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id);
return NULL;
}
crm_trace("Looking for compatible child from %s for %s on %s",
local_child->id, rsc->id, local_node->details->uname);
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
node = child_rsc->fns->location(child_rsc, NULL, current);
if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
crm_trace("Filtered %s", child_rsc->id);
continue;
}
if (node && local_node && node->details == local_node->details) {
crm_trace("Pairing %s with %s on %s",
local_child->id, child_rsc->id, node->details->uname);
return child_rsc;
} else if (node) {
crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
local_node->details->uname);
} else {
crm_trace("%s - not allocated %d", child_rsc->id, current);
}
}
crm_trace("Can't pair %s with %s", local_child->id, rsc->id);
return NULL;
}
resource_t *
find_compatible_child(resource_t * local_child, resource_t * rsc, enum rsc_role_e filter,
gboolean current)
{
resource_t *pair = NULL;
GListPtr gIter = NULL;
GListPtr scratch = NULL;
node_t *local_node = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
local_node = local_child->fns->location(local_child, NULL, current);
if (local_node) {
return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
}
scratch = g_hash_table_get_values(local_child->allowed_nodes);
scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL);
gIter = scratch;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
if (pair) {
goto done;
}
}
crm_debug("Can't pair %s with %s", local_child->id, rsc->id);
done:
g_list_free(scratch);
return pair;
}
void
clone_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
/* -- Never called --
*
* Instead we add the colocation constraints to the child and call from there
*/
GListPtr gIter = rsc_lh->children;
CRM_CHECK(FALSE, crm_err("This functionality is not thought to be used. Please report a bug."));
CRM_CHECK(rsc_lh, return);
CRM_CHECK(rsc_rh, return);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint);
}
return;
}
void
clone_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
GListPtr gIter = NULL;
gboolean do_interleave = FALSE;
clone_variant_data_t *clone_data = NULL;
clone_variant_data_t *clone_data_lh = NULL;
CRM_CHECK(constraint != NULL, return);
CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
CRM_CHECK(rsc_lh->variant == pe_native, return);
get_clone_variant_data(clone_data, constraint->rsc_rh);
crm_trace("Processing constraint %s: %s -> %s %d",
constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
if (constraint->rsc_lh->variant >= pe_clone) {
get_clone_variant_data(clone_data_lh, constraint->rsc_lh);
if (clone_data_lh->interleave && clone_data->clone_node_max != clone_data_lh->clone_node_max) {
crm_config_err("Cannot interleave " XML_CIB_TAG_INCARNATION
" %s and %s because"
" they do not support the same number of"
" resources per node", constraint->rsc_lh->id, constraint->rsc_rh->id);
/* only the LHS side needs to be labeled as interleave */
} else if (clone_data_lh->interleave) {
do_interleave = TRUE;
}
}
if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
crm_trace("%s is still provisional", rsc_rh->id);
return;
} else if (do_interleave) {
resource_t *rh_child = NULL;
rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN, FALSE);
if (rh_child) {
crm_debug("Pairing %s with %s", rsc_lh->id, rh_child->id);
rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint);
} else if (constraint->score >= INFINITY) {
crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
assign_node(rsc_lh, NULL, TRUE);
} else {
crm_debug("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
}
return;
} else if (constraint->score >= INFINITY) {
GListPtr rhs = NULL;
gIter = rsc_rh->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
if (chosen != NULL) {
rhs = g_list_prepend(rhs, chosen);
}
}
node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
g_list_free(rhs);
return;
}
gIter = rsc_rh->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
}
}
static enum action_tasks
clone_child_action(action_t * action)
{
enum action_tasks result = no_action;
resource_t *child = (resource_t *) action->rsc->children->data;
if (safe_str_eq(action->task, "notify")
|| safe_str_eq(action->task, "notified")) {
/* Find the action we're notifying about instead */
int stop = 0;
char *key = action->uuid;
int lpc = strlen(key);
for (; lpc > 0; lpc--) {
if (key[lpc] == '_' && stop == 0) {
stop = lpc;
} else if (key[lpc] == '_') {
char *task_mutable = NULL;
lpc++;
task_mutable = strdup(key + lpc);
task_mutable[stop - lpc] = 0;
crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
result = get_complex_task(child, task_mutable, TRUE);
free(task_mutable);
break;
}
}
} else {
result = get_complex_task(child, action->task, TRUE);
}
return result;
}
enum pe_action_flags
clone_action_flags(action_t * action, node_t * node)
{
GListPtr gIter = NULL;
gboolean any_runnable = FALSE;
gboolean check_runnable = TRUE;
enum action_tasks task = clone_child_action(action);
enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
const char *task_s = task2text(task);
gIter = action->rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
action_t *child_action = NULL;
resource_t *child = (resource_t *) gIter->data;
child_action =
find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
crm_trace("Checking for %s in %s on %s", task_s, child->id,
node ? node->details->uname : "none");
if (child_action) {
enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
if (is_set(flags, pe_action_optional)
&& is_set(child_flags, pe_action_optional) == FALSE) {
crm_trace("%s is manditory because of %s", action->uuid, child_action->uuid);
flags = crm_clear_bit(__FUNCTION__, action->rsc->id, flags, pe_action_optional);
pe_clear_action_bit(action, pe_action_optional);
}
if (is_set(child_flags, pe_action_runnable)) {
any_runnable = TRUE;
}
} else {
GListPtr gIter2 = child->actions;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
action_t *op = (action_t *) gIter2->data;
crm_trace("%s on %s (%s)", op->uuid, op->node ? op->node->details->uname : "none",
op->task);
}
}
}
if (check_runnable && any_runnable == FALSE) {
crm_trace("%s is not runnable because no children are", action->uuid);
flags = crm_clear_bit(__FUNCTION__, action->rsc->id, flags, pe_action_runnable);
if (node == NULL) {
pe_clear_action_bit(action, pe_action_runnable);
}
}
return flags;
}
static enum pe_graph_flags
clone_update_actions_interleave(action_t * first, action_t * then, node_t * node,
enum pe_action_flags flags, enum pe_action_flags filter,
enum pe_ordering type)
{
gboolean current = FALSE;
resource_t *first_child = NULL;
GListPtr gIter = then->rsc->children;
enum pe_graph_flags changed = pe_graph_none; /*pe_graph_disable */
enum action_tasks task = clone_child_action(first);
const char *first_task = task2text(task);
/* Fix this - lazy */
if (strstr(first->uuid, "_stopped_0") || strstr(first->uuid, "_demoted_0")) {
current = TRUE;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *then_child = (resource_t *) gIter->data;
CRM_ASSERT(then_child != NULL);
first_child = find_compatible_child(then_child, first->rsc, RSC_ROLE_UNKNOWN, current);
if (first_child == NULL && current) {
crm_trace("Ignore");
} else if (first_child == NULL) {
crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid,
then->uuid);
/* Me no like this hack - but what else can we do?
*
* If there is no-one active or about to be active
* on the same node as then_child, then they must
* not be allowed to start
*/
if (type & (pe_order_runnable_left | pe_order_implies_then) /* Mandatory */ ) {
crm_info("Inhibiting %s from being active", then_child->id);
assign_node(then_child, NULL, TRUE);
}
} else {
action_t *first_action = NULL;
action_t *then_action = NULL;
crm_debug("Pairing %s with %s", first_child->id, then_child->id);
first_action = find_first_action(first_child->actions, NULL, first_task, node);
then_action = find_first_action(then_child->actions, NULL, then->task, node);
CRM_CHECK(first_action != NULL || is_set(first_child->flags, pe_rsc_orphan),
crm_err("No action found for %s in %s (first)", first_task, first_child->id));
if (then_action == NULL && is_not_set(then_child->flags, pe_rsc_orphan)
&& crm_str_eq(then->task, RSC_STOP, TRUE) == FALSE
&& crm_str_eq(then->task, RSC_DEMOTED, TRUE) == FALSE) {
crm_err("Internal error: No action found for %s in %s (then)", then->task,
then_child->id);
}
if (first_action == NULL || then_action == NULL) {
continue;
}
if (order_actions(first_action, then_action, type)) {
crm_debug("Created constraint for %s -> %s", first_action->uuid, then_action->uuid);
changed |= (pe_graph_updated_first | pe_graph_updated_then);
}
changed |=
then_child->cmds->update_actions(first_action, then_action, node,
first_child->cmds->action_flags(first_action, node),
filter, type);
}
}
return changed;
}
enum pe_graph_flags
clone_update_actions(action_t * first, action_t * then, node_t * node, enum pe_action_flags flags,
enum pe_action_flags filter, enum pe_ordering type)
{
const char *rsc = "none";
gboolean interleave = FALSE;
enum pe_graph_flags changed = pe_graph_none;
if (first->rsc != then->rsc
&& first->rsc && first->rsc->variant >= pe_clone
&& then->rsc && then->rsc->variant >= pe_clone) {
clone_variant_data_t *clone_data = NULL;
if (strstr(then->uuid, "_stop_0") || strstr(then->uuid, "_demote_0")) {
get_clone_variant_data(clone_data, first->rsc);
rsc = first->rsc->id;
} else {
get_clone_variant_data(clone_data, then->rsc);
rsc = then->rsc->id;
}
interleave = clone_data->interleave;
}
crm_trace("Interleave %s -> %s: %s (based on %s)",
first->uuid, then->uuid, interleave ? "yes" : "no", rsc);
if (interleave) {
changed = clone_update_actions_interleave(first, then, node, flags, filter, type);
} else if (then->rsc) {
GListPtr gIter = then->rsc->children;
changed |= native_update_actions(first, then, node, flags, filter, type);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
action_t *child_action = find_first_action(child->actions, NULL, then->task, node);
if (child_action) {
enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
if (is_set(child_flags, pe_action_runnable)) {
changed |=
child->cmds->update_actions(first, child_action, node, flags, filter, type);
}
}
}
}
return changed;
}
void
clone_rsc_location(resource_t * rsc, rsc_to_node_t * constraint)
{
GListPtr gIter = rsc->children;
crm_trace("Processing location constraint %s for %s", constraint->id, rsc->id);
native_rsc_location(rsc, constraint);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_location(child_rsc, constraint);
}
}
void
clone_expand(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *op = (action_t *) gIter->data;
rsc->cmds->action_flags(op, NULL);
}
if (clone_data->start_notify) {
collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
expand_notification_data(clone_data->start_notify);
create_notifications(rsc, clone_data->start_notify, data_set);
}
if (clone_data->stop_notify) {
collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
expand_notification_data(clone_data->stop_notify);
create_notifications(rsc, clone_data->stop_notify, data_set);
}
if (clone_data->promote_notify) {
collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
expand_notification_data(clone_data->promote_notify);
create_notifications(rsc, clone_data->promote_notify, data_set);
}
if (clone_data->demote_notify) {
collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
expand_notification_data(clone_data->demote_notify);
create_notifications(rsc, clone_data->demote_notify, data_set);
}
/* Now that the notifcations have been created we can expand the children */
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->expand(child_rsc, data_set);
}
native_expand(rsc, data_set);
/* The notifications are in the graph now, we can destroy the notify_data */
free_notification_data(clone_data->demote_notify);
clone_data->demote_notify = NULL;
free_notification_data(clone_data->stop_notify);
clone_data->stop_notify = NULL;
free_notification_data(clone_data->start_notify);
clone_data->start_notify = NULL;
free_notification_data(clone_data->promote_notify);
clone_data->promote_notify = NULL;
}
static gint
sort_rsc_id(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t *)a;
const resource_t *resource2 = (const resource_t *)b;
CRM_ASSERT(resource1 != NULL);
CRM_ASSERT(resource2 != NULL);
return strcmp(resource1->id, resource2->id);
}
node_t *
rsc_known_on(resource_t * rsc, GListPtr * list)
{
GListPtr gIter = NULL;
node_t *one = NULL;
GListPtr result = NULL;
if (rsc->children) {
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
rsc_known_on(child, &result);
}
} else if (rsc->known_on) {
result = g_hash_table_get_values(rsc->known_on);
}
if (result && g_list_length(result) == 1) {
one = g_list_nth_data(result, 0);
}
if (list) {
GListPtr gIter = NULL;
gIter = result;
for (; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
*list = g_list_prepend(*list, node);
}
}
}
g_list_free(result);
return one;
}
static resource_t *
find_instance_on(resource_t * rsc, node_t * node)
{
GListPtr gIter = NULL;
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
GListPtr gIter2 = NULL;
GListPtr known_list = NULL;
resource_t *child = (resource_t *) gIter->data;
rsc_known_on(child, &known_list);
gIter2 = known_list;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
node_t *known = (node_t *) gIter2->data;
if (node->details == known->details) {
g_list_free(known_list);
return child;
}
}
g_list_free(known_list);
}
return NULL;
}
gboolean
clone_create_probe(resource_t * rsc, node_t * node, action_t * complete,
gboolean force, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
gboolean any_created = FALSE;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
rsc->children = g_list_sort(rsc->children, sort_rsc_id);
if (rsc->children == NULL) {
pe_warn("Clone %s has no children", rsc->id);
return FALSE;
}
if (is_not_set(rsc->flags, pe_rsc_unique)
&& clone_data->clone_node_max == 1) {
/* only look for one copy */
resource_t *child = NULL;
/* Try whoever we probed last time */
child = find_instance_on(rsc, node);
if (child) {
return child->cmds->create_probe(child, node, complete, force, data_set);
}
/* Try whoever we plan on starting there */
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
node_t *local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
if (local_node == NULL) {
continue;
}
if (local_node->details == node->details) {
return child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set);
}
}
/* Fall back to the first clone instance */
child = rsc->children->data;
return child->cmds->create_probe(child, node, complete, force, data_set);
}
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
if (child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set)) {
any_created = TRUE;
}
if (any_created && is_not_set(rsc->flags, pe_rsc_unique)
&& clone_data->clone_node_max == 1) {
/* only look for one copy (clone :0) */
break;
}
}
return any_created;
}
void
clone_append_meta(resource_t * rsc, xmlNode * xml)
{
char *name = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
free(name);
name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_notify) ? "true" : "false");
free(name);
name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
crm_xml_add_int(xml, name, clone_data->clone_max);
free(name);
name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
crm_xml_add_int(xml, name, clone_data->clone_node_max);
free(name);
}
+
+GHashTable *
+clone_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
+ float factor, enum pe_weights flags)
+{
+ return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags);
+}
diff --git a/pengine/group.c b/pengine/group.c
index e725647ff8..14fb2e2e2a 100644
--- a/pengine/group.c
+++ b/pengine/group.c
@@ -1,514 +1,514 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <pengine.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define VARIANT_GROUP 1
#include <lib/pengine/variant.h>
node_t *
group_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
node_t *node = NULL;
node_t *group_node = NULL;
GListPtr gIter = NULL;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc);
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return rsc->allocated_to;
}
crm_trace("Processing %s", rsc->id);
if (is_set(rsc->flags, pe_rsc_allocating)) {
crm_debug("Dependency loop detected involving %s", rsc->id);
return NULL;
}
if (group_data->first_child == NULL) {
/* nothign to allocate */
clear_bit(rsc->flags, pe_rsc_provisional);
return NULL;
}
set_bit(rsc->flags, pe_rsc_allocating);
rsc->role = group_data->first_child->role;
group_data->first_child->rsc_cons =
g_list_concat(group_data->first_child->rsc_cons, rsc->rsc_cons);
rsc->rsc_cons = NULL;
group_data->first_child->rsc_cons_lhs =
g_list_concat(group_data->first_child->rsc_cons_lhs, rsc->rsc_cons_lhs);
rsc->rsc_cons_lhs = NULL;
gIter = rsc->rsc_tickets;
for (; gIter != NULL; gIter = gIter->next) {
rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
if (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby) {
rsc_ticket_constraint(rsc, rsc_ticket, data_set);
}
}
dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __PRETTY_FUNCTION__,
rsc->allowed_nodes);
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
node = child_rsc->cmds->allocate(child_rsc, prefer, data_set);
if (group_node == NULL) {
group_node = node;
}
}
rsc->next_role = group_data->first_child->next_role;
clear_bit(rsc->flags, pe_rsc_allocating);
clear_bit(rsc->flags, pe_rsc_provisional);
if (group_data->colocated) {
return group_node;
}
return NULL;
}
void group_update_pseudo_status(resource_t * parent, resource_t * child);
void
group_create_actions(resource_t * rsc, pe_working_set_t * data_set)
{
action_t *op = NULL;
const char *value = NULL;
GListPtr gIter = rsc->children;
crm_trace("Creating actions for %s", rsc->id);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->create_actions(child_rsc, data_set);
group_update_pseudo_status(rsc, child_rsc);
}
op = start_action(rsc, NULL, TRUE /* !group_data->child_starting */ );
set_bit(op->flags, pe_action_pseudo | pe_action_runnable);
op = custom_action(rsc, started_key(rsc),
RSC_STARTED, NULL, TRUE /* !group_data->child_starting */ , TRUE, data_set);
set_bit(op->flags, pe_action_pseudo | pe_action_runnable);
op = stop_action(rsc, NULL, TRUE /* !group_data->child_stopping */ );
set_bit(op->flags, pe_action_pseudo | pe_action_runnable);
op = custom_action(rsc, stopped_key(rsc),
RSC_STOPPED, NULL, TRUE /* !group_data->child_stopping */ , TRUE, data_set);
set_bit(op->flags, pe_action_pseudo | pe_action_runnable);
value = g_hash_table_lookup(rsc->meta, "stateful");
if (crm_is_true(value)) {
op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set);
set_bit(op->flags, pe_action_pseudo);
set_bit(op->flags, pe_action_runnable);
op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set);
set_bit(op->flags, pe_action_pseudo);
set_bit(op->flags, pe_action_runnable);
op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set);
set_bit(op->flags, pe_action_pseudo);
set_bit(op->flags, pe_action_runnable);
op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set);
set_bit(op->flags, pe_action_pseudo);
set_bit(op->flags, pe_action_runnable);
}
}
void
group_update_pseudo_status(resource_t * parent, resource_t * child)
{
GListPtr gIter = child->actions;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, parent);
if (group_data->ordered == FALSE) {
/* If this group is not ordered, then leave the meta-actions as optional */
return;
}
if (group_data->child_stopping && group_data->child_starting) {
return;
}
for (; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (is_set(action->flags, pe_action_optional)) {
continue;
}
if (safe_str_eq(RSC_STOP, action->task) && is_set(action->flags, pe_action_runnable)) {
group_data->child_stopping = TRUE;
crm_trace("Based on %s the group is stopping", action->uuid);
} else if (safe_str_eq(RSC_START, action->task)
&& is_set(action->flags, pe_action_runnable)) {
group_data->child_starting = TRUE;
crm_trace("Based on %s the group is starting", action->uuid);
}
}
}
void
group_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = rsc->children;
resource_t *last_rsc = NULL;
resource_t *top = uber_parent(rsc);
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc);
new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
int stop = pe_order_none;
int stopped = pe_order_implies_then_printed;
int start = pe_order_implies_then | pe_order_runnable_left;
int started =
pe_order_runnable_left | pe_order_implies_then | pe_order_implies_then_printed;
child_rsc->cmds->internal_constraints(child_rsc, data_set);
if (last_rsc == NULL) {
if (group_data->ordered) {
stop |= pe_order_optional;
stopped = pe_order_implies_then;
}
} else if (group_data->colocated) {
rsc_colocation_new("group:internal_colocation", NULL, INFINITY,
child_rsc, last_rsc, NULL, NULL, data_set);
}
if (top->variant == pe_master) {
new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE,
stop | pe_order_implies_first_printed, data_set);
new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set);
new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set);
new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
pe_order_implies_first_printed, data_set);
}
order_start_start(rsc, child_rsc, pe_order_implies_first_printed);
order_stop_stop(rsc, child_rsc, stop | pe_order_implies_first_printed);
new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set);
new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set);
if (group_data->ordered == FALSE) {
order_start_start(rsc, child_rsc, start | pe_order_implies_first_printed);
if (top->variant == pe_master) {
new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE,
start | pe_order_implies_first_printed, data_set);
}
} else if (last_rsc != NULL) {
child_rsc->restart_type = pe_restart_restart;
order_start_start(last_rsc, child_rsc, start);
order_stop_stop(child_rsc, last_rsc, pe_order_optional|pe_order_restart);
if (top->variant == pe_master) {
new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set);
new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_optional,
data_set);
}
} else {
/* If anyone in the group is starting, then
* pe_order_implies_then will cause _everyone_ in the group
* to be sent a start action
* But this is safe since starting something that is already
* started is required to be "safe"
*/
int flags = pe_order_none;
order_start_start(rsc, child_rsc, flags);
if (top->variant == pe_master) {
new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, flags, data_set);
}
}
last_rsc = child_rsc;
}
if (group_data->ordered && last_rsc != NULL) {
int stop_stop_flags = pe_order_implies_then;
int stop_stopped_flags = pe_order_optional;
order_stop_stop(rsc, last_rsc, stop_stop_flags);
new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set);
if (top->variant == pe_master) {
new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set);
new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set);
}
}
}
void
group_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
GListPtr gIter = NULL;
group_variant_data_t *group_data = NULL;
if (rsc_lh == NULL) {
pe_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if (rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
}
gIter = rsc_lh->children;
crm_trace("Processing constraints from %s", rsc_lh->id);
get_group_variant_data(group_data, rsc_lh);
if (group_data->colocated) {
group_data->first_child->cmds->rsc_colocation_lh(group_data->first_child, rsc_rh,
constraint);
return;
} else if (constraint->score >= INFINITY) {
crm_config_err("%s: Cannot perform manditory colocation"
" between non-colocated group and %s", rsc_lh->id, rsc_rh->id);
return;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint);
}
}
void
group_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
GListPtr gIter = rsc_rh->children;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc_rh);
CRM_CHECK(rsc_lh->variant == pe_native, return);
crm_trace("Processing RH of constraint %s", constraint->id);
print_resource(LOG_DEBUG_3, "LHS", rsc_lh, TRUE);
if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
return;
} else if (group_data->colocated && group_data->first_child) {
if (constraint->score >= INFINITY) {
/* Ensure RHS is _fully_ up before can start LHS */
group_data->last_child->cmds->rsc_colocation_rh(rsc_lh, group_data->last_child,
constraint);
} else {
/* A partially active RHS is fine */
group_data->first_child->cmds->rsc_colocation_rh(rsc_lh, group_data->first_child,
constraint);
}
return;
} else if (constraint->score >= INFINITY) {
crm_config_err("%s: Cannot perform manditory colocation with"
" non-colocated group: %s", rsc_lh->id, rsc_rh->id);
return;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
}
}
enum pe_action_flags
group_action_flags(action_t * action, node_t * node)
{
GListPtr gIter = NULL;
enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
for (gIter = action->rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
enum action_tasks task = get_complex_task(child, action->task, TRUE);
const char *task_s = task2text(task);
action_t *child_action = find_first_action(child->actions, NULL, task_s, node);
if (child_action) {
enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
if (is_set(flags, pe_action_optional)
&& is_set(child_flags, pe_action_optional) == FALSE) {
crm_trace("%s is manditory because of %s", action->uuid, child_action->uuid);
clear_bit(flags, pe_action_optional);
pe_clear_action_bit(action, pe_action_optional);
}
if (safe_str_neq(task_s, action->task)
&& is_set(flags, pe_action_runnable)
&& is_set(child_flags, pe_action_runnable) == FALSE) {
crm_trace("%s is not runnable because of %s", action->uuid, child_action->uuid);
clear_bit(flags, pe_action_runnable);
pe_clear_action_bit(action, pe_action_runnable);
}
} else if (task != stop_rsc) {
crm_trace("%s is not runnable because of %s (not found in %s)", action->uuid, task_s,
child->id);
clear_bit(flags, pe_action_runnable);
}
}
return flags;
}
enum pe_graph_flags
group_update_actions(action_t * first, action_t * then, node_t * node, enum pe_action_flags flags,
enum pe_action_flags filter, enum pe_ordering type)
{
GListPtr gIter = then->rsc->children;
enum pe_graph_flags changed = pe_graph_none;
CRM_ASSERT(then->rsc != NULL);
changed |= native_update_actions(first, then, node, flags, filter, type);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
action_t *child_action = find_first_action(child->actions, NULL, then->task, node);
if (child_action) {
changed |= child->cmds->update_actions(first, child_action, node, flags, filter, type);
}
}
return changed;
}
void
group_rsc_location(resource_t * rsc, rsc_to_node_t * constraint)
{
GListPtr gIter = rsc->children;
GListPtr saved = constraint->node_list_rh;
GListPtr zero = node_list_dup(constraint->node_list_rh, TRUE, FALSE);
gboolean reset_scores = TRUE;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc);
crm_debug("Processing rsc_location %s for %s", constraint->id, rsc->id);
native_rsc_location(rsc, constraint);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_location(child_rsc, constraint);
if (group_data->colocated && reset_scores) {
reset_scores = FALSE;
constraint->node_list_rh = zero;
}
}
constraint->node_list_rh = saved;
g_list_free_full(zero, free);
}
void
group_expand(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = rsc->children;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc);
crm_trace("Processing actions from %s", rsc->id);
CRM_CHECK(rsc != NULL, return);
native_expand(rsc, data_set);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->expand(child_rsc, data_set);
}
}
GHashTable *
group_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
- int factor, gboolean allow_rollback, gboolean only_positive)
+ float factor, enum pe_weights flags)
{
GListPtr gIter = rsc->rsc_cons_lhs;
group_variant_data_t *group_data = NULL;
get_group_variant_data(group_data, rsc);
if (is_set(rsc->flags, pe_rsc_merging)) {
crm_info("Breaking dependency loop with %s at %s", rsc->id, rhs);
return nodes;
}
set_bit(rsc->flags, pe_rsc_merging);
nodes =
group_data->first_child->cmds->merge_weights(group_data->first_child, rhs, nodes, attr,
- factor, allow_rollback, only_positive);
+ factor, flags);
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
nodes = native_merge_weights(constraint->rsc_lh, rsc->id, nodes,
constraint->node_attribute,
- constraint->score / INFINITY, allow_rollback, only_positive);
+ (float) constraint->score / INFINITY, flags);
}
clear_bit(rsc->flags, pe_rsc_merging);
return nodes;
}
void
group_append_meta(resource_t * rsc, xmlNode * xml)
{
}
diff --git a/pengine/master.c b/pengine/master.c
index 309b7ec8f4..cd457c5ad9 100644
--- a/pengine/master.c
+++ b/pengine/master.c
@@ -1,1028 +1,1037 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define VARIANT_CLONE 1
#include <lib/pengine/variant.h>
extern gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
static int master_score(resource_t * rsc, node_t * node, int not_set_value);
static void
child_promoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
resource_t * rsc, resource_t * child, resource_t * last,
pe_working_set_t * data_set)
{
if (child == NULL) {
if (clone_data->ordered && last != NULL) {
crm_trace("Ordered version (last node)");
/* last child promote before promoted started */
new_rsc_order(last, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
}
return;
}
/* child promote before global promoted */
new_rsc_order(child, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
/* global promote before child promote */
new_rsc_order(rsc, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
if (clone_data->ordered) {
crm_trace("Ordered version");
if (last == NULL) {
/* global promote before first child promote */
last = rsc;
}
/* else: child/child relative promote */
order_start_start(last, child, type);
new_rsc_order(last, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
} else {
crm_trace("Un-ordered version");
}
}
static void
child_demoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
resource_t * rsc, resource_t * child, resource_t * last,
pe_working_set_t * data_set)
{
if (child == NULL) {
if (clone_data->ordered && last != NULL) {
crm_trace("Ordered version (last node)");
/* global demote before first child demote */
new_rsc_order(rsc, RSC_DEMOTE, last, RSC_DEMOTE, pe_order_optional, data_set);
}
return;
}
/* child demote before global demoted */
new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_implies_then_printed, data_set);
/* global demote before child demote */
new_rsc_order(rsc, RSC_DEMOTE, child, RSC_DEMOTE, pe_order_implies_first_printed, data_set);
if (clone_data->ordered && last != NULL) {
crm_trace("Ordered version");
/* child/child relative demote */
new_rsc_order(child, RSC_DEMOTE, last, RSC_DEMOTE, type, data_set);
} else if (clone_data->ordered) {
crm_trace("Ordered version (1st node)");
/* first child stop before global stopped */
new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, type, data_set);
} else {
crm_trace("Un-ordered version");
}
}
static void
master_update_pseudo_status(resource_t * rsc, gboolean * demoting, gboolean * promoting)
{
GListPtr gIter = NULL;
if (rsc->children) {
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
master_update_pseudo_status(child, demoting, promoting);
}
return;
}
CRM_ASSERT(demoting != NULL);
CRM_ASSERT(promoting != NULL);
gIter = rsc->actions;
for (; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (*promoting && *demoting) {
return;
} else if (is_set(action->flags, pe_action_optional)) {
continue;
} else if (safe_str_eq(RSC_DEMOTE, action->task)) {
*demoting = TRUE;
} else if (safe_str_eq(RSC_PROMOTE, action->task)) {
*promoting = TRUE;
}
}
}
#define apply_master_location(list) do { \
gIter2 = list; \
for(; gIter2 != NULL; gIter2 = gIter2->next) { \
rsc_to_node_t *cons = (rsc_to_node_t*)gIter2->data; \
\
cons_node = NULL; \
if(cons->role_filter == RSC_ROLE_MASTER) { \
crm_trace("Applying %s to %s", \
cons->id, child_rsc->id); \
cons_node = pe_find_node_id( \
cons->node_list_rh, chosen->details->id); \
} \
if(cons_node != NULL) { \
int new_priority = merge_weights( \
child_rsc->priority, cons_node->weight); \
crm_trace("\t%s: %d->%d (%d)", child_rsc->id, \
child_rsc->priority, new_priority, cons_node->weight); \
child_rsc->priority = new_priority; \
} \
} \
} while(0)
static node_t *
can_be_master(resource_t * rsc)
{
node_t *node = NULL;
node_t *local_node = NULL;
resource_t *parent = uber_parent(rsc);
clone_variant_data_t *clone_data = NULL;
#if 0
enum rsc_role_e role = RSC_ROLE_UNKNOWN;
role = rsc->fns->state(rsc, FALSE);
crm_info("%s role: %s", rsc->id, role2text(role));
#endif
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
if (can_be_master(child) == NULL) {
crm_trace( "Child %s of %s can't be promoted", child->id, rsc->id);
return NULL;
}
}
}
node = rsc->fns->location(rsc, NULL, FALSE);
if (node == NULL) {
crm_trace( "%s cannot be master: not allocated", rsc->id);
return NULL;
} else if (is_not_set(rsc->flags, pe_rsc_managed)) {
if (rsc->fns->state(rsc, TRUE) == RSC_ROLE_MASTER) {
crm_notice("Forcing unmanaged master %s to remain promoted on %s",
rsc->id, node->details->uname);
} else {
return NULL;
}
} else if (rsc->priority < 0) {
crm_trace( "%s cannot be master: preference: %d", rsc->id, rsc->priority);
return NULL;
} else if (can_run_resources(node) == FALSE) {
crm_trace( "Node cant run any resources: %s", node->details->uname);
return NULL;
}
get_clone_variant_data(clone_data, parent);
local_node = pe_hash_table_lookup(parent->allowed_nodes, node->details->id);
if (local_node == NULL) {
crm_err("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
return NULL;
} else if (local_node->count < clone_data->master_node_max
|| is_not_set(rsc->flags, pe_rsc_managed)) {
return local_node;
} else {
crm_trace( "%s cannot be master on %s: node full",
rsc->id, node->details->uname);
}
return NULL;
}
static gint
sort_master_instance(gconstpointer a, gconstpointer b, gpointer data_set)
{
int rc;
enum rsc_role_e role1 = RSC_ROLE_UNKNOWN;
enum rsc_role_e role2 = RSC_ROLE_UNKNOWN;
const resource_t *resource1 = (const resource_t *)a;
const resource_t *resource2 = (const resource_t *)b;
CRM_ASSERT(resource1 != NULL);
CRM_ASSERT(resource2 != NULL);
role1 = resource1->fns->state(resource1, TRUE);
role2 = resource2->fns->state(resource2, TRUE);
rc = sort_rsc_index(a, b);
if (rc != 0) {
crm_trace("%s %c %s (index)", resource1->id, rc < 0 ? '<' : '>', resource2->id);
return rc;
}
if (role1 > role2) {
crm_trace("%s %c %s (role)", resource1->id, '<', resource2->id);
return -1;
} else if (role1 < role2) {
crm_trace("%s %c %s (role)", resource1->id, '>', resource2->id);
return 1;
}
return sort_clone_instance(a, b, data_set);
}
+GHashTable *
+master_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
+ float factor, enum pe_weights flags)
+{
+ return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags);
+}
+
static void
master_promotion_order(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
node_t *node = NULL;
node_t *chosen = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (clone_data->merged_master_weights) {
return;
}
clone_data->merged_master_weights = TRUE;
crm_trace("Merging weights for %s", rsc->id);
set_bit(rsc->flags, pe_rsc_merging);
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
crm_trace("Sort index: %s = %d", child->id, child->sort_index);
}
dump_node_scores(LOG_DEBUG_3, rsc, "Before", rsc->allowed_nodes);
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
chosen = child->fns->location(child, NULL, FALSE);
if (chosen == NULL || child->sort_index < 0) {
crm_trace("Skipping %s", child->id);
continue;
}
node = (node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
CRM_ASSERT(node != NULL);
/* adds in master preferences and rsc_location.role=Master */
crm_trace("Adding %s to %s from %s", score2char(child->sort_index), node->details->uname,
child->id);
node->weight = merge_weights(child->sort_index, node->weight);
}
dump_node_scores(LOG_DEBUG_3, rsc, "Middle", rsc->allowed_nodes);
gIter = rsc->rsc_cons;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
/* (re-)adds location preferences of resources that the
* master instance should/must be colocated with
*/
if (constraint->role_lh == RSC_ROLE_MASTER) {
+ enum pe_weights flags = constraint->score == INFINITY ? 0 : pe_weights_rollback;
+
crm_trace("RHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
constraint->score);
rsc->allowed_nodes =
constraint->rsc_rh->cmds->merge_weights(constraint->rsc_rh, rsc->id,
rsc->allowed_nodes,
constraint->node_attribute,
- constraint->score / INFINITY,
- constraint->score ==
- INFINITY ? FALSE : TRUE, FALSE);
+ (float) constraint->score / INFINITY,
+ flags);
}
}
gIter = rsc->rsc_cons_lhs;
for (; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
/* (re-)adds location preferences of resource that wish to be
* colocated with the master instance
*/
if (constraint->role_rh == RSC_ROLE_MASTER) {
crm_trace("LHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
constraint->score);
rsc->allowed_nodes =
constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id,
rsc->allowed_nodes,
constraint->node_attribute,
- constraint->score / INFINITY, TRUE, TRUE);
+ (float) constraint->score / INFINITY,
+ (pe_weights_rollback | pe_weights_positive));
}
}
gIter = rsc->rsc_tickets;
for (; gIter != NULL; gIter = gIter->next) {
rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
if (rsc_ticket->role_lh == RSC_ROLE_MASTER
&& (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby)) {
resource_location(rsc, NULL, -INFINITY, "__stateful_without_ticket__", data_set);
}
}
dump_node_scores(LOG_DEBUG_3, rsc, "After", rsc->allowed_nodes);
/* write them back and sort */
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
chosen = child->fns->location(child, NULL, FALSE);
if (is_not_set(child->flags, pe_rsc_managed) && child->next_role == RSC_ROLE_MASTER) {
child->sort_index = INFINITY;
} else if (chosen == NULL || child->sort_index < 0) {
crm_trace("%s: %d", child->id, child->sort_index);
} else {
node = (node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
CRM_ASSERT(node != NULL);
child->sort_index = node->weight;
}
crm_trace("Set sort index: %s = %d", child->id, child->sort_index);
}
rsc->children = g_list_sort_with_data(rsc->children, sort_master_instance, data_set);
clear_bit(rsc->flags, pe_rsc_merging);
}
static gboolean
anonymous_known_on(resource_t * rsc, node_t *node)
{
GListPtr rIter = NULL;
char *key = clone_strip(rsc->id);
resource_t *parent = uber_parent(rsc);
for(rIter = parent->children; rIter; rIter = rIter->next) {
resource_t *child = rIter->data;
/* ->find_rsc() because we might be a cloned group
* and knowing that other members of the group are
* known here implies nothing
*/
rsc = parent->fns->find_rsc(child, key, NULL, pe_find_clone);
crm_trace("Checking %s for %s on %s", rsc->id, key, node->details->uname);
if(g_hash_table_lookup(rsc->known_on, node->details->id)) {
return TRUE;
}
}
return FALSE;
}
static int
master_score(resource_t * rsc, node_t * node, int not_set_value)
{
char *attr_name;
char *name = rsc->id;
const char *attr_value = NULL;
int score = not_set_value, len = 0;
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
int c_score = master_score(child, node, not_set_value);
if (score == not_set_value) {
score = c_score;
} else {
score += c_score;
}
}
return score;
}
if (node == NULL) {
if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED) {
crm_trace("Ingoring master score for %s: unknown state", rsc->id);
return score;
}
} else {
node_t *match = pe_find_node_id(rsc->running_on, node->details->id);
node_t *known = pe_hash_table_lookup(rsc->known_on, node->details->id);
if(is_not_set(rsc->flags, pe_rsc_unique) && anonymous_known_on(rsc, node)) {
crm_trace("Anonymous clone %s is known on %s", rsc->id, node->details->uname);
} else if (match == NULL && known == NULL) {
crm_trace("%s (aka. %s) is not known on %s - ignoring", rsc->id, rsc->clone_name, node->details->uname);
return score;
}
match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
if (match == NULL) {
return score;
} else if (match->weight < 0) {
crm_trace("%s on %s has score: %d - ignoring",
rsc->id, match->details->uname, match->weight);
return score;
}
}
if (rsc->clone_name) {
/* Use the name the lrm knows this resource as,
* since that's what crm_master would have used too
*/
name = rsc->clone_name;
}
len = 8 + strlen(name);
attr_name = calloc(1, len);
sprintf(attr_name, "master-%s", name);
if (node) {
attr_value = g_hash_table_lookup(node->details->attrs, attr_name);
crm_trace("%s: %s[%s] = %s", rsc->id, attr_name, node->details->uname, crm_str(attr_value));
}
if (attr_value != NULL) {
score = char2score(attr_value);
}
free(attr_name);
return score;
}
#define max(a, b) a<b?b:a
static void
apply_master_prefs(resource_t * rsc)
{
int score, new_score;
GListPtr gIter = rsc->children;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (clone_data->applied_master_prefs) {
/* Make sure we only do this once */
return;
}
clone_data->applied_master_prefs = TRUE;
for (; gIter != NULL; gIter = gIter->next) {
GHashTableIter iter;
node_t *node = NULL;
resource_t *child_rsc = (resource_t *) gIter->data;
g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
if (can_run_resources(node) == FALSE) {
/* This node will never be promoted to master,
* so don't apply the master score as that may
* lead to clone shuffling
*/
continue;
}
score = master_score(child_rsc, node, 0);
if (score > 0) {
new_score = merge_weights(node->weight, score);
if (new_score != node->weight) {
crm_trace("\t%s: Updating preference for %s (%d->%d)",
child_rsc->id, node->details->uname, node->weight, new_score);
node->weight = new_score;
}
}
new_score = max(child_rsc->priority, score);
if (new_score != child_rsc->priority) {
crm_trace("\t%s: Updating priority (%d->%d)",
child_rsc->id, child_rsc->priority, new_score);
child_rsc->priority = new_score;
}
}
}
}
static void
set_role_slave(resource_t * rsc, gboolean current)
{
GListPtr gIter = rsc->children;
if (current) {
if (rsc->role == RSC_ROLE_STARTED) {
rsc->role = RSC_ROLE_SLAVE;
}
} else {
GListPtr allocated = NULL;
rsc->fns->location(rsc, &allocated, FALSE);
if (allocated) {
rsc->next_role = RSC_ROLE_SLAVE;
} else {
rsc->next_role = RSC_ROLE_STOPPED;
}
g_list_free(allocated);
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
set_role_slave(child_rsc, current);
}
}
static void
set_role_master(resource_t * rsc)
{
GListPtr gIter = rsc->children;
if (rsc->next_role == RSC_ROLE_UNKNOWN) {
rsc->next_role = RSC_ROLE_MASTER;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
set_role_master(child_rsc);
}
}
node_t *
master_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
int promoted = 0;
GListPtr gIter = NULL;
GListPtr gIter2 = NULL;
GHashTableIter iter;
node_t *node = NULL;
node_t *chosen = NULL;
node_t *cons_node = NULL;
enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return NULL;
} else if (is_set(rsc->flags, pe_rsc_allocating)) {
crm_debug("Dependency loop detected involving %s", rsc->id);
return NULL;
}
apply_master_prefs(rsc);
clone_color(rsc, prefer, data_set);
set_bit(rsc->flags, pe_rsc_allocating);
/* count now tracks the number of masters allocated */
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
node->count = 0;
}
/*
* assign priority
*/
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
GListPtr list = NULL;
resource_t *child_rsc = (resource_t *) gIter->data;
crm_trace("Assigning priority for %s: %s", child_rsc->id,
role2text(child_rsc->next_role));
if (child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
set_role_slave(child_rsc, TRUE);
}
chosen = child_rsc->fns->location(child_rsc, &list, FALSE);
if (g_list_length(list) > 1) {
crm_config_err("Cannot promote non-colocated child %s", child_rsc->id);
}
g_list_free(list);
if (chosen == NULL) {
continue;
}
next_role = child_rsc->fns->state(child_rsc, FALSE);
switch (next_role) {
case RSC_ROLE_STARTED:
case RSC_ROLE_UNKNOWN:
CRM_CHECK(chosen != NULL, break);
/*
* Default to -1 if no value is set
*
* This allows master locations to be specified
* based solely on rsc_location constraints,
* but prevents anyone from being promoted if
* neither a constraint nor a master-score is present
*/
child_rsc->priority = master_score(child_rsc, chosen, -1);
break;
case RSC_ROLE_SLAVE:
case RSC_ROLE_STOPPED:
child_rsc->priority = -INFINITY;
break;
case RSC_ROLE_MASTER:
/* We will arrive here if we're re-creating actions after a stonith
*/
break;
default:
CRM_CHECK(FALSE /* unhandled */ ,
crm_err("Unknown resource role: %d for %s", next_role, child_rsc->id));
}
apply_master_location(child_rsc->rsc_location);
apply_master_location(rsc->rsc_location);
gIter2 = child_rsc->rsc_cons;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
rsc_colocation_t *cons = (rsc_colocation_t *) gIter2->data;
child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons);
}
child_rsc->sort_index = child_rsc->priority;
crm_trace("Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);
if (next_role == RSC_ROLE_MASTER) {
child_rsc->sort_index = INFINITY;
}
}
dump_node_scores(LOG_DEBUG_3, rsc, "Pre merge", rsc->allowed_nodes);
master_promotion_order(rsc, data_set);
/* mark the first N as masters */
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
char *score = score2char(child_rsc->sort_index);
chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
if (show_scores) {
fprintf(stdout, "%s promotion score on %s: %s\n",
child_rsc->id, chosen ? chosen->details->uname : "none", score);
} else {
do_crm_log(scores_log_level, "%s promotion score on %s: %s",
child_rsc->id, chosen ? chosen->details->uname : "none", score);
}
free(score);
chosen = NULL; /* nuke 'chosen' so that we don't promote more than the
* required number of instances
*/
if (child_rsc->sort_index < 0) {
crm_trace("Not supposed to promote child: %s", child_rsc->id);
} else if (promoted < clone_data->master_max || is_not_set(rsc->flags, pe_rsc_managed)) {
chosen = can_be_master(child_rsc);
}
crm_debug("%s master score: %d", child_rsc->id, child_rsc->priority);
if (chosen == NULL) {
set_role_slave(child_rsc, FALSE);
continue;
}
chosen->count++;
crm_info("Promoting %s (%s %s)",
child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
set_role_master(child_rsc);
promoted++;
}
clone_data->masters_allocated = promoted;
crm_info("%s: Promoted %d instances of a possible %d to master",
rsc->id, promoted, clone_data->master_max);
clear_bit(rsc->flags, pe_rsc_provisional);
clear_bit(rsc->flags, pe_rsc_allocating);
return NULL;
}
void
master_create_actions(resource_t * rsc, pe_working_set_t * data_set)
{
action_t *action = NULL;
GListPtr gIter = rsc->children;
action_t *action_complete = NULL;
gboolean any_promoting = FALSE;
gboolean any_demoting = FALSE;
resource_t *last_promote_rsc = NULL;
resource_t *last_demote_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug("Creating actions for %s", rsc->id);
/* create actions as normal */
clone_create_actions(rsc, data_set);
for (; gIter != NULL; gIter = gIter->next) {
gboolean child_promoting = FALSE;
gboolean child_demoting = FALSE;
resource_t *child_rsc = (resource_t *) gIter->data;
crm_trace("Creating actions for %s", child_rsc->id);
child_rsc->cmds->create_actions(child_rsc, data_set);
master_update_pseudo_status(child_rsc, &child_demoting, &child_promoting);
any_demoting = any_demoting || child_demoting;
any_promoting = any_promoting || child_promoting;
crm_trace("Created actions for %s: %d %d", child_rsc->id, child_promoting,
child_demoting);
}
/* promote */
action = promote_action(rsc, NULL, !any_promoting);
action_complete = custom_action(rsc, promoted_key(rsc),
RSC_PROMOTED, NULL, !any_promoting, TRUE, data_set);
action_complete->priority = INFINITY;
update_action_flags(action, pe_action_pseudo);
update_action_flags(action, pe_action_runnable);
update_action_flags(action_complete, pe_action_pseudo);
update_action_flags(action_complete, pe_action_runnable);
if (clone_data->masters_allocated > 0) {
update_action_flags(action, pe_action_runnable);
update_action_flags(action_complete, pe_action_runnable);
}
child_promoting_constraints(clone_data, pe_order_optional,
rsc, NULL, last_promote_rsc, data_set);
if (clone_data->promote_notify == NULL) {
clone_data->promote_notify =
create_notification_boundaries(rsc, RSC_PROMOTE, action, action_complete, data_set);
}
/* demote */
action = demote_action(rsc, NULL, !any_demoting);
action_complete = custom_action(rsc, demoted_key(rsc),
RSC_DEMOTED, NULL, !any_demoting, TRUE, data_set);
action_complete->priority = INFINITY;
update_action_flags(action, pe_action_pseudo);
update_action_flags(action, pe_action_runnable);
update_action_flags(action_complete, pe_action_pseudo);
update_action_flags(action_complete, pe_action_runnable);
child_demoting_constraints(clone_data, pe_order_optional, rsc, NULL, last_demote_rsc, data_set);
if (clone_data->demote_notify == NULL) {
clone_data->demote_notify =
create_notification_boundaries(rsc, RSC_DEMOTE, action, action_complete, data_set);
if (clone_data->promote_notify) {
/* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day
* Requires exposing *_notify
*/
order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre,
pe_order_optional);
order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre,
pe_order_optional);
order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre,
pe_order_optional);
order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre,
pe_order_optional);
order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre,
pe_order_optional);
}
}
/* restore the correct priority */
gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->priority = rsc->priority;
}
}
void
master_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = rsc->children;
resource_t *last_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
clone_internal_constraints(rsc, data_set);
/* global stopped before start */
new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
/* global stopped before promote */
new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
/* global demoted before start */
new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_START, pe_order_optional, data_set);
/* global started before promote */
new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
/* global demoted before stop */
new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
/* global demote before demoted */
new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_optional, data_set);
/* global demoted before promote */
new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
/* child demote before promote */
new_rsc_order(child_rsc, RSC_DEMOTE, child_rsc, RSC_PROMOTE, pe_order_optional, data_set);
child_promoting_constraints(clone_data, pe_order_optional,
rsc, child_rsc, last_rsc, data_set);
child_demoting_constraints(clone_data, pe_order_optional,
rsc, child_rsc, last_rsc, data_set);
last_rsc = child_rsc;
}
}
static void
node_hash_update_one(GHashTable * hash, node_t * other, const char *attr, int score)
{
GHashTableIter iter;
node_t *node = NULL;
const char *value = NULL;
if (other == NULL) {
return;
} else if (attr == NULL) {
attr = "#" XML_ATTR_UNAME;
}
value = g_hash_table_lookup(other->details->attrs, attr);
g_hash_table_iter_init(&iter, hash);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
const char *tmp = g_hash_table_lookup(node->details->attrs, attr);
if (safe_str_eq(value, tmp)) {
crm_trace("%s: %d + %d", node->details->uname, node->weight, other->weight);
node->weight = merge_weights(node->weight, score);
}
}
}
void
master_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
GListPtr gIter = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc_rh);
CRM_CHECK(rsc_rh != NULL, return);
if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
return;
} else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
crm_trace("Handling %s as a clone colocation", constraint->id);
clone_rsc_colocation_rh(rsc_lh, rsc_rh, constraint);
return;
}
CRM_CHECK(rsc_lh != NULL, return);
CRM_CHECK(rsc_lh->variant == pe_native, return);
crm_trace("Processing constraint %s: %d", constraint->id, constraint->score);
if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
gIter = rsc_rh->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
}
} else if (is_set(rsc_lh->flags, pe_rsc_provisional)) {
GListPtr rhs = NULL;
gIter = rsc_rh->children;
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE);
crm_trace("Processing: %s", child_rsc->id);
if (chosen != NULL && next_role == constraint->role_rh) {
crm_trace("Applying: %s %s %s %d", child_rsc->id,
role2text(next_role), chosen->details->uname, constraint->score);
if (constraint->score < INFINITY) {
node_hash_update_one(rsc_lh->allowed_nodes, chosen,
constraint->node_attribute, constraint->score);
}
rhs = g_list_prepend(rhs, chosen);
}
}
/* Only do this if its not a master-master colocation
* Doing this unconditionally would prevent the slaves from being started
*/
if (constraint->role_lh != RSC_ROLE_MASTER || constraint->role_rh != RSC_ROLE_MASTER) {
if (constraint->score >= INFINITY) {
node_list_exclude(rsc_lh->allowed_nodes, rhs, TRUE);
}
}
g_list_free(rhs);
} else if (constraint->role_lh == RSC_ROLE_MASTER) {
resource_t *rh_child = find_compatible_child(rsc_lh, rsc_rh, constraint->role_rh, FALSE);
if (rh_child == NULL && constraint->score >= INFINITY) {
crm_trace("%s can't be promoted %s", rsc_lh->id, constraint->id);
rsc_lh->priority = -INFINITY;
} else if (rh_child != NULL) {
int new_priority = merge_weights(rsc_lh->priority, constraint->score);
crm_debug("Applying %s to %s", constraint->id, rsc_lh->id);
crm_debug("\t%s: %d->%d", rsc_lh->id, rsc_lh->priority, new_priority);
rsc_lh->priority = new_priority;
}
}
return;
}
void
master_append_meta(resource_t * rsc, xmlNode * xml)
{
char *name = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
clone_append_meta(rsc, xml);
name = crm_meta_name(XML_RSC_ATTR_MASTER_MAX);
crm_xml_add_int(xml, name, clone_data->master_max);
free(name);
name = crm_meta_name(XML_RSC_ATTR_MASTER_NODEMAX);
crm_xml_add_int(xml, name, clone_data->master_node_max);
free(name);
}
diff --git a/pengine/native.c b/pengine/native.c
index c907002c5f..ad6429c485 100644
--- a/pengine/native.c
+++ b/pengine/native.c
@@ -1,3145 +1,3200 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <pengine.h>
#include <crm/pengine/rules.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define DELETE_THEN_REFRESH 1 /* The crmd will remove the resource from the CIB itself, making this redundant */
#define INFINITY_HACK (INFINITY * -100)
#define VARIANT_NATIVE 1
#include <lib/pengine/variant.h>
void native_rsc_colocation_rh_must(resource_t * rsc_lh, gboolean update_lh,
resource_t * rsc_rh, gboolean update_rh);
void native_rsc_colocation_rh_mustnot(resource_t * rsc_lh, gboolean update_lh,
resource_t * rsc_rh, gboolean update_rh);
void Recurring(resource_t * rsc, action_t * start, node_t * node, pe_working_set_t * data_set);
void RecurringOp(resource_t * rsc, action_t * start, node_t * node,
xmlNode * operation, pe_working_set_t * data_set);
void Recurring_Stopped(resource_t * rsc, action_t * start, node_t * node,
pe_working_set_t * data_set);
void RecurringOp_Stopped(resource_t * rsc, action_t * start, node_t * node,
xmlNode * operation, pe_working_set_t * data_set);
void pe_post_notify(resource_t * rsc, node_t * node, action_t * op,
notify_data_t * n_data, pe_working_set_t * data_set);
gboolean DeleteRsc(resource_t * rsc, node_t * node, gboolean optional, pe_working_set_t * data_set);
gboolean StopRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set);
gboolean StartRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set);
gboolean DemoteRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set);
gboolean PromoteRsc(resource_t * rsc, node_t * next, gboolean optional,
pe_working_set_t * data_set);
gboolean RoleError(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set);
gboolean NullOp(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set);
/* *INDENT-OFF* */
enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, },
/* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, },
/* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
};
gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,gboolean,pe_working_set_t*) = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, },
/* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, },
/* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, },
/* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, },
/* Master */ { RoleError, DemoteRsc, RoleError, DemoteRsc, NullOp, },
};
/* *INDENT-ON* */
struct capacity_data {
node_t *node;
resource_t *rsc;
gboolean is_enough;
};
static void
check_capacity(gpointer key, gpointer value, gpointer user_data)
{
int required = 0;
int remaining = 0;
struct capacity_data *data = user_data;
required = crm_parse_int(value, "0");
remaining = crm_parse_int(g_hash_table_lookup(data->node->details->utilization, key), "0");
if (required > remaining) {
crm_debug("Node %s has no enough %s for resource %s: required=%d remaining=%d",
data->node->details->uname, (char *)key, data->rsc->id, required, remaining);
data->is_enough = FALSE;
}
}
static gboolean
have_enough_capacity(node_t * node, resource_t * rsc)
{
struct capacity_data data;
data.node = node;
data.rsc = rsc;
data.is_enough = TRUE;
g_hash_table_foreach(rsc->utilization, check_capacity, &data);
return data.is_enough;
}
static gboolean
native_choose_node(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
/*
1. Sort by weight
2. color.chosen_node = the node (of those with the highest wieght)
with the fewest resources
3. remove color.chosen_node from all other colors
*/
int alloc_details = scores_log_level + 1;
GListPtr nodes = NULL;
node_t *chosen = NULL;
int lpc = 0;
int multiple = 0;
int length = 0;
gboolean result = FALSE;
if (safe_str_neq(data_set->placement_strategy, "default")) {
GListPtr gIter = NULL;
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
if (have_enough_capacity(node, rsc) == FALSE) {
crm_debug("Resource %s cannot be allocated to node %s: none of enough capacity",
rsc->id, node->details->uname);
resource_location(rsc, node, -INFINITY, "__limit_utilization_", data_set);
}
}
dump_node_scores(alloc_details, rsc, "Post-utilization", rsc->allowed_nodes);
}
length = g_hash_table_size(rsc->allowed_nodes);
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return rsc->allocated_to ? TRUE : FALSE;
}
if (prefer) {
chosen = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
if (chosen && chosen->weight >= 0 && can_run_resources(chosen)) {
crm_trace("Using preferred node %s for %s instead of choosing from %d candidates",
chosen->details->uname, rsc->id, length);
} else if (chosen && chosen->weight < 0) {
crm_trace("Preferred node %s for %s was unavailable", chosen->details->uname, rsc->id);
chosen = NULL;
} else if (chosen && can_run_resources(chosen)) {
crm_trace("Preferred node %s for %s was unsuitable", chosen->details->uname, rsc->id);
chosen = NULL;
} else {
crm_trace("Preferred node %s for %s was unknown", prefer->details->uname, rsc->id);
}
}
if (chosen == NULL && rsc->allowed_nodes) {
nodes = g_hash_table_get_values(rsc->allowed_nodes);
nodes = g_list_sort_with_data(nodes, sort_node_weight, g_list_nth_data(rsc->running_on, 0));
chosen = g_list_nth_data(nodes, 0);
crm_trace("Chose node %s for %s from %d candidates",
chosen ? chosen->details->uname : "<none>", rsc->id, length);
if (chosen && chosen->weight > 0 && can_run_resources(chosen)) {
node_t *running = g_list_nth_data(rsc->running_on, 0);
if (running && can_run_resources(running) == FALSE) {
crm_trace("Current node for %s (%s) can't run resources",
rsc->id, running->details->uname);
running = NULL;
}
for (lpc = 1; lpc < length && running; lpc++) {
node_t *tmp = g_list_nth_data(nodes, lpc);
if (tmp->weight == chosen->weight) {
multiple++;
if (tmp->details == running->details) {
/* prefer the existing node if scores are equal */
chosen = tmp;
}
}
}
}
}
if (multiple > 1) {
int log_level = LOG_INFO;
char *score = score2char(chosen->weight);
if (chosen->weight >= INFINITY) {
log_level = LOG_WARNING;
}
do_crm_log(log_level, "%d nodes with equal score (%s) for"
" running %s resources. Chose %s.",
multiple, score, rsc->id, chosen->details->uname);
free(score);
}
result = native_assign_node(rsc, nodes, chosen, FALSE);
g_list_free(nodes);
return result;
}
static int
node_list_attr_score(GHashTable * list, const char *attr, const char *value)
{
GHashTableIter iter;
node_t *node = NULL;
int best_score = -INFINITY;
const char *best_node = NULL;
if (attr == NULL) {
attr = "#" XML_ATTR_UNAME;
}
g_hash_table_iter_init(&iter, list);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
int weight = node->weight;
if (can_run_resources(node) == FALSE) {
weight = -INFINITY;
}
if (weight > best_score || best_node == NULL) {
const char *tmp = g_hash_table_lookup(node->details->attrs, attr);
if (safe_str_eq(value, tmp)) {
best_score = weight;
best_node = node->details->uname;
}
}
}
if (safe_str_neq(attr, "#" XML_ATTR_UNAME)) {
crm_info("Best score for %s=%s was %s with %d",
attr, value, best_node ? best_node : "<none>", best_score);
}
return best_score;
}
static void
-node_hash_update(GHashTable * list1, GHashTable * list2, const char *attr, int factor,
+node_hash_update(GHashTable * list1, GHashTable * list2, const char *attr, float factor,
gboolean only_positive)
{
int score = 0;
int new_score = 0;
GHashTableIter iter;
node_t *node = NULL;
if (attr == NULL) {
attr = "#" XML_ATTR_UNAME;
}
g_hash_table_iter_init(&iter, list1);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
CRM_CHECK(node != NULL, continue);
score = node_list_attr_score(list2, attr, g_hash_table_lookup(node->details->attrs, attr));
new_score = merge_weights(factor * score, node->weight);
if (factor < 0 && score < 0) {
/* Negative preference for a node with a negative score
* should not become a positive preference
*
* TODO: Decide if we want to filter only if weight == -INFINITY
*
*/
- crm_trace("%s: Filtering %d + %d*%d (factor * score)",
+ crm_trace("%s: Filtering %d + %f*%d (factor * score)",
node->details->uname, node->weight, factor, score);
} else if (node->weight == INFINITY_HACK) {
- crm_trace("%s: Filtering %d + %d*%d (node < 0)",
+ crm_trace("%s: Filtering %d + %f*%d (node < 0)",
node->details->uname, node->weight, factor, score);
} else if (only_positive && new_score < 0 && node->weight > 0) {
node->weight = INFINITY_HACK;
- crm_trace("%s: Filtering %d + %d*%d (score > 0)",
+ crm_trace("%s: Filtering %d + %f*%d (score > 0)",
node->details->uname, node->weight, factor, score);
} else if (only_positive && new_score < 0 && node->weight == 0) {
- crm_trace("%s: Filtering %d + %d*%d (score == 0)",
+ crm_trace("%s: Filtering %d + %f*%d (score == 0)",
node->details->uname, node->weight, factor, score);
} else {
- crm_trace("%s: %d + %d*%d", node->details->uname, node->weight, factor, score);
+ crm_trace("%s: %d + %f*%d", node->details->uname, node->weight, factor, score);
node->weight = new_score;
}
}
}
static GHashTable *
node_hash_dup(GHashTable * hash)
{
/* Hack! */
GListPtr list = g_hash_table_get_values(hash);
GHashTable *result = node_hash_from_list(list);
g_list_free(list);
return result;
}
GHashTable *
native_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
- int factor, gboolean allow_rollback, gboolean only_positive)
+ float factor, enum pe_weights flags)
{
- enum pe_weights flags = pe_weights_none;
-
- if (only_positive) {
- set_bit(flags, pe_weights_positive);
- }
- if (allow_rollback) {
- set_bit(flags, pe_weights_rollback);
- }
return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags);
}
GHashTable *
rsc_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
- int factor, enum pe_weights flags)
+ float factor, enum pe_weights flags)
{
GHashTable *work = NULL;
int multiplier = 1;
if (factor < 0) {
multiplier = -1;
}
if (is_set(rsc->flags, pe_rsc_merging)) {
crm_info("%s: Breaking dependency loop at %s", rhs, rsc->id);
return nodes;
}
set_bit(rsc->flags, pe_rsc_merging);
if (is_set(flags, pe_weights_init)) {
if (rsc->variant == pe_group && rsc->children) {
GListPtr last = rsc->children;
while (last->next != NULL) {
last = last->next;
}
crm_trace("Merging %s as a group %p %p", rsc->id, rsc->children, last);
work = rsc_merge_weights(last->data, rhs, NULL, attr, factor, flags);
} else {
work = node_hash_dup(rsc->allowed_nodes);
}
clear_bit(flags, pe_weights_init);
} else {
crm_trace("%s: Combining scores from %s", rhs, rsc->id);
work = node_hash_dup(nodes);
node_hash_update(work, rsc->allowed_nodes, attr, factor,
is_set(flags, pe_weights_positive));
}
if (is_set(flags, pe_weights_rollback) && can_run_any(work) == FALSE) {
crm_info("%s: Rolling back scores from %s", rhs, rsc->id);
g_hash_table_destroy(work);
clear_bit(rsc->flags, pe_rsc_merging);
return nodes;
}
if (can_run_any(work)) {
GListPtr gIter = NULL;
if (is_set(flags, pe_weights_forward)) {
gIter = rsc->rsc_cons;
} else {
gIter = rsc->rsc_cons_lhs;
}
for (; gIter != NULL; gIter = gIter->next) {
resource_t *other = NULL;
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
if (is_set(flags, pe_weights_forward)) {
other = constraint->rsc_rh;
} else {
other = constraint->rsc_lh;
}
crm_trace("Applying %s (%s)", constraint->id, other->id);
work = rsc_merge_weights(other, rhs, work, constraint->node_attribute,
- multiplier * constraint->score / INFINITY, flags);
+ multiplier * (float) constraint->score / INFINITY, flags);
dump_node_scores(LOG_TRACE, NULL, rhs, work);
}
}
if(is_set(flags, pe_weights_positive)) {
node_t *node = NULL;
GHashTableIter iter;
g_hash_table_iter_init(&iter, work);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
if (node->weight == INFINITY_HACK) {
node->weight = 1;
}
}
}
if (nodes) {
g_hash_table_destroy(nodes);
}
clear_bit(rsc->flags, pe_rsc_merging);
return work;
}
node_t *
native_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
int alloc_details = scores_log_level + 1;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
if (rsc->parent && is_not_set(rsc->parent->flags, pe_rsc_allocating)) {
/* never allocate children on their own */
crm_debug("Escalating allocation of %s to its parent: %s", rsc->id, rsc->parent->id);
rsc->parent->cmds->allocate(rsc->parent, prefer, data_set);
}
if (is_not_set(rsc->flags, pe_rsc_provisional)) {
return rsc->allocated_to;
}
if (is_set(rsc->flags, pe_rsc_allocating)) {
crm_debug("Dependency loop detected involving %s", rsc->id);
return NULL;
}
set_bit(rsc->flags, pe_rsc_allocating);
print_resource(alloc_details, "Allocating: ", rsc, FALSE);
dump_node_scores(alloc_details, rsc, "Pre-allloc", rsc->allowed_nodes);
for (gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
GHashTable *archive = NULL;
resource_t *rsc_rh = constraint->rsc_rh;
crm_trace("%s: Pre-Processing %s (%s, %d, %s)",
rsc->id, constraint->id, rsc_rh->id,
constraint->score, role2text(constraint->role_lh));
if (constraint->role_lh >= RSC_ROLE_MASTER
|| (constraint->score < 0 && constraint->score > -INFINITY)) {
archive = node_hash_dup(rsc->allowed_nodes);
}
rsc_rh->cmds->allocate(rsc_rh, NULL, data_set);
rsc->cmds->rsc_colocation_lh(rsc, rsc_rh, constraint);
if (archive && can_run_any(rsc->allowed_nodes) == FALSE) {
crm_info("%s: Rolling back scores from %s", rsc->id, rsc_rh->id);
g_hash_table_destroy(rsc->allowed_nodes);
rsc->allowed_nodes = archive;
archive = NULL;
}
if (archive) {
g_hash_table_destroy(archive);
}
}
dump_node_scores(alloc_details, rsc, "Post-coloc", rsc->allowed_nodes);
for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
rsc->allowed_nodes =
constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
constraint->node_attribute,
- constraint->score / INFINITY, TRUE, FALSE);
+ (float) constraint->score / INFINITY,
+ pe_weights_rollback);
}
for (gIter = rsc->rsc_tickets; gIter != NULL; gIter = gIter->next) {
rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
if (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby) {
rsc_ticket_constraint(rsc, rsc_ticket, data_set);
}
}
print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE);
if (rsc->next_role == RSC_ROLE_STOPPED) {
crm_trace("Making sure %s doesn't get allocated", rsc->id);
/* make sure it doesnt come up again */
resource_location(rsc, NULL, -INFINITY, XML_RSC_ATTR_TARGET_ROLE, data_set);
}
dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __PRETTY_FUNCTION__,
rsc->allowed_nodes);
if (is_set(data_set->flags, pe_flag_stonith_enabled)
&& is_set(data_set->flags, pe_flag_have_stonith_resource) == FALSE) {
clear_bit(rsc->flags, pe_rsc_managed);
}
if (is_not_set(rsc->flags, pe_rsc_managed)) {
const char *reason = NULL;
node_t *assign_to = NULL;
rsc->next_role = rsc->role;
if (rsc->running_on == NULL) {
reason = "inactive";
} else if (rsc->role == RSC_ROLE_MASTER) {
assign_to = rsc->running_on->data;
reason = "master";
} else if (is_set(rsc->flags, pe_rsc_failed)) {
reason = "failed";
} else {
assign_to = rsc->running_on->data;
reason = "active";
}
crm_info("Unmanaged resource %s allocated to %s: %s", rsc->id,
assign_to ? assign_to->details->uname : "'nowhere'", reason);
native_assign_node(rsc, NULL, assign_to, TRUE);
} else if (is_set(data_set->flags, pe_flag_stop_everything)
&& safe_str_neq(class, "stonith")) {
crm_debug("Forcing %s to stop", rsc->id);
native_assign_node(rsc, NULL, NULL, TRUE);
} else if (is_set(rsc->flags, pe_rsc_provisional)
&& native_choose_node(rsc, prefer, data_set)) {
crm_trace("Allocated resource %s to %s", rsc->id, rsc->allocated_to->details->uname);
} else if (rsc->allocated_to == NULL) {
if (is_not_set(rsc->flags, pe_rsc_orphan)) {
crm_info("Resource %s cannot run anywhere", rsc->id);
} else if (rsc->running_on != NULL) {
crm_info("Stopping orphan resource %s", rsc->id);
}
} else {
crm_debug("Pre-Allocated resource %s to %s", rsc->id, rsc->allocated_to->details->uname);
}
clear_bit(rsc->flags, pe_rsc_allocating);
print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE);
return rsc->allocated_to;
}
static gboolean
is_op_dup(resource_t * rsc, const char *name, const char *interval)
{
gboolean dup = FALSE;
const char *id = NULL;
const char *value = NULL;
xmlNode *operation = NULL;
for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
operation = __xml_next(operation)) {
if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
value = crm_element_value(operation, "name");
if (safe_str_neq(value, name)) {
continue;
}
value = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
if (value == NULL) {
value = "0";
}
if (safe_str_neq(value, interval)) {
continue;
}
if (id == NULL) {
id = ID(operation);
} else {
crm_config_err("Operation %s is a duplicate of %s", ID(operation), id);
crm_config_err
("Do not use the same (name, interval) combination more than once per resource");
dup = TRUE;
}
}
}
return dup;
}
void
RecurringOp(resource_t * rsc, action_t * start, node_t * node,
xmlNode * operation, pe_working_set_t * data_set)
{
char *key = NULL;
const char *name = NULL;
const char *value = NULL;
const char *interval = NULL;
const char *node_uname = NULL;
unsigned long long interval_ms = 0;
action_t *mon = NULL;
gboolean is_optional = TRUE;
GListPtr possible_matches = NULL;
/* Only process for the operations without role="Stopped" */
value = crm_element_value(operation, "role");
if (value && text2role(value) == RSC_ROLE_STOPPED) {
return;
}
crm_trace("Creating recurring action %s for %s in role %s on %s",
ID(operation), rsc->id, role2text(rsc->next_role),
node ? node->details->uname : "n/a");
if (node != NULL) {
node_uname = node->details->uname;
}
interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
interval_ms = crm_get_interval(interval);
if (interval_ms == 0) {
return;
}
name = crm_element_value(operation, "name");
if (is_op_dup(rsc, name, interval)) {
return;
}
if (safe_str_eq(name, RSC_STOP)
|| safe_str_eq(name, RSC_START)
|| safe_str_eq(name, RSC_DEMOTE)
|| safe_str_eq(name, RSC_PROMOTE)
) {
crm_config_err("Invalid recurring action %s wth name: '%s'", ID(operation), name);
return;
}
key = generate_op_key(rsc->id, name, interval_ms);
if (find_rsc_op_entry(rsc, key) == NULL) {
/* disabled */
free(key);
return;
}
if (start != NULL) {
crm_trace("Marking %s %s due to %s",
key, is_set(start->flags, pe_action_optional) ? "optional" : "manditory",
start->uuid);
is_optional = (rsc->cmds->action_flags(start, NULL) & pe_action_optional);
} else {
crm_trace("Marking %s optional", key);
is_optional = TRUE;
}
/* start a monitor for an already active resource */
possible_matches = find_actions_exact(rsc->actions, key, node);
if (possible_matches == NULL) {
is_optional = FALSE;
crm_trace("Marking %s manditory: not active", key);
} else {
g_list_free(possible_matches);
}
if ((rsc->next_role == RSC_ROLE_MASTER && value == NULL)
|| (value != NULL && text2role(value) != rsc->next_role)) {
int log_level = LOG_DEBUG_2;
const char *result = "Ignoring";
if (is_optional) {
char *local_key = strdup(key);
log_level = LOG_INFO;
result = "Cancelling";
/* its running : cancel it */
mon = custom_action(rsc, local_key, RSC_CANCEL, node, FALSE, TRUE, data_set);
free(mon->task);
mon->task = strdup(RSC_CANCEL);
add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval);
add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name);
local_key = NULL;
switch (rsc->role) {
case RSC_ROLE_SLAVE:
case RSC_ROLE_STARTED:
if (rsc->next_role == RSC_ROLE_MASTER) {
local_key = promote_key(rsc);
} else if (rsc->next_role == RSC_ROLE_STOPPED) {
local_key = stop_key(rsc);
}
break;
case RSC_ROLE_MASTER:
local_key = demote_key(rsc);
break;
default:
break;
}
if (local_key) {
custom_action_order(rsc, NULL, mon, rsc, local_key, NULL,
pe_order_runnable_left, data_set);
}
mon = NULL;
}
do_crm_log(log_level, "%s action %s (%s vs. %s)",
result, key, value ? value : role2text(RSC_ROLE_SLAVE),
role2text(rsc->next_role));
free(key);
key = NULL;
return;
}
mon = custom_action(rsc, key, name, node, is_optional, TRUE, data_set);
key = mon->uuid;
if (is_optional) {
crm_trace("%s\t %s (optional)", crm_str(node_uname), mon->uuid);
}
if (start == NULL || is_set(start->flags, pe_action_runnable) == FALSE) {
crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid);
update_action_flags(mon, pe_action_runnable | pe_action_clear);
} else if (node == NULL || node->details->online == FALSE || node->details->unclean) {
crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid);
update_action_flags(mon, pe_action_runnable | pe_action_clear);
} else if (is_set(mon->flags, pe_action_optional) == FALSE) {
crm_info(" Start recurring %s (%llus) for %s on %s", mon->task, interval_ms / 1000,
rsc->id, crm_str(node_uname));
}
if (rsc->next_role == RSC_ROLE_MASTER) {
char *running_master = crm_itoa(PCMK_EXECRA_RUNNING_MASTER);
add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master);
free(running_master);
}
if (node == NULL || is_set(rsc->flags, pe_rsc_managed)) {
custom_action_order(rsc, start_key(rsc), NULL,
NULL, strdup(key), mon,
pe_order_implies_then | pe_order_runnable_left, data_set);
if (rsc->next_role == RSC_ROLE_MASTER) {
custom_action_order(rsc, promote_key(rsc), NULL,
rsc, NULL, mon,
pe_order_optional | pe_order_runnable_left, data_set);
} else if (rsc->role == RSC_ROLE_MASTER) {
custom_action_order(rsc, demote_key(rsc), NULL,
rsc, NULL, mon,
pe_order_optional | pe_order_runnable_left, data_set);
}
}
}
void
Recurring(resource_t * rsc, action_t * start, node_t * node, pe_working_set_t * data_set)
{
if (is_not_set(data_set->flags, pe_flag_maintenance_mode)) {
xmlNode *operation = NULL;
for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
operation = __xml_next(operation)) {
if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
RecurringOp(rsc, start, node, operation, data_set);
}
}
}
}
void
RecurringOp_Stopped(resource_t * rsc, action_t * start, node_t * node,
xmlNode * operation, pe_working_set_t * data_set)
{
char *key = NULL;
const char *name = NULL;
const char *role = NULL;
const char *interval = NULL;
const char *node_uname = NULL;
unsigned long long interval_ms = 0;
GListPtr possible_matches = NULL;
GListPtr gIter = NULL;
/* TODO: Support of non-unique clone */
if (is_set(rsc->flags, pe_rsc_unique) == FALSE) {
return;
}
/* Only process for the operations with role="Stopped" */
role = crm_element_value(operation, "role");
if (role == NULL || text2role(role) != RSC_ROLE_STOPPED) {
return;
}
crm_trace
("Creating recurring actions %s for %s in role %s on nodes where it'll not be running",
ID(operation), rsc->id, role2text(rsc->next_role));
if (node != NULL) {
node_uname = node->details->uname;
}
interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
interval_ms = crm_get_interval(interval);
if (interval_ms == 0) {
return;
}
name = crm_element_value(operation, "name");
if (is_op_dup(rsc, name, interval)) {
return;
}
if (safe_str_eq(name, RSC_STOP)
|| safe_str_eq(name, RSC_START)
|| safe_str_eq(name, RSC_DEMOTE)
|| safe_str_eq(name, RSC_PROMOTE)
) {
crm_config_err("Invalid recurring action %s wth name: '%s'", ID(operation), name);
return;
}
key = generate_op_key(rsc->id, name, interval_ms);
if (find_rsc_op_entry(rsc, key) == NULL) {
/* disabled */
free(key);
return;
}
/* if the monitor exists on the node where the resource will be running, cancel it */
if (node != NULL) {
possible_matches = find_actions_exact(rsc->actions, key, node);
if (possible_matches) {
action_t *cancel_op = NULL;
char *local_key = strdup(key);
g_list_free(possible_matches);
cancel_op = custom_action(rsc, local_key, RSC_CANCEL, node, FALSE, TRUE, data_set);
free(cancel_op->task);
cancel_op->task = strdup(RSC_CANCEL);
add_hash_param(cancel_op->meta, XML_LRM_ATTR_INTERVAL, interval);
add_hash_param(cancel_op->meta, XML_LRM_ATTR_TASK, name);
local_key = NULL;
if (rsc->next_role == RSC_ROLE_STARTED || rsc->next_role == RSC_ROLE_SLAVE) {
/* rsc->role == RSC_ROLE_STOPPED: cancel the monitor before start */
/* rsc->role == RSC_ROLE_STARTED: for a migration, cancel the monitor on the target node before start */
custom_action_order(rsc, NULL, cancel_op, rsc, start_key(rsc), NULL,
pe_order_runnable_left, data_set);
}
crm_info("Cancel action %s (%s vs. %s) on %s",
key, role, role2text(rsc->next_role), crm_str(node_uname));
}
}
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
node_t *stop_node = (node_t *) gIter->data;
const char *stop_node_uname = stop_node->details->uname;
gboolean is_optional = TRUE;
gboolean probe_is_optional = TRUE;
gboolean stop_is_optional = TRUE;
action_t *stopped_mon = NULL;
char *rc_inactive = NULL;
GListPtr probe_complete_ops = NULL;
GListPtr stop_ops = NULL;
GListPtr local_gIter = NULL;
char *stop_op_key = NULL;
if (node_uname && safe_str_eq(stop_node_uname, node_uname)) {
continue;
}
crm_trace("Creating recurring action %s for %s on %s",
ID(operation), rsc->id, crm_str(stop_node_uname));
/* start a monitor for an already stopped resource */
possible_matches = find_actions_exact(rsc->actions, key, stop_node);
if (possible_matches == NULL) {
crm_trace("Marking %s manditory on %s: not active", key, crm_str(stop_node_uname));
is_optional = FALSE;
} else {
crm_trace("Marking %s optional on %s: already active", key, crm_str(stop_node_uname));
is_optional = TRUE;
g_list_free(possible_matches);
}
stopped_mon = custom_action(rsc, strdup(key), name, stop_node,
is_optional, TRUE, data_set);
rc_inactive = crm_itoa(PCMK_EXECRA_NOT_RUNNING);
add_hash_param(stopped_mon->meta, XML_ATTR_TE_TARGET_RC, rc_inactive);
free(rc_inactive);
probe_complete_ops = find_actions(data_set->actions, CRM_OP_PROBED, NULL);
for (local_gIter = probe_complete_ops; local_gIter != NULL; local_gIter = local_gIter->next) {
action_t *probe_complete = (action_t *) local_gIter->data;
if (probe_complete->node == NULL) {
if (is_set(probe_complete->flags, pe_action_optional) == FALSE) {
probe_is_optional = FALSE;
}
if (is_set(probe_complete->flags, pe_action_runnable) == FALSE) {
crm_debug("%s\t %s (cancelled : probe un-runnable)",
crm_str(stop_node_uname), stopped_mon->uuid);
update_action_flags(stopped_mon, pe_action_runnable | pe_action_clear);
}
if (is_set(rsc->flags, pe_rsc_managed)) {
custom_action_order(NULL, NULL, probe_complete,
NULL, strdup(key), stopped_mon,
pe_order_optional, data_set);
}
break;
}
}
if (probe_complete_ops) {
g_list_free(probe_complete_ops);
}
stop_op_key = stop_key(rsc);
stop_ops = find_actions_exact(rsc->actions, stop_op_key, stop_node);
for (local_gIter = stop_ops; local_gIter != NULL; local_gIter = local_gIter->next) {
action_t *stop = (action_t *) local_gIter->data;
if (is_set(stop->flags, pe_action_optional) == FALSE) {
stop_is_optional = FALSE;
}
if (is_set(stop->flags, pe_action_runnable) == FALSE) {
crm_debug("%s\t %s (cancelled : stop un-runnable)",
crm_str(stop_node_uname), stopped_mon->uuid);
update_action_flags(stopped_mon, pe_action_runnable | pe_action_clear);
}
if (is_set(rsc->flags, pe_rsc_managed)) {
custom_action_order(rsc, strdup(stop_op_key), stop,
NULL, strdup(key), stopped_mon,
pe_order_implies_then | pe_order_runnable_left, data_set);
}
}
if (stop_ops) {
g_list_free(stop_ops);
}
free(stop_op_key);
if (is_optional == FALSE && probe_is_optional && stop_is_optional
&& is_set(rsc->flags, pe_rsc_managed) == FALSE) {
crm_trace("Marking %s optional on %s due to unmanaged",
key, crm_str(stop_node_uname));
update_action_flags(stopped_mon, pe_action_optional);
}
if (is_set(stopped_mon->flags, pe_action_optional)) {
crm_trace("%s\t %s (optional)", crm_str(stop_node_uname), stopped_mon->uuid);
}
if (stop_node->details->online == FALSE || stop_node->details->unclean) {
crm_debug("%s\t %s (cancelled : no node available)",
crm_str(stop_node_uname), stopped_mon->uuid);
update_action_flags(stopped_mon, pe_action_runnable | pe_action_clear);
}
if (is_set(stopped_mon->flags, pe_action_runnable)
&& is_set(stopped_mon->flags, pe_action_optional) == FALSE) {
crm_notice(" Start recurring %s (%llus) for %s on %s", stopped_mon->task,
interval_ms / 1000, rsc->id, crm_str(stop_node_uname));
}
}
free(key);
}
void
Recurring_Stopped(resource_t * rsc, action_t * start, node_t * node, pe_working_set_t * data_set)
{
if (is_not_set(data_set->flags, pe_flag_maintenance_mode)) {
xmlNode *operation = NULL;
for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
operation = __xml_next(operation)) {
if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
RecurringOp_Stopped(rsc, start, node, operation, data_set);
}
}
}
}
void
native_create_actions(resource_t * rsc, pe_working_set_t * data_set)
{
action_t *start = NULL;
node_t *chosen = NULL;
node_t *current = NULL;
gboolean need_stop = FALSE;
GListPtr gIter = NULL;
int num_active_nodes = g_list_length(rsc->running_on);
enum rsc_role_e role = RSC_ROLE_UNKNOWN;
enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
chosen = rsc->allocated_to;
if (chosen != NULL && rsc->next_role == RSC_ROLE_UNKNOWN) {
rsc->next_role = RSC_ROLE_STARTED;
crm_trace("Fixed next_role: unknown -> %s", role2text(rsc->next_role));
} else if (rsc->next_role == RSC_ROLE_UNKNOWN) {
rsc->next_role = RSC_ROLE_STOPPED;
crm_trace("Fixed next_role: unknown -> %s", role2text(rsc->next_role));
}
crm_trace("Processing state transition for %s: %s->%s", rsc->id,
role2text(rsc->role), role2text(rsc->next_role));
if(rsc->running_on) {
current = rsc->running_on->data;
}
get_rsc_attributes(rsc->parameters, rsc, chosen, data_set);
for (gIter = rsc->dangling_migrations; gIter != NULL; gIter = gIter->next) {
node_t *current = (node_t *) gIter->data;
action_t *stop = stop_action(rsc, current, FALSE);
set_bit(stop->flags, pe_action_dangle);
crm_trace("Forcing a cleanup of %s on %s", rsc->id, current->details->uname);
if (is_set(data_set->flags, pe_flag_remove_after_stop)) {
DeleteRsc(rsc, current, FALSE, data_set);
}
}
if (num_active_nodes > 1) {
if (num_active_nodes == 2
&& chosen
&& rsc->partial_migration_target
&& (chosen->details == rsc->partial_migration_target->details)) {
/* Here the chosen node is still the migration target from a partial
* migration. Attempt to continue the migration instead of recovering
* by stopping the resource everywhere and starting it on a single node. */
crm_trace("Will attempt to continue with a partial migration to target %s from %s",
rsc->partial_migration_target->details->id,
rsc->partial_migration_source->details->id);
} else {
const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE);
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
pe_proc_err("Resource %s (%s::%s) is active on %d nodes %s",
rsc->id, class, type, num_active_nodes,
recovery2text(rsc->recovery_type));
crm_warn("See %s for more information.",
"http://clusterlabs.org/wiki/FAQ#Resource_is_Too_Active");
if (rsc->recovery_type == recovery_stop_start) {
need_stop = TRUE;
}
/* If by chance a partial migration is in process,
* but the migration target is not chosen still, clear all
* partial migration data. */
rsc->partial_migration_source = rsc->partial_migration_target = NULL;
}
}
if (is_set(rsc->flags, pe_rsc_start_pending)) {
start = start_action(rsc, chosen, TRUE);
set_bit(start->flags, pe_action_print_always);
}
if(current && chosen && current->details != chosen->details) {
crm_trace("Moving %s", rsc->id);
need_stop = TRUE;
} else if(is_set(rsc->flags, pe_rsc_failed)) {
crm_trace("Recovering %s", rsc->id);
need_stop = TRUE;
} else if(rsc->role > RSC_ROLE_STARTED && current != NULL && chosen != NULL) {
/* Recovery of a promoted resource */
start = start_action(rsc, chosen, TRUE);
if(is_set(start->flags, pe_action_optional) == FALSE) {
crm_trace("Forced start %s", rsc->id);
need_stop = TRUE;
}
}
crm_trace("Creating actions for %s: %s->%s", rsc->id,
role2text(rsc->role), role2text(rsc->next_role));
role = rsc->role;
/* Potentiall optional steps on brining the resource down and back up to the same level */
while (role != RSC_ROLE_STOPPED) {
next_role = rsc_state_matrix[role][RSC_ROLE_STOPPED];
crm_trace("Down: Executing: %s->%s (%s)%s", role2text(role), role2text(next_role), rsc->id, need_stop?" required":"");
if (rsc_action_matrix[role][next_role] (rsc, current, !need_stop, data_set) == FALSE) {
break;
}
role = next_role;
}
while (rsc->role <= rsc->next_role && role != rsc->role) {
next_role = rsc_state_matrix[role][rsc->role];
crm_trace("Up: Executing: %s->%s (%s)%s", role2text(role), role2text(next_role), rsc->id, need_stop?" required":"");
if (rsc_action_matrix[role][next_role] (rsc, chosen, !need_stop, data_set) == FALSE) {
break;
}
role = next_role;
}
role = rsc->role;
/* Required steps from this role to the next */
while (role != rsc->next_role) {
next_role = rsc_state_matrix[role][rsc->next_role];
crm_trace("Role: Executing: %s->%s (%s)", role2text(role), role2text(next_role), rsc->id);
if (rsc_action_matrix[role][next_role] (rsc, chosen, FALSE, data_set) == FALSE) {
break;
}
role = next_role;
}
if (rsc->next_role != RSC_ROLE_STOPPED || is_set(rsc->flags, pe_rsc_managed) == FALSE) {
start = start_action(rsc, chosen, TRUE);
Recurring(rsc, start, chosen, data_set);
Recurring_Stopped(rsc, start, chosen, data_set);
} else {
Recurring_Stopped(rsc, NULL, NULL, data_set);
}
}
void
native_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
{
/* This function is on the critical path and worth optimizing as much as possible */
resource_t *top = uber_parent(rsc);
int type = pe_order_optional | pe_order_implies_then | pe_order_restart;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
custom_action_order(rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL,
rsc, generate_op_key(rsc->id, RSC_START, 0), NULL, type, data_set);
if (top->variant == pe_master) {
custom_action_order(rsc, generate_op_key(rsc->id, RSC_DEMOTE, 0), NULL,
rsc, generate_op_key(rsc->id, RSC_STOP, 0), NULL,
pe_order_implies_first_master, data_set);
custom_action_order(rsc, generate_op_key(rsc->id, RSC_START, 0), NULL,
rsc, generate_op_key(rsc->id, RSC_PROMOTE, 0), NULL,
pe_order_runnable_left, data_set);
}
if (is_not_set(rsc->flags, pe_rsc_managed)) {
crm_trace("Skipping fencing constraints for unmanaged resource: %s", rsc->id);
return;
}
if (safe_str_neq(class, "stonith")) {
action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);
custom_action_order(rsc, stop_key(rsc), NULL,
NULL, strdup(all_stopped->task), all_stopped,
pe_order_implies_then | pe_order_runnable_left, data_set);
}
if (g_hash_table_size(rsc->utilization) > 0
&& safe_str_neq(data_set->placement_strategy, "default")) {
GHashTableIter iter;
node_t *next = NULL;
GListPtr gIter = NULL;
crm_trace("Creating utilization constraints for %s - strategy: %s",
rsc->id, data_set->placement_strategy);
for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
node_t *current = (node_t *) gIter->data;
char *load_stopped_task = crm_concat(LOAD_STOPPED, current->details->uname, '_');
action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set);
if (load_stopped->node == NULL) {
load_stopped->node = node_copy(current);
update_action_flags(load_stopped, pe_action_optional | pe_action_clear);
}
custom_action_order(rsc, stop_key(rsc), NULL,
NULL, load_stopped_task, load_stopped, pe_order_load, data_set);
}
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&next)) {
char *load_stopped_task = crm_concat(LOAD_STOPPED, next->details->uname, '_');
action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set);
if (load_stopped->node == NULL) {
load_stopped->node = node_copy(next);
update_action_flags(load_stopped, pe_action_optional | pe_action_clear);
}
custom_action_order(NULL, strdup(load_stopped_task), load_stopped,
rsc, start_key(rsc), NULL, pe_order_load, data_set);
custom_action_order(NULL, strdup(load_stopped_task), load_stopped,
rsc, generate_op_key(rsc->id, RSC_MIGRATE, 0), NULL,
pe_order_load, data_set);
free(load_stopped_task);
}
}
}
void
native_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
if (rsc_lh == NULL) {
pe_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if (constraint->rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
}
crm_trace("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id);
rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint);
}
-static gboolean
+enum filter_colocation_res {
+ influence_nothing = 0,
+ influence_rsc_location,
+ influence_rsc_priority,
+};
+
+static enum filter_colocation_res
filter_colocation_constraint(resource_t * rsc_lh, resource_t * rsc_rh,
rsc_colocation_t * constraint)
{
if (constraint->score == 0) {
- return FALSE;
+ return influence_nothing;
+ }
+
+ /* rh side must be allocated before we can process constraint */
+ if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
+ return influence_nothing;
+ }
+
+ if ((constraint->role_lh >= RSC_ROLE_SLAVE) &&
+ rsc_lh->parent &&
+ rsc_lh->parent->variant == pe_master &&
+ is_not_set(rsc_lh->flags, pe_rsc_provisional)) {
+
+ /* LH and RH resources have already been allocated, place the correct
+ * priority oh LH rsc for the given multistate resource role */
+ return influence_rsc_priority;
+ }
+
+ if (is_not_set(rsc_lh->flags, pe_rsc_provisional)) {
+ /* error check */
+ struct node_shared_s *details_lh;
+ struct node_shared_s *details_rh;
+
+
+ if ((constraint->score > -INFINITY) && (constraint->score < INFINITY)) {
+ return influence_nothing;
+ }
+
+ details_rh = rsc_rh->allocated_to ? rsc_rh->allocated_to->details : NULL;
+ details_lh = rsc_lh->allocated_to ? rsc_lh->allocated_to->details : NULL;
+
+ if (constraint->score == INFINITY && details_lh != details_rh) {
+ crm_err("%s and %s are both allocated"
+ " but to different nodes: %s vs. %s",
+ rsc_lh->id, rsc_rh->id,
+ details_lh ? details_lh->uname : "n/a", details_rh ? details_rh->uname : "n/a");
+
+ } else if (constraint->score == -INFINITY && details_lh == details_rh) {
+ crm_err("%s and %s are both allocated"
+ " but to the SAME node: %s",
+ rsc_lh->id, rsc_rh->id, details_rh ? details_rh->uname : "n/a");
+ }
+
+ return influence_nothing;
}
if (constraint->score > 0
&& constraint->role_lh != RSC_ROLE_UNKNOWN && constraint->role_lh != rsc_lh->next_role) {
- crm_trace( "LH: Skipping constraint: \"%s\" state filter",
- role2text(constraint->role_rh));
- return FALSE;
+ crm_trace( "LH: Skipping constraint: \"%s\" state filter nextrole is %s",
+ role2text(constraint->role_lh), role2text(rsc_lh->next_role));
+ return influence_nothing;
}
if (constraint->score > 0
&& constraint->role_rh != RSC_ROLE_UNKNOWN && constraint->role_rh != rsc_rh->next_role) {
crm_trace( "RH: Skipping constraint: \"%s\" state filter",
role2text(constraint->role_rh));
return FALSE;
}
if (constraint->score < 0
&& constraint->role_lh != RSC_ROLE_UNKNOWN && constraint->role_lh == rsc_lh->next_role) {
crm_trace( "LH: Skipping -ve constraint: \"%s\" state filter",
- role2text(constraint->role_rh));
- return FALSE;
+ role2text(constraint->role_lh));
+ return influence_nothing;
}
if (constraint->score < 0
&& constraint->role_rh != RSC_ROLE_UNKNOWN && constraint->role_rh == rsc_rh->next_role) {
crm_trace( "RH: Skipping -ve constraint: \"%s\" state filter",
role2text(constraint->role_rh));
- return FALSE;
+ return influence_nothing;
}
- return TRUE;
+ return influence_rsc_location;
+}
+
+static void
+influence_priority(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
+{
+ const char *rh_value = NULL;
+ const char *lh_value = NULL;
+ const char *attribute = "#id";
+ int score_multiplier = 1;
+
+ if (constraint->node_attribute != NULL) {
+ attribute = constraint->node_attribute;
+ }
+
+ if (!rsc_rh->allocated_to || !rsc_lh->allocated_to) {
+ return;
+ }
+
+ lh_value = g_hash_table_lookup(rsc_lh->allocated_to->details->attrs, attribute);
+ rh_value = g_hash_table_lookup(rsc_rh->allocated_to->details->attrs, attribute);
+
+ if (!safe_str_eq(lh_value, rh_value)) {
+ return;
+ }
+
+ if (constraint->role_rh &&
+ (constraint->role_rh != rsc_rh->next_role)) {
+ return;
+ }
+
+ if (constraint->role_lh == RSC_ROLE_SLAVE) {
+ score_multiplier = -1;
+ }
+
+ rsc_lh->priority = merge_weights(score_multiplier * constraint->score, rsc_lh->priority);
}
static void
colocation_match(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
const char *tmp = NULL;
const char *value = NULL;
const char *attribute = "#id";
GHashTable *work = NULL;
gboolean do_check = FALSE;
GHashTableIter iter;
node_t *node = NULL;
if (constraint->node_attribute != NULL) {
attribute = constraint->node_attribute;
}
if (rsc_rh->allocated_to) {
value = g_hash_table_lookup(rsc_rh->allocated_to->details->attrs, attribute);
do_check = TRUE;
} else if (constraint->score < 0) {
/* nothing to do:
* anti-colocation with something thats not running
*/
return;
}
work = node_hash_dup(rsc_lh->allowed_nodes);
g_hash_table_iter_init(&iter, work);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
tmp = g_hash_table_lookup(node->details->attrs, attribute);
if (do_check && safe_str_eq(tmp, value)) {
if (constraint->score < INFINITY) {
crm_trace("%s: %s.%s += %d", constraint->id, rsc_lh->id,
node->details->uname, constraint->score);
node->weight = merge_weights(constraint->score, node->weight);
}
} else if (do_check == FALSE || constraint->score >= INFINITY) {
crm_trace("%s: %s.%s -= %d (%s)", constraint->id, rsc_lh->id,
node->details->uname, constraint->score,
do_check ? "failed" : "unallocated");
node->weight = merge_weights(-constraint->score, node->weight);
}
}
if (can_run_any(work)
|| constraint->score <= -INFINITY || constraint->score >= INFINITY) {
g_hash_table_destroy(rsc_lh->allowed_nodes);
rsc_lh->allowed_nodes = work;
work = NULL;
} else {
char *score = score2char(constraint->score);
crm_info("%s: Rolling back scores from %s (%d, %s)",
rsc_lh->id, rsc_rh->id, do_check, score);
free(score);
}
if (work) {
g_hash_table_destroy(work);
}
}
void
native_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
{
- crm_trace("%sColocating %s with %s (%s, weight=%d)",
- constraint->score >= 0 ? "" : "Anti-",
- rsc_lh->id, rsc_rh->id, constraint->id, constraint->score);
-
- if (filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) {
- return;
- }
+ enum filter_colocation_res filter_results;
- if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
- return;
-
- } else if (is_not_set(rsc_lh->flags, pe_rsc_provisional)) {
- /* error check */
- struct node_shared_s *details_lh;
- struct node_shared_s *details_rh;
+ filter_results = filter_colocation_constraint(rsc_lh, rsc_rh, constraint);
- if ((constraint->score > -INFINITY) && (constraint->score < INFINITY)) {
- return;
- }
-
- details_rh = rsc_rh->allocated_to ? rsc_rh->allocated_to->details : NULL;
- details_lh = rsc_lh->allocated_to ? rsc_lh->allocated_to->details : NULL;
-
- if (constraint->score == INFINITY && details_lh != details_rh) {
- crm_err("%s and %s are both allocated"
- " but to different nodes: %s vs. %s",
- rsc_lh->id, rsc_rh->id,
- details_lh ? details_lh->uname : "n/a", details_rh ? details_rh->uname : "n/a");
-
- } else if (constraint->score == -INFINITY && details_lh == details_rh) {
- crm_err("%s and %s are both allocated"
- " but to the SAME node: %s",
- rsc_lh->id, rsc_rh->id, details_rh ? details_rh->uname : "n/a");
- }
-
- return;
-
- } else {
+ switch (filter_results) {
+ case influence_rsc_priority:
+ influence_priority(rsc_lh, rsc_rh, constraint);
+ break;
+ case influence_rsc_location:
+ crm_trace("%sColocating %s with %s (%s, weight=%d)",
+ constraint->score >= 0 ? "" : "Anti-",
+ rsc_lh->id, rsc_rh->id, constraint->id, constraint->score);
colocation_match(rsc_lh, rsc_rh, constraint);
+ break;
+ case influence_nothing:
+ default:
+ return;
}
}
static gboolean
filter_rsc_ticket(resource_t * rsc_lh, rsc_ticket_t * rsc_ticket)
{
if (rsc_ticket->role_lh != RSC_ROLE_UNKNOWN && rsc_ticket->role_lh != rsc_lh->role) {
crm_trace( "LH: Skipping constraint: \"%s\" state filter",
role2text(rsc_ticket->role_lh));
return FALSE;
}
return TRUE;
}
void
rsc_ticket_constraint(resource_t * rsc_lh, rsc_ticket_t * rsc_ticket, pe_working_set_t * data_set)
{
if (rsc_ticket == NULL) {
pe_err("rsc_ticket was NULL");
return;
}
if (rsc_lh == NULL) {
pe_err("rsc_lh was NULL for %s", rsc_ticket->id);
return;
}
if (rsc_ticket->ticket->granted && rsc_ticket->ticket->standby == FALSE) {
return;
}
if (rsc_lh->children) {
GListPtr gIter = rsc_lh->children;
crm_trace("Processing ticket dependencies from %s", rsc_lh->id);
for (; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
rsc_ticket_constraint(child_rsc, rsc_ticket, data_set);
}
return;
}
crm_trace("%s: Processing ticket dependency on %s (%s, %s)",
rsc_lh->id, rsc_ticket->ticket->id, rsc_ticket->id, role2text(rsc_ticket->role_lh));
if (rsc_ticket->ticket->granted == FALSE && g_list_length(rsc_lh->running_on) > 0) {
GListPtr gIter = NULL;
switch (rsc_ticket->loss_policy) {
case loss_ticket_stop:
resource_location(rsc_lh, NULL, -INFINITY, "__loss_of_ticket__", data_set);
break;
case loss_ticket_demote:
/*Promotion score will be set to -INFINITY in master_promotion_order() */
if (rsc_ticket->role_lh != RSC_ROLE_MASTER) {
resource_location(rsc_lh, NULL, -INFINITY, "__loss_of_ticket__", data_set);
}
break;
case loss_ticket_fence:
if (filter_rsc_ticket(rsc_lh, rsc_ticket) == FALSE) {
return;
}
resource_location(rsc_lh, NULL, -INFINITY, "__loss_of_ticket__", data_set);
for (gIter = rsc_lh->running_on; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
crm_warn("Node %s will be fenced for deadman", node->details->uname);
node->details->unclean = TRUE;
}
break;
case loss_ticket_freeze:
if (filter_rsc_ticket(rsc_lh, rsc_ticket) == FALSE) {
return;
}
if (g_list_length(rsc_lh->running_on) > 0) {
clear_bit(rsc_lh->flags, pe_rsc_managed);
set_bit(rsc_lh->flags, pe_rsc_block);
}
break;
}
} else if (rsc_ticket->ticket->granted == FALSE){
if (rsc_ticket->role_lh != RSC_ROLE_MASTER || rsc_ticket->loss_policy == loss_ticket_stop) {
resource_location(rsc_lh, NULL, -INFINITY, "__no_ticket__", data_set);
}
} else if (rsc_ticket->ticket->standby) {
if (rsc_ticket->role_lh != RSC_ROLE_MASTER || rsc_ticket->loss_policy == loss_ticket_stop) {
resource_location(rsc_lh, NULL, -INFINITY, "__ticket_standby__", data_set);
}
}
}
const char *convert_non_atomic_task(char *raw_task, resource_t * rsc, gboolean allow_notify);
const char *
convert_non_atomic_task(char *raw_task, resource_t * rsc, gboolean allow_notify)
{
int task = no_action;
const char *atomic_task = raw_task;
crm_trace("Processing %s for %s", crm_str(raw_task), rsc->id);
if (raw_task == NULL) {
return NULL;
} else if (strstr(raw_task, "notify") != NULL) {
goto done; /* no conversion */
} else if (rsc->variant < pe_group) {
goto done; /* no conversion */
}
task = text2task(raw_task);
switch (task) {
case stop_rsc:
case start_rsc:
case action_notify:
case action_promote:
case action_demote:
break;
case stopped_rsc:
case started_rsc:
case action_notified:
case action_promoted:
case action_demoted:
task--;
break;
case monitor_rsc:
case shutdown_crm:
case stonith_node:
goto done;
break;
default:
crm_trace("Unknown action: %s", raw_task);
goto done;
break;
}
if (task != no_action) {
if (is_set(rsc->flags, pe_rsc_notify) && allow_notify) {
/* atomic_task = generate_notify_key(rid, "confirmed-post", task2text(task+1)); */
crm_err("Not handled");
} else {
atomic_task = task2text(task + 1);
}
crm_trace("Converted %s -> %s", raw_task, atomic_task);
}
done:
return atomic_task;
}
enum pe_action_flags
native_action_flags(action_t * action, node_t * node)
{
return action->flags;
}
enum pe_graph_flags
native_update_actions(action_t * first, action_t * then, node_t * node, enum pe_action_flags flags,
enum pe_action_flags filter, enum pe_ordering type)
{
/* flags == get_action_flags(first, then_node) called from update_action() */
enum pe_graph_flags changed = pe_graph_none;
enum pe_action_flags then_flags = then->flags;
enum pe_action_flags first_flags = first->flags;
if (type & pe_order_asymmetrical) {
resource_t *then_rsc = then->rsc;
enum rsc_role_e then_rsc_role = then_rsc ? then_rsc->fns->state(then_rsc, TRUE) : 0;
if (!then_rsc) {
/* ignore */
} else if ((then_rsc_role == RSC_ROLE_STOPPED) && safe_str_eq(then->task, RSC_STOP)) {
/* ignore... if 'then' is supposed to be stopped after 'first', but
* then is already stopped, there is nothing to be done when non-symmetrical. */
} else if ((then_rsc_role == RSC_ROLE_STARTED) && safe_str_eq(then->task, RSC_START)) {
/* ignore... if 'then' is supposed to be started after 'first', but
* then is already started, there is nothing to be done when non-symmetrical. */
} else if (!(first->flags & pe_action_runnable)) {
/* prevent 'then' action from happening if 'first' is not runnable and
* 'then' has not yet occurred. */
pe_clear_action_bit(then, pe_action_runnable);
pe_clear_action_bit(then, pe_action_optional);
crm_trace("Unset optional and runnable on %s", then->uuid);
} else {
/* ignore... then is allowed to start/stop if it wants to. */
}
}
if (type & pe_order_implies_first) {
if ((filter & pe_action_optional) && (flags & pe_action_optional) == 0) {
crm_trace("Unset optional on %s because of %s", first->uuid, then->uuid);
pe_clear_action_bit(first, pe_action_optional);
}
}
if (type & pe_order_implies_first_master) {
if ((filter & pe_action_optional) &&
((then->flags & pe_action_optional) == FALSE) &&
then->rsc && (then->rsc->role == RSC_ROLE_MASTER)) {
clear_bit(first->flags, pe_action_optional);
}
}
if (is_set(type, pe_order_runnable_left)
&& is_set(filter, pe_action_runnable)
&& is_set(then->flags, pe_action_runnable)
&& is_set(flags, pe_action_runnable) == FALSE) {
crm_trace("Unset runnable on %s because of %s", then->uuid, first->uuid);
pe_clear_action_bit(then, pe_action_runnable);
}
if (is_set(type, pe_order_implies_then)
&& is_set(filter, pe_action_optional)
&& is_set(then->flags, pe_action_optional)
&& is_set(flags, pe_action_optional) == FALSE) {
crm_trace("Unset optional on %s because of %s", then->uuid, first->uuid);
pe_clear_action_bit(then, pe_action_optional);
}
if (is_set(type, pe_order_restart)) {
const char *reason = NULL;
CRM_ASSERT(first->rsc && first->rsc->variant == pe_native);
CRM_ASSERT(then->rsc && then->rsc->variant == pe_native);
if ((filter & pe_action_runnable) && (then->flags & pe_action_runnable) == 0) {
reason = "shutdown";
}
if ((filter & pe_action_optional) && (then->flags & pe_action_optional) == 0) {
reason = "recover";
}
if (reason && is_set(first->flags, pe_action_optional)
&& is_set(first->flags, pe_action_runnable)) {
crm_trace("Handling %s: %s -> %s", reason, first->uuid, then->uuid);
pe_clear_action_bit(first, pe_action_optional);
}
if (reason && is_not_set(first->flags, pe_action_optional)
&& is_not_set(first->flags, pe_action_runnable)) {
crm_trace("Handling %s: %s -> %s", reason, first->uuid, then->uuid);
pe_clear_action_bit(then, pe_action_runnable);
}
}
if (then_flags != then->flags) {
changed |= pe_graph_updated_then;
crm_trace("Then: Flags for %s on %s are now 0x%.6x (was 0x%.6x) because of %s 0x%.6x",
then->uuid, then->node ? then->node->details->uname : "[none]", then->flags,
then_flags, first->uuid, first->flags);
}
if (first_flags != first->flags) {
changed |= pe_graph_updated_first;
crm_trace("First: Flags for %s on %s are now 0x%.6x (was 0x%.6x) because of %s 0x%.6x",
first->uuid, first->node ? first->node->details->uname : "[none]", first->flags,
first_flags, then->uuid, then->flags);
}
return changed;
}
void
native_rsc_location(resource_t * rsc, rsc_to_node_t * constraint)
{
GListPtr gIter = NULL;
GHashTableIter iter;
node_t *node = NULL;
if (constraint == NULL) {
pe_err("Constraint is NULL");
return;
} else if (rsc == NULL) {
pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id);
return;
}
crm_trace("Applying %s (%s) to %s", constraint->id,
role2text(constraint->role_filter), rsc->id);
/* take "lifetime" into account */
if (constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) {
crm_debug("Constraint (%s) is not active (role : %s)",
constraint->id, role2text(constraint->role_filter));
return;
} else if (is_active(constraint) == FALSE) {
crm_trace("Constraint (%s) is not active", constraint->id);
return;
}
if (constraint->node_list_rh == NULL) {
crm_trace("RHS of constraint %s is NULL", constraint->id);
return;
}
for (gIter = constraint->node_list_rh; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
node_t *other_node = NULL;
other_node = (node_t *) pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
if (other_node != NULL) {
crm_trace("%s + %s: %d + %d",
node->details->uname,
other_node->details->uname, node->weight, other_node->weight);
other_node->weight = merge_weights(other_node->weight, node->weight);
} else {
node_t *new_node = node_copy(node);
g_hash_table_insert(rsc->allowed_nodes, (gpointer) new_node->details->id, new_node);
}
}
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
crm_trace("%s + %s : %d", rsc->id, node->details->uname, node->weight);
}
}
void
native_expand(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
crm_trace("Processing actions from %s", rsc->id);
for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
crm_trace("processing action %d for rsc=%s", action->id, rsc->id);
graph_element_from_action(action, data_set);
}
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
child_rsc->cmds->expand(child_rsc, data_set);
}
}
void
#define log_change(fmt, args...) do { \
if(terminal) { \
printf(" * "fmt"\n", ##args); \
} else { \
crm_notice(fmt, ##args); \
} \
} while(0)
LogActions(resource_t * rsc, pe_working_set_t * data_set, gboolean terminal)
{
node_t *next = NULL;
node_t *current = NULL;
action_t *stop = NULL;
action_t *start = NULL;
action_t *demote = NULL;
action_t *promote = NULL;
char *key = NULL;
gboolean moving = FALSE;
GListPtr possible_matches = NULL;
if (rsc->children) {
GListPtr gIter = NULL;
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
LogActions(child_rsc, data_set, terminal);
}
return;
}
next = rsc->allocated_to;
if (rsc->running_on) {
if (g_list_length(rsc->running_on) > 1 && rsc->partial_migration_source) {
current = rsc->partial_migration_source;
} else {
current = rsc->running_on->data;
}
if (rsc->role == RSC_ROLE_STOPPED) {
/*
* This can occur when resources are being recovered
* We fiddle with the current role in native_create_actions()
*/
rsc->role = RSC_ROLE_STARTED;
}
}
if (current == NULL && is_set(rsc->flags, pe_rsc_orphan)) {
/* Don't log stopped orphans */
return;
}
if (is_not_set(rsc->flags, pe_rsc_managed)
|| (current == NULL && next == NULL)) {
crm_info("Leave %s\t(%s%s)",
rsc->id, role2text(rsc->role), is_not_set(rsc->flags,
pe_rsc_managed) ? " unmanaged" : "");
return;
}
if (current != NULL && next != NULL && safe_str_neq(current->details->id, next->details->id)) {
moving = TRUE;
}
key = start_key(rsc);
possible_matches = find_actions(rsc->actions, key, next);
free(key);
if (possible_matches) {
start = possible_matches->data;
g_list_free(possible_matches);
}
key = stop_key(rsc);
possible_matches = find_actions(rsc->actions, key, next);
free(key);
if (possible_matches) {
stop = possible_matches->data;
g_list_free(possible_matches);
}
key = promote_key(rsc);
possible_matches = find_actions(rsc->actions, key, next);
free(key);
if (possible_matches) {
promote = possible_matches->data;
g_list_free(possible_matches);
}
key = demote_key(rsc);
possible_matches = find_actions(rsc->actions, key, next);
free(key);
if (possible_matches) {
demote = possible_matches->data;
g_list_free(possible_matches);
}
if (rsc->role == rsc->next_role) {
key = generate_op_key(rsc->id, RSC_MIGRATED, 0);
possible_matches = find_actions(rsc->actions, key, next);
free(key);
CRM_CHECK(next != NULL,);
if (next == NULL) {
} else if (possible_matches && current) {
log_change("Migrate %s\t(%s %s -> %s)",
rsc->id, role2text(rsc->role), current->details->uname,
next->details->uname);
g_list_free(possible_matches);
} else if(is_set(rsc->flags, pe_rsc_reload)) {
log_change("Reload %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else if (start == NULL || is_set(start->flags, pe_action_optional)) {
crm_info("Leave %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else if (moving && current) {
log_change("Move %s\t(%s %s -> %s)",
rsc->id, role2text(rsc->role), current->details->uname,
next->details->uname);
} else if (is_set(rsc->flags, pe_rsc_failed)) {
log_change("Recover %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else if (start && is_set(start->flags, pe_action_runnable) == FALSE) {
log_change("Stop %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else {
log_change("Restart %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
}
return;
}
if (rsc->role > RSC_ROLE_SLAVE && rsc->role > rsc->next_role) {
CRM_CHECK(current != NULL,);
if (current != NULL) {
gboolean allowed = FALSE;
if (demote != NULL && (demote->flags & pe_action_runnable)) {
allowed = TRUE;
}
log_change("Demote %s\t(%s -> %s %s%s)",
rsc->id,
role2text(rsc->role),
role2text(rsc->next_role),
current->details->uname,
allowed ? "" : " - blocked");
if (stop != NULL && is_not_set(stop->flags, pe_action_optional)
&& rsc->next_role > RSC_ROLE_STOPPED) {
if (is_set(rsc->flags, pe_rsc_failed)) {
log_change("Recover %s\t(%s %s)",
rsc->id, role2text(rsc->role), next->details->uname);
} else if(is_set(rsc->flags, pe_rsc_reload)) {
log_change("Reload %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else {
log_change("Restart %s\t(%s %s)",
rsc->id, role2text(rsc->role), next->details->uname);
}
}
}
} else if (rsc->next_role == RSC_ROLE_STOPPED) {
GListPtr gIter = NULL;
CRM_CHECK(current != NULL,);
for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
log_change("Stop %s\t(%s)", rsc->id, node->details->uname);
}
}
if (moving) {
log_change("Move %s\t(%s %s -> %s)",
rsc->id, role2text(rsc->next_role), current->details->uname,
next->details->uname);
}
if (rsc->role == RSC_ROLE_STOPPED) {
gboolean allowed = FALSE;
if(start && (start->flags & pe_action_runnable)) {
allowed = TRUE;
}
CRM_CHECK(next != NULL,);
if (next != NULL) {
log_change("Start %s\t(%s%s)", rsc->id, next->details->uname, allowed?"":" - blocked");
}
if(allowed == FALSE) {
return;
}
}
if (rsc->next_role > RSC_ROLE_SLAVE && rsc->role < rsc->next_role) {
gboolean allowed = FALSE;
CRM_CHECK(next != NULL,);
if (stop != NULL && is_not_set(stop->flags, pe_action_optional)
&& rsc->role > RSC_ROLE_STOPPED) {
if (is_set(rsc->flags, pe_rsc_failed)) {
log_change("Recover %s\t(%s %s)",
rsc->id, role2text(rsc->role), next->details->uname);
} else if(is_set(rsc->flags, pe_rsc_reload)) {
log_change("Reload %s\t(%s %s)", rsc->id, role2text(rsc->role), next->details->uname);
} else {
log_change("Restart %s\t(%s %s)",
rsc->id, role2text(rsc->role), next->details->uname);
}
}
if (promote && (promote->flags & pe_action_runnable)) {
allowed = TRUE;
}
log_change("Promote %s\t(%s -> %s %s%s)",
rsc->id,
role2text(rsc->role),
role2text(rsc->next_role),
next->details->uname,
allowed ? "" : " - blocked");
}
}
gboolean
StopRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
crm_trace("%s", rsc->id);
if (rsc->next_role == RSC_ROLE_STOPPED
&& rsc->variant == pe_native && safe_str_eq(class, "stonith")) {
action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);
custom_action_order(NULL, strdup(all_stopped->task), all_stopped,
rsc, stop_key(rsc), NULL,
pe_order_optional | pe_order_stonith_stop, data_set);
}
for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
node_t *current = (node_t *) gIter->data;
action_t *stop;
if (rsc->partial_migration_target) {
if(rsc->partial_migration_target->details == current->details) {
crm_trace("Filtered %s -> %s %s", current->details->uname, next->details->uname, rsc->id);
continue;
} else {
crm_trace("Forced on %s %s", current->details->uname, rsc->id);
optional = FALSE;
}
}
crm_trace("%s on %s", rsc->id, current->details->uname);
stop = stop_action(rsc, current, optional);
if(is_not_set(rsc->flags, pe_rsc_managed)) {
update_action_flags(stop, pe_action_runnable|pe_action_clear);
}
if (is_set(data_set->flags, pe_flag_remove_after_stop)) {
DeleteRsc(rsc, current, optional, data_set);
}
}
return TRUE;
}
gboolean
StartRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
action_t *start = NULL;
crm_trace("%s on %s %d", rsc->id, next?next->details->uname:"N/A", optional);
start = start_action(rsc, next, TRUE);
if (is_set(start->flags, pe_action_runnable) && optional == FALSE) {
update_action_flags(start, pe_action_optional | pe_action_clear);
}
return TRUE;
}
gboolean
PromoteRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
char *key = NULL;
GListPtr gIter = NULL;
gboolean runnable = TRUE;
GListPtr action_list = NULL;
crm_trace("%s on %s", rsc->id, next?next->details->uname:"N/A");
CRM_CHECK(next != NULL, return FALSE);
key = start_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
free(key);
for (gIter = action_list; gIter != NULL; gIter = gIter->next) {
action_t *start = (action_t *) gIter->data;
if (is_set(start->flags, pe_action_runnable) == FALSE) {
runnable = FALSE;
}
}
g_list_free(action_list);
if (runnable) {
promote_action(rsc, next, optional);
return TRUE;
}
crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id);
key = promote_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
free(key);
for (gIter = action_list; gIter != NULL; gIter = gIter->next) {
action_t *promote = (action_t *) gIter->data;
update_action_flags(promote, pe_action_runnable | pe_action_clear);
}
g_list_free(action_list);
return TRUE;
}
gboolean
DemoteRsc(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
crm_trace("%s", rsc->id);
/* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */
for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
node_t *current = (node_t *) gIter->data;
crm_trace("%s on %s", rsc->id, next?next->details->uname:"N/A");
demote_action(rsc, current, optional);
}
return TRUE;
}
gboolean
RoleError(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
crm_err("%s on %s", rsc->id, next?next->details->uname:"N/A");
CRM_CHECK(FALSE, return FALSE);
return FALSE;
}
gboolean
NullOp(resource_t * rsc, node_t * next, gboolean optional, pe_working_set_t * data_set)
{
crm_trace("%s", rsc->id);
return FALSE;
}
gboolean
DeleteRsc(resource_t * rsc, node_t * node, gboolean optional, pe_working_set_t * data_set)
{
action_t *delete = NULL;
#if DELETE_THEN_REFRESH
action_t *refresh = NULL;
#endif
if (is_set(rsc->flags, pe_rsc_failed)) {
crm_trace("Resource %s not deleted from %s: failed", rsc->id, node->details->uname);
return FALSE;
} else if (node == NULL) {
crm_trace("Resource %s not deleted: NULL node", rsc->id);
return FALSE;
} else if (node->details->unclean || node->details->online == FALSE) {
crm_trace("Resource %s not deleted from %s: unrunnable", rsc->id, node->details->uname);
return FALSE;
}
crm_notice("Removing %s from %s", rsc->id, node->details->uname);
delete = delete_action(rsc, node, optional);
new_rsc_order(rsc, RSC_STOP, rsc, RSC_DELETE,
optional ? pe_order_implies_then : pe_order_optional, data_set);
new_rsc_order(rsc, RSC_DELETE, rsc, RSC_START,
optional ? pe_order_implies_then : pe_order_optional, data_set);
#if DELETE_THEN_REFRESH
refresh = custom_action(NULL, strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH,
node, FALSE, TRUE, data_set);
add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
order_actions(delete, refresh, pe_order_optional);
#endif
return TRUE;
}
#include <../lib/pengine/unpack.h>
#define set_char(x) last_rsc_id[lpc] = x; complete = TRUE;
static char *
increment_clone(char *last_rsc_id)
{
int lpc = 0;
int len = 0;
char *tmp = NULL;
gboolean complete = FALSE;
CRM_CHECK(last_rsc_id != NULL, return NULL);
if (last_rsc_id != NULL) {
len = strlen(last_rsc_id);
}
lpc = len - 1;
while (complete == FALSE && lpc > 0) {
switch (last_rsc_id[lpc]) {
case 0:
lpc--;
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[lpc] = '0';
lpc--;
break;
case ':':
tmp = last_rsc_id;
last_rsc_id = calloc(1, len + 2);
memcpy(last_rsc_id, tmp, len);
last_rsc_id[++lpc] = '1';
last_rsc_id[len] = '0';
last_rsc_id[len + 1] = 0;
complete = TRUE;
free(tmp);
break;
default:
crm_err("Unexpected char: %c (%d)", last_rsc_id[lpc], lpc);
return NULL;
break;
}
}
return last_rsc_id;
}
static node_t *
probe_grouped_clone(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
{
node_t *running = NULL;
resource_t *top = uber_parent(rsc);
if (running == NULL && is_set(top->flags, pe_rsc_unique) == FALSE) {
/* Annoyingly we also need to check any other clone instances
* Clumsy, but it will work.
*
* An alternative would be to update known_on for every peer
* during process_rsc_state()
*
* This code desperately needs optimization
* ptest -x with 100 nodes, 100 clones and clone-max=10:
* No probes O(25s)
* Detection without clone loop O(3m)
* Detection with clone loop O(8m)
ptest[32211]: 2010/02/18_14:27:55 CRIT: stage5: Probing for unknown resources
ptest[32211]: 2010/02/18_14:33:39 CRIT: stage5: Done
ptest[32211]: 2010/02/18_14:35:05 CRIT: stage7: Updating action states
ptest[32211]: 2010/02/18_14:35:05 CRIT: stage7: Done
*/
char *clone_id = clone_zero(rsc->id);
resource_t *peer = pe_find_resource(top->children, clone_id);
while (peer && running == NULL) {
running = pe_hash_table_lookup(peer->known_on, node->details->id);
if (running != NULL) {
/* we already know the status of the resource on this node */
crm_trace("Skipping active clone: %s", rsc->id);
free(clone_id);
return running;
}
clone_id = increment_clone(clone_id);
peer = pe_find_resource(data_set->resources, clone_id);
}
free(clone_id);
}
return running;
}
gboolean
native_create_probe(resource_t * rsc, node_t * node, action_t * complete,
gboolean force, pe_working_set_t * data_set)
{
char *key = NULL;
action_t *probe = NULL;
node_t *running = NULL;
resource_t *top = uber_parent(rsc);
static const char *rc_master = NULL;
static const char *rc_inactive = NULL;
if (rc_inactive == NULL) {
rc_inactive = crm_itoa(PCMK_EXECRA_NOT_RUNNING);
rc_master = crm_itoa(PCMK_EXECRA_RUNNING_MASTER);
}
CRM_CHECK(node != NULL, return FALSE);
if (force == FALSE && is_not_set(data_set->flags, pe_flag_startup_probes)) {
crm_trace("Skipping active resource detection for %s", rsc->id);
return FALSE;
}
if (rsc->children) {
GListPtr gIter = NULL;
gboolean any_created = FALSE;
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
any_created = child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set)
|| any_created;
}
return any_created;
}
if (is_set(rsc->flags, pe_rsc_orphan)) {
crm_trace("Skipping orphan: %s", rsc->id);
return FALSE;
}
running = g_hash_table_lookup(rsc->known_on, node->details->id);
if (running == NULL && is_set(rsc->flags, pe_rsc_unique) == FALSE) {
/* Anonymous clones */
if (rsc->parent == top) {
running = g_hash_table_lookup(rsc->parent->known_on, node->details->id);
} else {
/* Grouped anonymous clones need extra special handling */
running = probe_grouped_clone(rsc, node, data_set);
}
}
if (force == FALSE && running != NULL) {
/* we already know the status of the resource on this node */
crm_trace("Skipping active: %s", rsc->id);
return FALSE;
}
key = generate_op_key(rsc->id, RSC_STATUS, 0);
probe = custom_action(rsc, key, RSC_STATUS, node, FALSE, TRUE, data_set);
update_action_flags(probe, pe_action_optional | pe_action_clear);
/*
* We need to know if it's running_on (not just known_on) this node
* to correctly determine the target rc.
*/
running = pe_find_node_id(rsc->running_on, node->details->id);
if (running == NULL) {
add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_inactive);
} else if (rsc->role == RSC_ROLE_MASTER) {
add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, rc_master);
}
crm_debug("Probing %s on %s (%s)", rsc->id, node->details->uname, role2text(rsc->role));
order_actions(probe, complete, pe_order_implies_then);
return TRUE;
}
static void
native_start_constraints(resource_t * rsc, action_t * stonith_op, gboolean is_stonith,
pe_working_set_t * data_set)
{
node_t *target = stonith_op ? stonith_op->node : NULL;
if (is_stonith) {
char *key = start_key(rsc);
action_t *ready = get_pseudo_op(STONITH_UP, data_set);
crm_trace("Ordering %s action before stonith events", key);
custom_action_order(rsc, key, NULL,
NULL, strdup(ready->task), ready,
pe_order_optional | pe_order_implies_then, data_set);
} else {
GListPtr gIter = NULL;
action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);
action_t *stonith_done = get_pseudo_op(STONITH_DONE, data_set);
for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (action->needs == rsc_req_stonith) {
order_actions(stonith_done, action, pe_order_optional);
} else if (target != NULL && safe_str_eq(action->task, RSC_START)
&& NULL == pe_hash_table_lookup(rsc->known_on, target->details->id)) {
/* if known == NULL, then we dont know if
* the resource is active on the node
* we're about to shoot
*
* in this case, regardless of action->needs,
* the only safe option is to wait until
* the node is shot before doing anything
* to with the resource
*
* its analogous to waiting for all the probes
* for rscX to complete before starting rscX
*
* the most likely explaination is that the
* DC died and took its status with it
*/
crm_debug("Ordering %s after %s recovery", action->uuid, target->details->uname);
order_actions(all_stopped, action, pe_order_optional | pe_order_runnable_left);
}
}
}
}
static void
native_stop_constraints(resource_t * rsc, action_t * stonith_op, gboolean is_stonith,
pe_working_set_t * data_set)
{
char *key = NULL;
GListPtr gIter = NULL;
GListPtr action_list = NULL;
resource_t *top = uber_parent(rsc);
key = stop_key(rsc);
action_list = find_actions(rsc->actions, key, stonith_op->node);
free(key);
/* add the stonith OP as a stop pre-req and the mark the stop
* as a pseudo op - since its now redundant
*/
for (gIter = action_list; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (action->node->details->online
&& action->node->details->unclean == FALSE && is_set(rsc->flags, pe_rsc_failed)) {
continue;
}
if (is_set(rsc->flags, pe_rsc_failed)) {
crm_notice("Stop of failed resource %s is"
" implicit after %s is fenced", rsc->id, action->node->details->uname);
} else {
crm_info("%s is implicit after %s is fenced",
action->uuid, action->node->details->uname);
}
/* the stop would never complete and is
* now implied by the stonith operation
*/
update_action_flags(action, pe_action_pseudo);
update_action_flags(action, pe_action_runnable);
update_action_flags(action, pe_action_implied_by_stonith);
if (is_stonith == FALSE) {
action_t *parent_stop = find_first_action(top->actions, NULL, RSC_STOP, NULL);
order_actions(stonith_op, action, pe_order_optional);
order_actions(stonith_op, parent_stop, pe_order_optional);
}
if (is_set(rsc->flags, pe_rsc_notify)) {
/* Create a second notification that will be delivered
* immediately after the node is fenced
*
* Basic problem:
* - C is a clone active on the node to be shot and stopping on another
* - R is a resource that depends on C
*
* + C.stop depends on R.stop
* + C.stopped depends on STONITH
* + C.notify depends on C.stopped
* + C.healthy depends on C.notify
* + R.stop depends on C.healthy
*
* The extra notification here changes
* + C.healthy depends on C.notify
* into:
* + C.healthy depends on C.notify'
* + C.notify' depends on STONITH'
* thus breaking the loop
*/
notify_data_t *n_data =
create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op, data_set);
crm_info("Creating secondary notification for %s", action->uuid);
collect_notification_data(rsc, TRUE, FALSE, n_data);
g_hash_table_insert(n_data->keys, strdup("notify_stop_resource"),
strdup(rsc->id));
g_hash_table_insert(n_data->keys, strdup("notify_stop_uname"),
strdup(action->node->details->uname));
create_notifications(uber_parent(rsc), n_data, data_set);
free_notification_data(n_data);
}
/* From Bug #1601, successful fencing must be an input to a failed resources stop action.
However given group(rA, rB) running on nodeX and B.stop has failed,
A := stop healthy resource (rA.stop)
B := stop failed resource (pseudo operation B.stop)
C := stonith nodeX
A requires B, B requires C, C requires A
This loop would prevent the cluster from making progress.
This block creates the "C requires A" dependency and therefore must (at least
for now) be disabled.
Instead, run the block above and treat all resources on nodeX as B would be
(marked as a pseudo op depending on the STONITH).
TODO: Break the "A requires B" dependency in update_action() and re-enable this block
} else if(is_stonith == FALSE) {
crm_info("Moving healthy resource %s"
" off %s before fencing",
rsc->id, node->details->uname);
* stop healthy resources before the
* stonith op
*
custom_action_order(
rsc, stop_key(rsc), NULL,
NULL,strdup(CRM_OP_FENCE),stonith_op,
pe_order_optional, data_set);
*/
}
g_list_free(action_list);
key = demote_key(rsc);
action_list = find_actions(rsc->actions, key, stonith_op->node);
free(key);
for (gIter = action_list; gIter != NULL; gIter = gIter->next) {
action_t *action = (action_t *) gIter->data;
if (action->node->details->online == FALSE || action->node->details->unclean == TRUE
|| is_set(rsc->flags, pe_rsc_failed)) {
if (is_set(rsc->flags, pe_rsc_failed)) {
crm_info("Demote of failed resource %s is"
" implict after %s is fenced", rsc->id, action->node->details->uname);
} else {
crm_info("%s is implicit after %s is fenced",
action->uuid, action->node->details->uname);
}
/* the stop would never complete and is
* now implied by the stonith operation
*/
crm_trace("here - 1");
update_action_flags(action, pe_action_pseudo);
update_action_flags(action, pe_action_runnable);
if (is_stonith == FALSE) {
order_actions(stonith_op, action, pe_order_optional);
}
}
}
g_list_free(action_list);
}
void
rsc_stonith_ordering(resource_t * rsc, action_t * stonith_op, pe_working_set_t * data_set)
{
gboolean is_stonith = FALSE;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
if (rsc->children) {
GListPtr gIter = NULL;
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
rsc_stonith_ordering(child_rsc, stonith_op, data_set);
}
return;
}
if (is_not_set(rsc->flags, pe_rsc_managed)) {
crm_trace("Skipping fencing constraints for unmanaged resource: %s", rsc->id);
return;
}
if (stonith_op != NULL && safe_str_eq(class, "stonith")) {
is_stonith = TRUE;
}
/* Start constraints */
native_start_constraints(rsc, stonith_op, is_stonith, data_set);
/* Stop constraints */
native_stop_constraints(rsc, stonith_op, is_stonith, data_set);
}
enum stack_activity {
stack_stable = 0,
stack_starting = 1,
stack_stopping = 2,
stack_middle = 4,
};
static enum stack_activity
find_clone_activity_on(resource_t * rsc, resource_t * target, node_t * node, const char *type)
{
int mode = stack_stable;
action_t *active = NULL;
if (target->children) {
GListPtr gIter = NULL;
for (gIter = target->children; gIter != NULL; gIter = gIter->next) {
resource_t *child = (resource_t *) gIter->data;
mode |= find_clone_activity_on(rsc, child, node, type);
}
return mode;
}
active = find_first_action(target->actions, NULL, RSC_START, NULL);
if (active && is_set(active->flags, pe_action_optional) == FALSE
&& is_set(active->flags, pe_action_pseudo) == FALSE) {
crm_debug("%s: found scheduled %s action (%s)", rsc->id, active->uuid, type);
mode |= stack_starting;
}
active = find_first_action(target->actions, NULL, RSC_STOP, node);
if (active && is_set(active->flags, pe_action_optional) == FALSE
&& is_set(active->flags, pe_action_pseudo) == FALSE) {
crm_debug("%s: found scheduled %s action (%s)", rsc->id, active->uuid, type);
mode |= stack_stopping;
}
return mode;
}
static enum stack_activity
check_stack_element(resource_t * rsc, resource_t * other_rsc, const char *type)
{
resource_t *other_p = uber_parent(other_rsc);
if (other_rsc == NULL || other_rsc == rsc) {
return stack_stable;
} else if (other_p->variant == pe_native) {
crm_notice("Cannot migrate %s due to dependency on %s (%s)", rsc->id, other_rsc->id, type);
return stack_middle;
} else if (other_rsc == rsc->parent) {
int mode = 0;
GListPtr gIter = NULL;
for (gIter = other_rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
if (constraint->score > 0) {
mode |= check_stack_element(rsc, constraint->rsc_rh, type);
}
}
return mode;
} else if (other_p->variant == pe_group) {
crm_notice("Cannot migrate %s due to dependency on group %s (%s)",
rsc->id, other_rsc->id, type);
return stack_middle;
}
/* else: >= clone */
/*
## Assumption
A depends on clone(B)
## Resource Activity During Move
N1 N2 N3
--- --- ---
t0 A.stop
t1 B.stop B.stop
t2 B.start B.start
t3 A.start
## Resource Activity During Migration
N1 N2 N3
--- --- ---
t0 B.start B.start
t1 A.stop (1)
t2 A.start (2)
t3 B.stop B.stop
Node 1: Rewritten to be a migrate-to operation
Node 2: Rewritten to be a migrate-from operation
# Constraints
The following constraints already exist in the system.
The 'ok' and 'fail' column refers to whether they still hold for migration.
a) A.stop -> A.start - ok
b) B.stop -> B.start - fail
c) A.stop -> B.stop - ok
d) B.start -> A.start - ok
e) B.stop -> A.start - fail
f) A.stop -> B.start - fail
## Scenarios
B unchanged - ok
B stopping only - fail - possible after fixing 'e'
B starting only - fail - possible after fixing 'f'
B stoping and starting - fail - constraint 'b' is unfixable
B restarting only on N2 - fail - as-per previous only rarer
*/
/* Only allow migration when the clone is either stable, only starting or only stopping */
return find_clone_activity_on(rsc, other_rsc, NULL, type);
}
static gboolean
at_stack_bottom(resource_t * rsc)
{
char *key = NULL;
action_t *start = NULL;
action_t *other = NULL;
int mode = stack_stable;
GListPtr action_list = NULL;
GListPtr gIter = NULL;
key = start_key(rsc);
action_list = find_actions(rsc->actions, key, NULL);
free(key);
crm_trace("%s: processing", rsc->id);
CRM_CHECK(action_list != NULL, return FALSE);
start = action_list->data;
g_list_free(action_list);
for (gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
resource_t *target = constraint->rsc_rh;
crm_trace("Checking %s: %s == %s (%d)", constraint->id, rsc->id, target->id,
constraint->score);
if (constraint->score > 0) {
mode |= check_stack_element(rsc, target, "coloc");
if (mode & stack_middle) {
return FALSE;
} else if ((mode & stack_stopping) && (mode & stack_starting)) {
crm_notice("Cannot migrate %s due to colocation activity (last was %s)",
rsc->id, target->id);
return FALSE;
}
}
}
for (gIter = start->actions_before; gIter != NULL; gIter = gIter->next) {
action_wrapper_t *other_w = (action_wrapper_t *) gIter->data;
other = other_w->action;
if (other_w->type & pe_order_serialize_only) {
crm_trace("%s: depends on %s (serialize ordering)", rsc->id, other->uuid);
continue;
}
crm_trace("%s: Checking %s ordering", rsc->id, other->uuid);
if (is_set(other->flags, pe_action_optional) == FALSE) {
mode |= check_stack_element(rsc, other->rsc, "order");
if (mode & stack_middle) {
return FALSE;
} else if ((mode & stack_stopping) && (mode & stack_starting)) {
crm_notice("Cannot migrate %s due to ordering activity (last was %s)",
rsc->id, other->rsc->id);
return FALSE;
}
}
}
return TRUE;
}
static action_t *
get_first_named_action(resource_t *rsc, const char *action, gboolean only_valid, node_t *current)
{
action_t *a = NULL;
GListPtr action_list = NULL;
char *key = generate_op_key(rsc->id, action, 0);
action_list = find_actions(rsc->actions, key, current);
if (action_list == NULL || action_list->data == NULL) {
crm_trace("%s: no %s action", rsc->id, action);
free(key);
return NULL;
}
a = action_list->data;
g_list_free(action_list);
if(only_valid && is_set(a->flags, pe_action_pseudo)) {
crm_trace("%s: pseudo", key);
a = NULL;
} else if(only_valid && is_not_set(a->flags, pe_action_runnable)) {
crm_trace("%s: runnable", key);
a = NULL;
}
free(key);
return a;
}
static void
MigrateRsc(resource_t * rsc, action_t *stop, action_t *start, pe_working_set_t * data_set, gboolean partial)
{
action_t *to = NULL;
action_t *from = NULL;
action_t *then = NULL;
action_t *other = NULL;
action_t *done = get_pseudo_op(STONITH_DONE, data_set);
GListPtr gIter = NULL;
const char *value = g_hash_table_lookup(rsc->meta, XML_OP_ATTR_ALLOW_MIGRATE);
crm_trace("%s %s -> %s", rsc->id, stop->node->details->uname, start->node->details->uname);
if (crm_is_true(value) == FALSE) {
return;
}
if (rsc->next_role > RSC_ROLE_SLAVE) {
crm_trace("%s: resource role: role=%s", rsc->id, role2text(rsc->next_role));
return;
}
if(start == NULL || stop == NULL) {
crm_trace("%s: not exists %p -> %p", rsc->id, stop, start);
return;
} else if (start->node == NULL || stop->node == NULL) {
crm_trace("%s: no node %p -> %p", rsc->id, stop->node, start->node);
return;
} else if(is_set(stop->flags, pe_action_optional)) {
crm_trace("%s: stop action", rsc->id);
return;
} else if(is_set(start->flags, pe_action_optional)) {
crm_trace("%s: start action", rsc->id);
return;
} else if (stop->node->details == start->node->details) {
crm_trace("%s: not moving %p -> %p", rsc->id, stop->node, start->node);
return;
} else if (at_stack_bottom(rsc) == FALSE) {
crm_trace("%s: not at stack bottom", rsc->id);
return;
}
if (partial) {
crm_info("Completing partial migration of %s from %s to %s", rsc->id,
stop->node ? stop->node->details->uname : "unknown",
start->node ? start->node->details->uname : "unknown");
} else {
crm_info("Migrating %s from %s to %s", rsc->id,
stop->node ? stop->node->details->uname : "unknown",
start->node ? start->node->details->uname : "unknown");
}
/* Preserve the stop to ensure the end state is sane on that node,
* Make the start a pseudo op
* Create migrate_to, have it depend on everything the stop did
* Create migrate_from
* *-> migrate_to -> migrate_from -> stop -> start
*/
update_action_flags(start, pe_action_pseudo); /* easier than trying to delete it from the graph
* but perhaps we should have it run anyway
*/
if (!partial) {
to = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATE, 0), RSC_MIGRATE, stop->node,
FALSE, TRUE, data_set);
}
from = custom_action(rsc, generate_op_key(rsc->id, RSC_MIGRATED, 0), RSC_MIGRATED, start->node,
FALSE, TRUE, data_set);
/* This is slightly sub-optimal if 'to' fails, but always
* run both halves of the migration before terminating the
* transition.
*
* This can be removed if/when we update unpack_rsc_op() to
* 'correctly' handle partial migrations.
*
* Without this, we end up stopping both sides
*/
from->priority = INFINITY;
if (!partial) {
order_actions(to, from, pe_order_optional);
add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->uname);
add_hash_param(to->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->uname);
}
then = to ? to : from;
order_actions(from, stop, pe_order_optional);
order_actions(done, then, pe_order_optional);
add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_SOURCE, stop->node->details->uname);
add_hash_param(from->meta, XML_LRM_ATTR_MIGRATE_TARGET, start->node->details->uname);
/* Create the correct ordering ajustments based on find_clone_activity_on(); */
for (gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
resource_t *target = constraint->rsc_rh;
crm_info("Repairing %s: %s == %s (%d)", constraint->id, rsc->id, target->id,
constraint->score);
if (constraint->score > 0) {
int mode = check_stack_element(rsc, target, "coloc");
action_t *clone_stop = find_first_action(target->actions, NULL, RSC_STOP, NULL);
action_t *clone_start = find_first_action(target->actions, NULL, RSC_STARTED, NULL);
CRM_ASSERT(clone_stop != NULL);
CRM_ASSERT(clone_start != NULL);
CRM_ASSERT((mode & stack_middle) == 0);
CRM_ASSERT(((mode & stack_stopping) && (mode & stack_starting)) == 0);
if (mode & stack_stopping) {
#if 0
crm_debug("Creating %s.start -> %s.stop ordering", rsc->id, target->id);
order_actions(from, clone_stop, pe_order_optional);
#endif
GListPtr lpc2 = NULL;
for (lpc2 = start->actions_before; lpc2 != NULL; lpc2 = lpc2->next) {
action_wrapper_t *other_w = (action_wrapper_t *) lpc2->data;
/* Needed if the clone's started pseudo-action ever gets printed in the graph */
if (other_w->action == clone_start) {
crm_debug("Breaking %s -> %s ordering", other_w->action->uuid,
start->uuid);
other_w->type = pe_order_none;
}
}
} else if (mode & stack_starting) {
#if 0
crm_debug("Creating %s.started -> %s.stop ordering", target->id, rsc->id);
order_actions(clone_start, to, pe_order_optional);
#endif
GListPtr lpc2 = NULL;
for (lpc2 = clone_stop->actions_before; lpc2 != NULL; lpc2 = lpc2->next) {
action_wrapper_t *other_w = (action_wrapper_t *) lpc2->data;
/* Needed if the clone's stop pseudo-action ever gets printed in the graph */
if (other_w->action == stop) {
crm_debug("Breaking %s -> %s ordering", other_w->action->uuid,
clone_stop->uuid);
other_w->type = pe_order_none;
}
}
}
}
}
#if 0
/* Implied now that start/stop are not morphed into migrate ops */
/* Anything that needed stop to complete, now also needs start to have completed */
for (gIter = stop->actions_after; gIter != NULL; gIter = gIter->next) {
action_wrapper_t *other_w = (action_wrapper_t *) gIter->data;
other = other_w->action;
if (is_set(other->flags, pe_action_optional) || other->rsc != NULL) {
continue;
}
crm_debug("Ordering %s before %s (stop)", from->uuid, other->uuid);
order_actions(from, other, other_w->type);
}
#endif
/* migrate 'then' action also needs anything that the stop needed to have completed too */
for (gIter = stop->actions_before; gIter != NULL; gIter = gIter->next) {
action_wrapper_t *other_w = (action_wrapper_t *) gIter->data;
other = other_w->action;
if (other->rsc == NULL) {
/* nothing */
} else if (is_set(other->flags, pe_action_optional) || other->rsc == rsc
|| other->rsc == rsc->parent) {
continue;
}
crm_debug("Ordering %s before %s (stop)", other_w->action->uuid, stop->uuid);
order_actions(other, then, other_w->type);
}
/* migrate 'then' action also needs anything that the start needed to have completed too */
for (gIter = start->actions_before; gIter != NULL; gIter = gIter->next) {
action_wrapper_t *other_w = (action_wrapper_t *) gIter->data;
other = other_w->action;
if (other->rsc == NULL) {
/* nothing */
} else if (is_set(other->flags, pe_action_optional) || other->rsc == rsc
|| other->rsc == rsc->parent) {
continue;
}
crm_debug("Ordering %s before %s (start)", other_w->action->uuid, stop->uuid);
order_actions(other, then, other_w->type);
}
}
static void
ReloadRsc(resource_t * rsc, action_t *stop, action_t *start, pe_working_set_t * data_set)
{
action_t *action = NULL;
action_t *rewrite = NULL;
if(is_not_set(rsc->flags, pe_rsc_try_reload)) {
return;
} else if(is_not_set(stop->flags, pe_action_optional)) {
crm_trace("%s: stop action", rsc->id);
return;
} else if(is_not_set(start->flags, pe_action_optional)) {
crm_trace("%s: start action", rsc->id);
return;
}
crm_trace("%s on %s", rsc->id, stop->node->details->uname);
action = get_first_named_action(rsc, RSC_PROMOTE, TRUE, NULL);
if (action && is_set(action->flags, pe_action_optional) == FALSE) {
update_action_flags(action, pe_action_pseudo);
}
action = get_first_named_action(rsc, RSC_DEMOTE, TRUE, NULL);
if (action && is_set(action->flags, pe_action_optional) == FALSE) {
rewrite = action;
update_action_flags(stop, pe_action_pseudo);
} else {
rewrite = start;
}
crm_info("Rewriting %s of %s on %s as a reload",
rewrite->task, rsc->id, stop->node->details->uname);
set_bit(rsc->flags, pe_rsc_reload);
update_action_flags(rewrite, pe_action_optional|pe_action_clear);
free(rewrite->uuid);
free(rewrite->task);
rewrite->task = strdup("reload");
rewrite->uuid = generate_op_key(rsc->id, rewrite->task, 0);
}
void
rsc_migrate_reload(resource_t * rsc, pe_working_set_t * data_set)
{
GListPtr gIter = NULL;
action_t *stop = NULL;
action_t *start = NULL;
gboolean partial = FALSE;
if (rsc->children) {
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
resource_t *child_rsc = (resource_t *) gIter->data;
rsc_migrate_reload(child_rsc, data_set);
}
return;
} else if (rsc->variant > pe_native) {
return;
}
crm_trace("Processing %s", rsc->id);
if (rsc->partial_migration_target) {
start = get_first_named_action(rsc, RSC_START, TRUE, rsc->partial_migration_target);
stop = get_first_named_action(rsc, RSC_STOP, TRUE, rsc->partial_migration_source);
if (start && stop) {
partial = TRUE;
}
}
crm_trace("%s %s %p", rsc->id, partial?"partial":"full", stop);
if (!partial) {
stop = get_first_named_action(rsc, RSC_STOP, TRUE, rsc->running_on ? rsc->running_on->data : NULL);
start = get_first_named_action(rsc, RSC_START, TRUE, NULL);
}
if (is_not_set(rsc->flags, pe_rsc_managed)
|| is_set(rsc->flags, pe_rsc_failed)
|| is_set(rsc->flags, pe_rsc_start_pending)
|| rsc->next_role < RSC_ROLE_STARTED
|| ((g_list_length(rsc->running_on) != 1) && !partial)) {
crm_trace("%s: general resource state: flags=0x%.16llx", rsc->id, rsc->flags);
return;
}
if(stop == NULL) {
return;
} else if (is_set(stop->flags, pe_action_optional) && is_set(rsc->flags, pe_rsc_try_reload)) {
ReloadRsc(rsc, stop, start, data_set);
} else if(is_not_set(stop->flags, pe_action_optional)) {
MigrateRsc(rsc, stop, start, data_set, partial);
}
}
void
native_append_meta(resource_t * rsc, xmlNode * xml)
{
char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION);
if (value) {
char *name = NULL;
name = crm_meta_name(XML_RSC_ATTR_INCARNATION);
crm_xml_add(xml, name, value);
free(name);
}
}
diff --git a/pengine/regression.sh b/pengine/regression.sh
index f6d7d1c813..e0cbdd3034 100755
--- a/pengine/regression.sh
+++ b/pengine/regression.sh
@@ -1,653 +1,656 @@
#!/bin/bash
# Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
core=`dirname $0`
. $core/regression.core.sh
create_mode="true"
info Generating test outputs for these tests...
# do_test file description
info Done.
echo ""
info Performing the following tests from $io_dir
create_mode="false"
echo ""
do_test simple1 "Offline "
do_test simple2 "Start "
do_test simple3 "Start 2 "
do_test simple4 "Start Failed"
do_test simple6 "Stop Start "
do_test simple7 "Shutdown "
#do_test simple8 "Stonith "
#do_test simple9 "Lower version"
#do_test simple10 "Higher version"
do_test simple11 "Priority (ne)"
do_test simple12 "Priority (eq)"
do_test simple8 "Stickiness"
echo ""
do_test group1 "Group "
do_test group2 "Group + Native "
do_test group3 "Group + Group "
do_test group4 "Group + Native (nothing)"
do_test group5 "Group + Native (move) "
do_test group6 "Group + Group (move) "
do_test group7 "Group colocation"
do_test group13 "Group colocation (cant run)"
do_test group8 "Group anti-colocation"
do_test group9 "Group recovery"
do_test group10 "Group partial recovery"
do_test group11 "Group target_role"
do_test group14 "Group stop (graph terminated)"
do_test group15 "-ve group colocation"
do_test bug-1573 "Partial stop of a group with two children"
do_test bug-1718 "Mandatory group ordering - Stop group_FUN"
do_test bug-lf-2613 "Move group on failure"
do_test bug-lf-2619 "Move group on clone failure"
echo ""
do_test rsc_dep1 "Must not "
do_test rsc_dep3 "Must "
do_test rsc_dep5 "Must not 3 "
do_test rsc_dep7 "Must 3 "
do_test rsc_dep10 "Must (but cant)"
do_test rsc_dep2 "Must (running) "
do_test rsc_dep8 "Must (running : alt) "
do_test rsc_dep4 "Must (running + move)"
do_test asymmetric "Asymmetric - require explicit location constraints"
echo ""
do_test orphan-0 "Orphan ignore"
do_test orphan-1 "Orphan stop"
do_test orphan-2 "Orphan stop, remove failcount"
echo ""
do_test params-0 "Params: No change"
do_test params-1 "Params: Changed"
do_test params-2 "Params: Resource definition"
do_test params-4 "Params: Reload"
do_test params-5 "Params: Restart based on probe digest"
do_test novell-251689 "Resource definition change + target_role=stopped"
do_test bug-lf-2106 "Restart all anonymous clone instances after config change"
do_test params-6 "Params: Detect reload in previously migrated resource"
echo ""
do_test target-0 "Target Role : baseline"
do_test target-1 "Target Role : master"
do_test target-2 "Target Role : invalid"
echo ""
do_test domain "Failover domains"
do_test base-score "Set a node's default score for all nodes"
echo ""
do_test date-1 "Dates" -t "2005-020"
do_test date-2 "Date Spec - Pass" -t "2005-020T12:30"
do_test date-3 "Date Spec - Fail" -t "2005-020T11:30"
do_test probe-0 "Probe (anon clone)"
do_test probe-1 "Pending Probe"
do_test probe-2 "Correctly re-probe cloned groups"
do_test probe-3 "Probe (pending node)"
do_test probe-4 "Probe (pending node + stopped resource)" --rc 4
do_test standby "Standby"
do_test comments "Comments"
echo ""
do_test one-or-more-0 "Everything starts"
do_test one-or-more-1 "Nothing starts because of A"
do_test one-or-more-2 "D can start because of C"
do_test one-or-more-3 "D cannot start because of B and C"
do_test one-or-more-4 "D cannot start because of target-role"
do_test one-or-more-5 "Start A and F even though C and D are stopped"
do_test one-or-more-6 "Leave A running even though B is stopped"
do_test one-or-more-7 "Leave A running even though C is stopped"
echo ""
do_test order1 "Order start 1 "
do_test order2 "Order start 2 "
do_test order3 "Order stop "
do_test order4 "Order (multiple) "
do_test order5 "Order (move) "
do_test order6 "Order (move w/ restart) "
do_test order7 "Order (manditory) "
do_test order-optional "Order (score=0) "
do_test order-required "Order (score=INFINITY) "
do_test bug-lf-2171 "Prevent group start when clone is stopped"
do_test order-clone "Clone ordering should be able to prevent startup of dependant clones"
do_test order-sets "Ordering for resource sets"
do_test order-serialize "Serialize resources without inhibiting migration"
do_test order-serialize-set "Serialize a set of resources without inhibiting migration"
do_test clone-order-primitive "Order clone start after a primitive"
do_test order-optional-keyword "Order (optional keyword)"
do_test order-mandatory "Order (mandatory keyword)"
do_test bug-lf-2493 "Don't imply colocation requirements when applying ordering constraints with clones"
do_test ordered-set-basic-startup "Constraint set with default order settings."
# This test emits an error log and thus upsets the test suite; even
# though it explicitly aims to test an error leg. FIXME
# do_test order-wrong-kind "Order (error)"
echo ""
do_test coloc-loop "Colocation - loop"
do_test coloc-many-one "Colocation - many-to-one"
do_test coloc-list "Colocation - many-to-one with list"
do_test coloc-group "Colocation - groups"
do_test coloc-slave-anti "Anti-colocation with slave shouldn't prevent master colocation"
do_test coloc-attr "Colocation based on node attributes"
do_test coloc-negative-group "Negative colocation with a group"
do_test coloc-intra-set "Intra-set colocation"
do_test bug-lf-2435 "Colocation sets with a negative score"
do_test coloc-clone-stays-active "Ensure clones don't get stopped/demoted because a dependant must stop"
+do_test coloc_fp_logic "Verify floating point calculations in colocation are working"
+do_test colo_master_w_native "cl#5070 - Verify promotion order is affected when colocating master to native rsc."
+do_test colo_slave_w_native "cl#5070 - Verify promotion order is affected when colocating slave to native rsc."
echo ""
do_test rsc-sets-seq-true "Resource Sets - sequential=false"
do_test rsc-sets-seq-false "Resource Sets - sequential=true"
do_test rsc-sets-clone "Resource Sets - Clone"
do_test rsc-sets-master "Resource Sets - Master"
do_test rsc-sets-clone-1 "Resource Sets - Clone (lf#2404)"
#echo ""
#do_test agent1 "version: lt (empty)"
#do_test agent2 "version: eq "
#do_test agent3 "version: gt "
echo ""
do_test attrs1 "string: eq (and) "
do_test attrs2 "string: lt / gt (and)"
do_test attrs3 "string: ne (or) "
do_test attrs4 "string: exists "
do_test attrs5 "string: not_exists "
do_test attrs6 "is_dc: true "
do_test attrs7 "is_dc: false "
do_test attrs8 "score_attribute "
echo ""
do_test mon-rsc-1 "Schedule Monitor - start"
do_test mon-rsc-2 "Schedule Monitor - move "
do_test mon-rsc-3 "Schedule Monitor - pending start "
do_test mon-rsc-4 "Schedule Monitor - move/pending start"
echo ""
do_test rec-rsc-0 "Resource Recover - no start "
do_test rec-rsc-1 "Resource Recover - start "
do_test rec-rsc-2 "Resource Recover - monitor "
do_test rec-rsc-3 "Resource Recover - stop - ignore"
do_test rec-rsc-4 "Resource Recover - stop - block "
do_test rec-rsc-5 "Resource Recover - stop - fence "
do_test rec-rsc-6 "Resource Recover - multiple - restart"
do_test rec-rsc-7 "Resource Recover - multiple - stop "
do_test rec-rsc-8 "Resource Recover - multiple - block "
do_test rec-rsc-9 "Resource Recover - group/group"
echo ""
do_test quorum-1 "No quorum - ignore"
do_test quorum-2 "No quorum - freeze"
do_test quorum-3 "No quorum - stop "
do_test quorum-4 "No quorum - start anyway"
do_test quorum-5 "No quorum - start anyway (group)"
do_test quorum-6 "No quorum - start anyway (clone)"
echo ""
do_test rec-node-1 "Node Recover - Startup - no fence"
do_test rec-node-2 "Node Recover - Startup - fence "
do_test rec-node-3 "Node Recover - HA down - no fence"
do_test rec-node-4 "Node Recover - HA down - fence "
do_test rec-node-5 "Node Recover - CRM down - no fence"
do_test rec-node-6 "Node Recover - CRM down - fence "
do_test rec-node-7 "Node Recover - no quorum - ignore "
do_test rec-node-8 "Node Recover - no quorum - freeze "
do_test rec-node-9 "Node Recover - no quorum - stop "
do_test rec-node-10 "Node Recover - no quorum - stop w/fence"
do_test rec-node-11 "Node Recover - CRM down w/ group - fence "
do_test rec-node-12 "Node Recover - nothing active - fence "
do_test rec-node-13 "Node Recover - failed resource + shutdown - fence "
do_test rec-node-15 "Node Recover - unknown lrm section"
do_test rec-node-14 "Serialize all stonith's"
echo ""
do_test multi1 "Multiple Active (stop/start)"
echo ""
do_test migrate-begin "Normal migration"
do_test migrate-success "Completed migration"
do_test migrate-partial-1 "Completed migration, missing stop on source"
do_test migrate-partial-2 "Successful migrate_to only"
do_test migrate-partial-3 "Successful migrate_to only, target down"
do_test migrate-partial-4 "Migrate from the correct host after migrate_to+migrate_from"
do_test migrate-fail-2 "Failed migrate_from"
do_test migrate-fail-3 "Failed migrate_from + stop on source"
do_test migrate-fail-4 "Failed migrate_from + stop on target - ideally we wouldn't need to re-stop on target"
do_test migrate-fail-5 "Failed migrate_from + stop on source and target"
do_test migrate-fail-6 "Failed migrate_to"
do_test migrate-fail-7 "Failed migrate_to + stop on source"
do_test migrate-fail-8 "Failed migrate_to + stop on target - ideally we wouldn't need to re-stop on target"
do_test migrate-fail-9 "Failed migrate_to + stop on source and target"
do_test migrate-stop "Migration in a stopping stack"
do_test migrate-start "Migration in a starting stack"
do_test migrate-stop_start "Migration in a restarting stack"
do_test migrate-stop-complex "Migration in a complex stopping stack"
do_test migrate-start-complex "Migration in a complex starting stack"
do_test migrate-stop-start-complex "Migration in a complex moving stack"
do_test migrate-shutdown "Order the post-migration 'stop' before node shutdown"
do_test migrate-1 "Migrate (migrate)"
do_test migrate-2 "Migrate (stable)"
do_test migrate-3 "Migrate (failed migrate_to)"
do_test migrate-4 "Migrate (failed migrate_from)"
do_test novell-252693 "Migration in a stopping stack"
do_test novell-252693-2 "Migration in a starting stack"
do_test novell-252693-3 "Non-Migration in a starting and stopping stack"
do_test bug-1820 "Migration in a group"
do_test bug-1820-1 "Non-migration in a group"
do_test migrate-5 "Primitive migration with a clone"
do_test migrate-fencing "Migration after Fencing"
#echo ""
#do_test complex1 "Complex "
do_test bug-lf-2422 "Dependancy on partially active group - stop ocfs:*"
echo ""
do_test clone-anon-probe-1 "Probe the correct (anonymous) clone instance for each node"
do_test clone-anon-probe-2 "Avoid needless re-probing of anonymous clones"
do_test clone-anon-failcount "Merge failcounts for anonymous clones"
do_test inc0 "Incarnation start"
do_test inc1 "Incarnation start order"
do_test inc2 "Incarnation silent restart, stop, move"
do_test inc3 "Inter-incarnation ordering, silent restart, stop, move"
do_test inc4 "Inter-incarnation ordering, silent restart, stop, move (ordered)"
do_test inc5 "Inter-incarnation ordering, silent restart, stop, move (restart 1)"
do_test inc6 "Inter-incarnation ordering, silent restart, stop, move (restart 2)"
do_test inc7 "Clone colocation"
do_test inc8 "Clone anti-colocation"
do_test inc9 "Non-unique clone"
do_test inc10 "Non-unique clone (stop)"
do_test inc11 "Primitive colocation with clones"
do_test inc12 "Clone shutdown"
do_test cloned-group "Make sure only the correct number of cloned groups are started"
do_test clone-no-shuffle "Dont prioritize allocation of instances that must be moved"
do_test clone-max-zero "Orphan processing with clone-max=0"
do_test clone-anon-dup "Bug LF#2087 - Correctly parse the state of anonymous clones that are active more than once per node"
do_test bug-lf-2160 "Dont shuffle clones due to colocation"
do_test bug-lf-2213 "clone-node-max enforcement for cloned groups"
do_test bug-lf-2153 "Clone ordering constraints"
do_test bug-lf-2361 "Ensure clones observe mandatory ordering constraints if the LHS is unrunnable"
do_test bug-lf-2317 "Avoid needless restart of primitive depending on a clone"
do_test clone-colocate-instance-1 "Colocation with a specific clone instance (negative example)"
do_test clone-colocate-instance-2 "Colocation with a specific clone instance"
do_test clone-order-instance "Ordering with specific clone instances"
do_test bug-lf-2453 "Enforce mandatory clone ordering without colocation"
do_test bug-lf-2508 "Correctly reconstruct the status of anonymous cloned groups"
do_test bug-lf-2544 "Balanced clone placement"
do_test bug-lf-2445 "Redistribute clones with node-max > 1 and stickiness = 0"
do_test bug-lf-2574 "Avoid clone shuffle"
do_test bug-lf-2581 "Avoid group restart due to unrelated clone (re)start"
echo ""
do_test master-0 "Stopped -> Slave"
do_test master-1 "Stopped -> Promote"
do_test master-2 "Stopped -> Promote : notify"
do_test master-3 "Stopped -> Promote : master location"
do_test master-4 "Started -> Promote : master location"
do_test master-5 "Promoted -> Promoted"
do_test master-6 "Promoted -> Promoted (2)"
do_test master-7 "Promoted -> Fenced"
do_test master-8 "Promoted -> Fenced -> Moved"
do_test master-9 "Stopped + Promotable + No quorum"
do_test master-10 "Stopped -> Promotable : notify with monitor"
do_test master-11 "Stopped -> Promote : colocation"
do_test novell-239082 "Demote/Promote ordering"
do_test novell-239087 "Stable master placement"
do_test master-12 "Promotion based solely on rsc_location constraints"
do_test master-13 "Include preferences of colocated resources when placing master"
do_test master-demote "Ordering when actions depends on demoting a slave resource"
do_test master-ordering "Prevent resources from starting that need a master"
do_test bug-1765 "Master-Master Colocation (dont stop the slaves)"
do_test master-group "Promotion of cloned groups"
do_test bug-lf-1852 "Don't shuffle master/slave instances unnecessarily"
do_test master-failed-demote "Dont retry failed demote actions"
do_test master-failed-demote-2 "Dont retry failed demote actions (notify=false)"
do_test master-depend "Ensure resources that depend on the master don't get allocated until the master does"
do_test master-reattach "Re-attach to a running master"
do_test master-allow-start "Don't include master score if it would prevent allocation"
do_test master-colocation "Allow master instances placemaker to be influenced by colocation constraints"
do_test master-pseudo "Make sure promote/demote pseudo actions are created correctly"
do_test master-role "Prevent target-role from promoting more than master-max instances"
do_test bug-lf-2358 "Master-Master anti-colocation"
do_test master-promotion-constraint "Mandatory master colocation constraints"
do_test unmanaged-master "Ensure role is preserved for unmanaged resources"
do_test master-unmanaged-monitor "Start the correct monitor operation for unmanaged masters"
do_test master-demote-2 "Demote does not clear past failure"
do_test master-move "Move master based on failure of colocated group"
do_test master-probed-score "Observe the promotion score of probed resources"
do_test colocation_constraint_stops_master "cl#5054 - Ensure master is demoted when stopped by colocation constraint"
do_test colocation_constraint_stops_slave "cl#5054 - Ensure slave is not demoted when stopped by colocation constraint"
do_test order_constraint_stops_master "cl#5054 - Ensure master is demoted when stopped by order constraint"
do_test order_constraint_stops_slave "cl#5054 - Ensure slave is not demoted when stopped by order constraint"
do_test master_monitor_restart "cl#5072 - Ensure master monitor operation will start after promotion."
echo ""
do_test history-1 "Correctly parse stateful-1 resource state"
echo ""
do_test managed-0 "Managed (reference)"
do_test managed-1 "Not managed - down "
do_test managed-2 "Not managed - up "
do_test bug-5028 "Shutdown should block if anything depends on an unmanaged resource"
do_test bug-5028-detach "Ensure detach still works"
do_test bug-5028-bottom "Ensure shutdown still blocks if the blocked resource is at the bottom of the stack"
echo ""
do_test interleave-0 "Interleave (reference)"
do_test interleave-1 "coloc - not interleaved"
do_test interleave-2 "coloc - interleaved "
do_test interleave-3 "coloc - interleaved (2)"
do_test interleave-pseudo-stop "Interleaved clone during stonith"
do_test interleave-stop "Interleaved clone during stop"
do_test interleave-restart "Interleaved clone during dependancy restart"
echo ""
do_test notify-0 "Notify reference"
do_test notify-1 "Notify simple"
do_test notify-2 "Notify simple, confirm"
do_test notify-3 "Notify move, confirm"
do_test novell-239079 "Notification priority"
#do_test notify-2 "Notify - 764"
echo ""
do_test 594 "OSDL #594 - Unrunnable actions scheduled in transition"
do_test 662 "OSDL #662 - Two resources start on one node when incarnation_node_max = 1"
do_test 696 "OSDL #696 - CRM starts stonith RA without monitor"
do_test 726 "OSDL #726 - Attempting to schedule rsc_posic041_monitor_5000 _after_ a stop"
do_test 735 "OSDL #735 - Correctly detect that rsc_hadev1 is stopped on hadev3"
do_test 764 "OSDL #764 - Missing monitor op for DoFencing:child_DoFencing:1"
do_test 797 "OSDL #797 - Assert triggered: task_id_i > max_call_id"
do_test 829 "OSDL #829"
do_test 994 "OSDL #994 - Stopping the last resource in a resource group causes the entire group to be restarted"
do_test 994-2 "OSDL #994 - with a dependant resource"
do_test 1360 "OSDL #1360 - Clone stickiness"
do_test 1484 "OSDL #1484 - on_fail=stop"
do_test 1494 "OSDL #1494 - Clone stability"
do_test unrunnable-1 "Unrunnable"
do_test stonith-0 "Stonith loop - 1"
do_test stonith-1 "Stonith loop - 2"
do_test stonith-2 "Stonith loop - 3"
do_test stonith-3 "Stonith startup"
do_test bug-1572-1 "Recovery of groups depending on master/slave"
do_test bug-1572-2 "Recovery of groups depending on master/slave when the master is never re-promoted"
do_test bug-1685 "Depends-on-master ordering"
do_test bug-1822 "Dont promote partially active groups"
do_test bug-pm-11 "New resource added to a m/s group"
do_test bug-pm-12 "Recover only the failed portion of a cloned group"
do_test bug-n-387749 "Don't shuffle clone instances"
do_test bug-n-385265 "Don't ignore the failure stickiness of group children - resource_idvscommon should stay stopped"
do_test bug-n-385265-2 "Ensure groups are migrated instead of remaining partially active on the current node"
do_test bug-lf-1920 "Correctly handle probes that find active resources"
do_test bnc-515172 "Location constraint with multiple expressions"
do_test colocate-primitive-with-clone "Optional colocation with a clone"
do_test use-after-free-merge "Use-after-free in native_merge_weights"
do_test bug-lf-2551 "STONITH ordering for stop"
do_test bug-lf-2606 "Stonith implies demote"
do_test bug-lf-2474 "Ensure resource op timeout takes precedence over op_defaults"
do_test bug-suse-707150 "Prevent vm-01 from starting due to colocation/ordering"
do_test bug-5014-A-start-B-start "Verify when A starts B starts using symmetrical=false"
do_test bug-5014-A-stop-B-started "Verify when A stops B does not stop if it has already started using symmetric=false"
do_test bug-5014-A-stopped-B-stopped "Verify when A is stopped and B has not started, B does not start before A using symmetric=false"
do_test bug-5014-CthenAthenB-C-stopped "Verify when C then A is symmetrical=true, A then B is symmetric=false, and C is stopped that nothing starts."
do_test bug-5014-CLONE-A-start-B-start "Verify when A starts B starts using clone resources with symmetric=false"
do_test bug-5014-CLONE-A-stop-B-started "Verify when A stops B does not stop if it has already started using clone resources with symmetric=false."
do_test bug-5014-GROUP-A-start-B-start "Verify when A starts B starts when using group resources with symmetric=false."
do_test bug-5014-GROUP-A-stopped-B-started "Verify when A stops B does not stop if it has already started using group resources with symmetric=false."
do_test bug-5014-GROUP-A-stopped-B-stopped "Verify when A is stopped and B has not started, B does not start before A using group resources with symmetric=false."
do_test bug-5014-ordered-set-symmetrical-false "Verify ordered sets work with symmetrical=false"
do_test bug-5014-ordered-set-symmetrical-true "Verify ordered sets work with symmetrical=true"
do_test bug-5007-masterslave_colocation "Verify use of colocation scores other than INFINITY and -INFINITY work on multi-state resources."
do_test bug-5038 "Prevent restart of anonymous clones when clone-max decreases"
do_test bug-5025-1 "Automatically clean up failcount after resource config change with reload"
do_test bug-5025-2 "Make sure clear failcount action isn't set when config does not change."
do_test bug-5025-3 "Automatically clean up failcount after resource config change with restart"
do_test monitor-onfail-restart "bug-5058 - Monitor failure with on-fail set to restart"
do_test monitor-onfail-stop "bug-5058 - Monitor failure wiht on-fail set to stop"
do_test bug-5059 "No need to restart p_stateful1:*"
do_test bug-5069-op-enabled "Test on-fail=ignore with failure when monitor is enabled."
do_test bug-5069-op-disabled "Test on-fail-ignore with failure when monitor is disabled."
do_test ignore_stonith_rsc_order1 "cl#5056- Ignore order constraint between stonith and non-stonith rsc."
do_test ignore_stonith_rsc_order2 "cl#5056- Ignore order constraint with group rsc containing mixed stonith and non-stonith."
do_test ignore_stonith_rsc_order3 "cl#5056- Ignore order constraint, stonith clone and mixed group"
do_test ignore_stonith_rsc_order4 "cl#5056- Ignore order constraint, stonith clone and clone with nested mixed group"
do_test honor_stonith_rsc_order1 "cl#5056- Honor order constraint, stonith clone and pure stonith group(single rsc)."
do_test honor_stonith_rsc_order2 "cl#5056- Honor order constraint, stonith clone and pure stonith group(multiple rsc)"
do_test honor_stonith_rsc_order3 "cl#5056- Honor order constraint, stonith clones with nested pure stonith group."
do_test honor_stonith_rsc_order4 "cl#5056- Honor order constraint, between two native stonith rscs."
echo ""
do_test systemhealth1 "System Health () #1"
do_test systemhealth2 "System Health () #2"
do_test systemhealth3 "System Health () #3"
do_test systemhealthn1 "System Health (None) #1"
do_test systemhealthn2 "System Health (None) #2"
do_test systemhealthn3 "System Health (None) #3"
do_test systemhealthm1 "System Health (Migrate On Red) #1"
do_test systemhealthm2 "System Health (Migrate On Red) #2"
do_test systemhealthm3 "System Health (Migrate On Red) #3"
do_test systemhealtho1 "System Health (Only Green) #1"
do_test systemhealtho2 "System Health (Only Green) #2"
do_test systemhealtho3 "System Health (Only Green) #3"
do_test systemhealthp1 "System Health (Progessive) #1"
do_test systemhealthp2 "System Health (Progessive) #2"
do_test systemhealthp3 "System Health (Progessive) #3"
echo ""
do_test utilization "Placement Strategy - utilization"
do_test minimal "Placement Strategy - minimal"
do_test balanced "Placement Strategy - balanced"
echo ""
do_test placement-stickiness "Optimized Placement Strategy - stickiness"
do_test placement-priority "Optimized Placement Strategy - priority"
do_test placement-location "Optimized Placement Strategy - location"
do_test placement-capacity "Optimized Placement Strategy - capacity"
echo ""
do_test utilization-order1 "Utilization Order - Simple"
do_test utilization-order2 "Utilization Order - Complex"
do_test utilization-order3 "Utilization Order - Migrate"
do_test utilization-order4 "Utilization Order - Live Mirgration (bnc#695440)"
do_test utilization-shuffle "Don't displace prmExPostgreSQLDB2 on act2, Start prmExPostgreSQLDB1 on act3"
echo ""
do_test reprobe-target_rc "Ensure correct target_rc for reprobe of inactive resources"
echo ""
do_test stopped-monitor-00 "Stopped Monitor - initial start"
do_test stopped-monitor-01 "Stopped Monitor - failed started"
do_test stopped-monitor-02 "Stopped Monitor - started multi-up"
do_test stopped-monitor-03 "Stopped Monitor - stop started"
do_test stopped-monitor-04 "Stopped Monitor - failed stop"
do_test stopped-monitor-05 "Stopped Monitor - start unmanaged"
do_test stopped-monitor-06 "Stopped Monitor - unmanaged multi-up"
do_test stopped-monitor-07 "Stopped Monitor - start unmanaged multi-up"
do_test stopped-monitor-08 "Stopped Monitor - migrate"
do_test stopped-monitor-09 "Stopped Monitor - unmanage started"
do_test stopped-monitor-10 "Stopped Monitor - unmanaged started multi-up"
do_test stopped-monitor-11 "Stopped Monitor - stop unmanaged started"
do_test stopped-monitor-12 "Stopped Monitor - unmanaged started multi-up (targer-role="Stopped")"
do_test stopped-monitor-20 "Stopped Monitor - initial stop"
do_test stopped-monitor-21 "Stopped Monitor - stopped single-up"
do_test stopped-monitor-22 "Stopped Monitor - stopped multi-up"
do_test stopped-monitor-23 "Stopped Monitor - start stopped"
do_test stopped-monitor-24 "Stopped Monitor - unmanage stopped"
do_test stopped-monitor-25 "Stopped Monitor - unmanaged stopped multi-up"
do_test stopped-monitor-26 "Stopped Monitor - start unmanaged stopped"
do_test stopped-monitor-27 "Stopped Monitor - unmanaged stopped multi-up (target-role="Started")"
do_test stopped-monitor-30 "Stopped Monitor - new node started"
do_test stopped-monitor-31 "Stopped Monitor - new node stopped"
echo""
do_test ticket-primitive-1 "Ticket - Primitive (loss-policy=stop, initial)"
do_test ticket-primitive-2 "Ticket - Primitive (loss-policy=stop, granted)"
do_test ticket-primitive-3 "Ticket - Primitive (loss-policy-stop, revoked)"
do_test ticket-primitive-4 "Ticket - Primitive (loss-policy=demote, initial)"
do_test ticket-primitive-5 "Ticket - Primitive (loss-policy=demote, granted)"
do_test ticket-primitive-6 "Ticket - Primitive (loss-policy=demote, revoked)"
do_test ticket-primitive-7 "Ticket - Primitive (loss-policy=fence, initial)"
do_test ticket-primitive-8 "Ticket - Primitive (loss-policy=fence, granted)"
do_test ticket-primitive-9 "Ticket - Primitive (loss-policy=fence, revoked)"
do_test ticket-primitive-10 "Ticket - Primitive (loss-policy=freeze, initial)"
do_test ticket-primitive-11 "Ticket - Primitive (loss-policy=freeze, granted)"
do_test ticket-primitive-12 "Ticket - Primitive (loss-policy=freeze, revoked)"
do_test ticket-primitive-13 "Ticket - Primitive (loss-policy=stop, standby, granted)"
do_test ticket-primitive-14 "Ticket - Primitive (loss-policy=stop, granted, standby)"
do_test ticket-primitive-15 "Ticket - Primitive (loss-policy=stop, standby, revoked)"
do_test ticket-primitive-16 "Ticket - Primitive (loss-policy=demote, standby, granted)"
do_test ticket-primitive-17 "Ticket - Primitive (loss-policy=demote, granted, standby)"
do_test ticket-primitive-18 "Ticket - Primitive (loss-policy=demote, standby, revoked)"
do_test ticket-primitive-19 "Ticket - Primitive (loss-policy=fence, standby, granted)"
do_test ticket-primitive-20 "Ticket - Primitive (loss-policy=fence, granted, standby)"
do_test ticket-primitive-21 "Ticket - Primitive (loss-policy=fence, standby, revoked)"
do_test ticket-primitive-22 "Ticket - Primitive (loss-policy=freeze, standby, granted)"
do_test ticket-primitive-23 "Ticket - Primitive (loss-policy=freeze, granted, standby)"
do_test ticket-primitive-24 "Ticket - Primitive (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-group-1 "Ticket - Group (loss-policy=stop, initial)"
do_test ticket-group-2 "Ticket - Group (loss-policy=stop, granted)"
do_test ticket-group-3 "Ticket - Group (loss-policy-stop, revoked)"
do_test ticket-group-4 "Ticket - Group (loss-policy=demote, initial)"
do_test ticket-group-5 "Ticket - Group (loss-policy=demote, granted)"
do_test ticket-group-6 "Ticket - Group (loss-policy=demote, revoked)"
do_test ticket-group-7 "Ticket - Group (loss-policy=fence, initial)"
do_test ticket-group-8 "Ticket - Group (loss-policy=fence, granted)"
do_test ticket-group-9 "Ticket - Group (loss-policy=fence, revoked)"
do_test ticket-group-10 "Ticket - Group (loss-policy=freeze, initial)"
do_test ticket-group-11 "Ticket - Group (loss-policy=freeze, granted)"
do_test ticket-group-12 "Ticket - Group (loss-policy=freeze, revoked)"
do_test ticket-group-13 "Ticket - Group (loss-policy=stop, standby, granted)"
do_test ticket-group-14 "Ticket - Group (loss-policy=stop, granted, standby)"
do_test ticket-group-15 "Ticket - Group (loss-policy=stop, standby, revoked)"
do_test ticket-group-16 "Ticket - Group (loss-policy=demote, standby, granted)"
do_test ticket-group-17 "Ticket - Group (loss-policy=demote, granted, standby)"
do_test ticket-group-18 "Ticket - Group (loss-policy=demote, standby, revoked)"
do_test ticket-group-19 "Ticket - Group (loss-policy=fence, standby, granted)"
do_test ticket-group-20 "Ticket - Group (loss-policy=fence, granted, standby)"
do_test ticket-group-21 "Ticket - Group (loss-policy=fence, standby, revoked)"
do_test ticket-group-22 "Ticket - Group (loss-policy=freeze, standby, granted)"
do_test ticket-group-23 "Ticket - Group (loss-policy=freeze, granted, standby)"
do_test ticket-group-24 "Ticket - Group (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-clone-1 "Ticket - Clone (loss-policy=stop, initial)"
do_test ticket-clone-2 "Ticket - Clone (loss-policy=stop, granted)"
do_test ticket-clone-3 "Ticket - Clone (loss-policy-stop, revoked)"
do_test ticket-clone-4 "Ticket - Clone (loss-policy=demote, initial)"
do_test ticket-clone-5 "Ticket - Clone (loss-policy=demote, granted)"
do_test ticket-clone-6 "Ticket - Clone (loss-policy=demote, revoked)"
do_test ticket-clone-7 "Ticket - Clone (loss-policy=fence, initial)"
do_test ticket-clone-8 "Ticket - Clone (loss-policy=fence, granted)"
do_test ticket-clone-9 "Ticket - Clone (loss-policy=fence, revoked)"
do_test ticket-clone-10 "Ticket - Clone (loss-policy=freeze, initial)"
do_test ticket-clone-11 "Ticket - Clone (loss-policy=freeze, granted)"
do_test ticket-clone-12 "Ticket - Clone (loss-policy=freeze, revoked)"
do_test ticket-clone-13 "Ticket - Clone (loss-policy=stop, standby, granted)"
do_test ticket-clone-14 "Ticket - Clone (loss-policy=stop, granted, standby)"
do_test ticket-clone-15 "Ticket - Clone (loss-policy=stop, standby, revoked)"
do_test ticket-clone-16 "Ticket - Clone (loss-policy=demote, standby, granted)"
do_test ticket-clone-17 "Ticket - Clone (loss-policy=demote, granted, standby)"
do_test ticket-clone-18 "Ticket - Clone (loss-policy=demote, standby, revoked)"
do_test ticket-clone-19 "Ticket - Clone (loss-policy=fence, standby, granted)"
do_test ticket-clone-20 "Ticket - Clone (loss-policy=fence, granted, standby)"
do_test ticket-clone-21 "Ticket - Clone (loss-policy=fence, standby, revoked)"
do_test ticket-clone-22 "Ticket - Clone (loss-policy=freeze, standby, granted)"
do_test ticket-clone-23 "Ticket - Clone (loss-policy=freeze, granted, standby)"
do_test ticket-clone-24 "Ticket - Clone (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-master-1 "Ticket - Master (loss-policy=stop, initial)"
do_test ticket-master-2 "Ticket - Master (loss-policy=stop, granted)"
do_test ticket-master-3 "Ticket - Master (loss-policy-stop, revoked)"
do_test ticket-master-4 "Ticket - Master (loss-policy=demote, initial)"
do_test ticket-master-5 "Ticket - Master (loss-policy=demote, granted)"
do_test ticket-master-6 "Ticket - Master (loss-policy=demote, revoked)"
do_test ticket-master-7 "Ticket - Master (loss-policy=fence, initial)"
do_test ticket-master-8 "Ticket - Master (loss-policy=fence, granted)"
do_test ticket-master-9 "Ticket - Master (loss-policy=fence, revoked)"
do_test ticket-master-10 "Ticket - Master (loss-policy=freeze, initial)"
do_test ticket-master-11 "Ticket - Master (loss-policy=freeze, granted)"
do_test ticket-master-12 "Ticket - Master (loss-policy=freeze, revoked)"
do_test ticket-master-13 "Ticket - Master (loss-policy=stop, standby, granted)"
do_test ticket-master-14 "Ticket - Master (loss-policy=stop, granted, standby)"
do_test ticket-master-15 "Ticket - Master (loss-policy=stop, standby, revoked)"
do_test ticket-master-16 "Ticket - Master (loss-policy=demote, standby, granted)"
do_test ticket-master-17 "Ticket - Master (loss-policy=demote, granted, standby)"
do_test ticket-master-18 "Ticket - Master (loss-policy=demote, standby, revoked)"
do_test ticket-master-19 "Ticket - Master (loss-policy=fence, standby, granted)"
do_test ticket-master-20 "Ticket - Master (loss-policy=fence, granted, standby)"
do_test ticket-master-21 "Ticket - Master (loss-policy=fence, standby, revoked)"
do_test ticket-master-22 "Ticket - Master (loss-policy=freeze, standby, granted)"
do_test ticket-master-23 "Ticket - Master (loss-policy=freeze, granted, standby)"
do_test ticket-master-24 "Ticket - Master (loss-policy=freeze, standby, revoked)"
echo ""
do_test ticket-rsc-sets-1 "Ticket - Resource sets (1 ticket, initial)"
do_test ticket-rsc-sets-2 "Ticket - Resource sets (1 ticket, granted)"
do_test ticket-rsc-sets-3 "Ticket - Resource sets (1 ticket, revoked)"
do_test ticket-rsc-sets-4 "Ticket - Resource sets (2 tickets, initial)"
do_test ticket-rsc-sets-5 "Ticket - Resource sets (2 tickets, granted)"
do_test ticket-rsc-sets-6 "Ticket - Resource sets (2 tickets, granted)"
do_test ticket-rsc-sets-7 "Ticket - Resource sets (2 tickets, revoked)"
do_test ticket-rsc-sets-8 "Ticket - Resource sets (1 ticket, standby, granted)"
do_test ticket-rsc-sets-9 "Ticket - Resource sets (1 ticket, granted, standby)"
do_test ticket-rsc-sets-10 "Ticket - Resource sets (1 ticket, standby, revoked)"
do_test ticket-rsc-sets-11 "Ticket - Resource sets (2 tickets, standby, granted)"
do_test ticket-rsc-sets-12 "Ticket - Resource sets (2 tickets, standby, granted)"
do_test ticket-rsc-sets-13 "Ticket - Resource sets (2 tickets, granted, standby)"
do_test ticket-rsc-sets-14 "Ticket - Resource sets (2 tickets, standby, revoked)"
echo ""
do_test template-1 "Template - 1"
do_test template-2 "Template - 2"
do_test template-3 "Template - 3 (merge operations)"
do_test template-coloc-1 "Template - Colocation 1"
do_test template-coloc-2 "Template - Colocation 2"
do_test template-coloc-3 "Template - Colocation 3"
do_test template-order-1 "Template - Order 1"
do_test template-order-2 "Template - Order 2"
do_test template-order-3 "Template - Order 3"
do_test template-ticket "Template - Ticket"
do_test template-rsc-sets-1 "Template - Resource Sets 1"
do_test template-rsc-sets-2 "Template - Resource Sets 2"
do_test template-rsc-sets-3 "Template - Resource Sets 3"
do_test template-rsc-sets-4 "Template - Resource Sets 4"
echo ""
test_results
diff --git a/pengine/test10/clone-anon-failcount.scores b/pengine/test10/clone-anon-failcount.scores
index 6b138b6116..8c193e1274 100644
--- a/pengine/test10/clone-anon-failcount.scores
+++ b/pengine/test10/clone-anon-failcount.scores
@@ -1,333 +1,333 @@
Allocation scores:
clone_color: clnDiskd1 allocation score on srv01: 300
clone_color: clnDiskd1 allocation score on srv02: 0
clone_color: clnDiskd1 allocation score on srv03: 0
clone_color: clnDiskd1 allocation score on srv04: 0
clone_color: clnG3dummy01:0 allocation score on srv01: 0
clone_color: clnG3dummy01:0 allocation score on srv02: 100
clone_color: clnG3dummy01:0 allocation score on srv03: 0
clone_color: clnG3dummy01:0 allocation score on srv04: 0
clone_color: clnG3dummy01:1 allocation score on srv01: 0
clone_color: clnG3dummy01:1 allocation score on srv02: 0
clone_color: clnG3dummy01:1 allocation score on srv03: 100
clone_color: clnG3dummy01:1 allocation score on srv04: 0
clone_color: clnG3dummy01:2 allocation score on srv01: 0
clone_color: clnG3dummy01:2 allocation score on srv02: 0
clone_color: clnG3dummy01:2 allocation score on srv03: 0
clone_color: clnG3dummy01:2 allocation score on srv04: 100
clone_color: clnG3dummy01:3 allocation score on srv01: 100
clone_color: clnG3dummy01:3 allocation score on srv02: 0
clone_color: clnG3dummy01:3 allocation score on srv03: 0
clone_color: clnG3dummy01:3 allocation score on srv04: 0
clone_color: clnG3dummy02:0 allocation score on srv01: 0
clone_color: clnG3dummy02:0 allocation score on srv02: 100
clone_color: clnG3dummy02:0 allocation score on srv03: 0
clone_color: clnG3dummy02:0 allocation score on srv04: 0
clone_color: clnG3dummy02:1 allocation score on srv01: 0
clone_color: clnG3dummy02:1 allocation score on srv02: 0
clone_color: clnG3dummy02:1 allocation score on srv03: 100
clone_color: clnG3dummy02:1 allocation score on srv04: 0
clone_color: clnG3dummy02:2 allocation score on srv01: 0
clone_color: clnG3dummy02:2 allocation score on srv02: 0
clone_color: clnG3dummy02:2 allocation score on srv03: 0
clone_color: clnG3dummy02:2 allocation score on srv04: 100
clone_color: clnG3dummy02:3 allocation score on srv01: 100
clone_color: clnG3dummy02:3 allocation score on srv02: 0
clone_color: clnG3dummy02:3 allocation score on srv03: 0
clone_color: clnG3dummy02:3 allocation score on srv04: 0
-clone_color: clnG3dummy1 allocation score on srv01: 300
+clone_color: clnG3dummy1 allocation score on srv01: 301
clone_color: clnG3dummy1 allocation score on srv02: 0
clone_color: clnG3dummy1 allocation score on srv03: 0
-clone_color: clnG3dummy1 allocation score on srv04: 0
-clone_color: clnG3dummy2 allocation score on srv01: 300
+clone_color: clnG3dummy1 allocation score on srv04: 1
+clone_color: clnG3dummy2 allocation score on srv01: 302
clone_color: clnG3dummy2 allocation score on srv02: 0
clone_color: clnG3dummy2 allocation score on srv03: 0
-clone_color: clnG3dummy2 allocation score on srv04: 0
-clone_color: clnPingd allocation score on srv01: 300
+clone_color: clnG3dummy2 allocation score on srv04: 2
+clone_color: clnPingd allocation score on srv01: 303
clone_color: clnPingd allocation score on srv02: 0
clone_color: clnPingd allocation score on srv03: 0
-clone_color: clnPingd allocation score on srv04: 0
+clone_color: clnPingd allocation score on srv04: 3
clone_color: clnPrmDiskd1:0 allocation score on srv01: 0
clone_color: clnPrmDiskd1:0 allocation score on srv02: 100
clone_color: clnPrmDiskd1:0 allocation score on srv03: 0
clone_color: clnPrmDiskd1:0 allocation score on srv04: 0
clone_color: clnPrmDiskd1:1 allocation score on srv01: 0
clone_color: clnPrmDiskd1:1 allocation score on srv02: 0
clone_color: clnPrmDiskd1:1 allocation score on srv03: 100
clone_color: clnPrmDiskd1:1 allocation score on srv04: 0
clone_color: clnPrmDiskd1:2 allocation score on srv01: 0
clone_color: clnPrmDiskd1:2 allocation score on srv02: 0
clone_color: clnPrmDiskd1:2 allocation score on srv03: 0
clone_color: clnPrmDiskd1:2 allocation score on srv04: 100
clone_color: clnPrmDiskd1:3 allocation score on srv01: 100
clone_color: clnPrmDiskd1:3 allocation score on srv02: 0
clone_color: clnPrmDiskd1:3 allocation score on srv03: 0
clone_color: clnPrmDiskd1:3 allocation score on srv04: 0
clone_color: clnPrmPingd:0 allocation score on srv01: 0
clone_color: clnPrmPingd:0 allocation score on srv02: 100
clone_color: clnPrmPingd:0 allocation score on srv03: 0
clone_color: clnPrmPingd:0 allocation score on srv04: 0
clone_color: clnPrmPingd:1 allocation score on srv01: 0
clone_color: clnPrmPingd:1 allocation score on srv02: 0
clone_color: clnPrmPingd:1 allocation score on srv03: 100
clone_color: clnPrmPingd:1 allocation score on srv04: 0
clone_color: clnPrmPingd:2 allocation score on srv01: 0
clone_color: clnPrmPingd:2 allocation score on srv02: 0
clone_color: clnPrmPingd:2 allocation score on srv03: 0
clone_color: clnPrmPingd:2 allocation score on srv04: 100
clone_color: clnPrmPingd:3 allocation score on srv01: 100
clone_color: clnPrmPingd:3 allocation score on srv02: 0
clone_color: clnPrmPingd:3 allocation score on srv03: 0
clone_color: clnPrmPingd:3 allocation score on srv04: 0
clone_color: clnUMdummy01:0 allocation score on srv01: -INFINITY
clone_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
clone_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
clone_color: clnUMdummy01:0 allocation score on srv04: 100
clone_color: clnUMdummy01:1 allocation score on srv01: -INFINITY
clone_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
clone_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
clone_color: clnUMdummy01:1 allocation score on srv04: 0
clone_color: clnUMdummy02:0 allocation score on srv01: -INFINITY
clone_color: clnUMdummy02:0 allocation score on srv02: 0
clone_color: clnUMdummy02:0 allocation score on srv03: 0
clone_color: clnUMdummy02:0 allocation score on srv04: 100
clone_color: clnUMdummy02:1 allocation score on srv01: -INFINITY
clone_color: clnUMdummy02:1 allocation score on srv02: 0
clone_color: clnUMdummy02:1 allocation score on srv03: 0
clone_color: clnUMdummy02:1 allocation score on srv04: 0
clone_color: clnUMgroup01 allocation score on srv01: -INFINITY
clone_color: clnUMgroup01 allocation score on srv02: -INFINITY
clone_color: clnUMgroup01 allocation score on srv03: -INFINITY
-clone_color: clnUMgroup01 allocation score on srv04: 0
+clone_color: clnUMgroup01 allocation score on srv04: 4
clone_color: clnUmResource:0 allocation score on srv01: -INFINITY
clone_color: clnUmResource:0 allocation score on srv02: -INFINITY
clone_color: clnUmResource:0 allocation score on srv03: -INFINITY
clone_color: clnUmResource:0 allocation score on srv04: 0
clone_color: clnUmResource:1 allocation score on srv01: -INFINITY
clone_color: clnUmResource:1 allocation score on srv02: -INFINITY
clone_color: clnUmResource:1 allocation score on srv03: -INFINITY
clone_color: clnUmResource:1 allocation score on srv04: 0
group_color: OVDBgroup02-1 allocation score on srv01: 200
group_color: OVDBgroup02-1 allocation score on srv02: -INFINITY
group_color: OVDBgroup02-1 allocation score on srv03: -INFINITY
group_color: OVDBgroup02-1 allocation score on srv04: 100
group_color: OVDBgroup02-2 allocation score on srv01: -INFINITY
group_color: OVDBgroup02-2 allocation score on srv02: 200
group_color: OVDBgroup02-2 allocation score on srv03: -INFINITY
group_color: OVDBgroup02-2 allocation score on srv04: 100
group_color: OVDBgroup02-3 allocation score on srv01: -INFINITY
group_color: OVDBgroup02-3 allocation score on srv02: -INFINITY
group_color: OVDBgroup02-3 allocation score on srv03: 200
group_color: OVDBgroup02-3 allocation score on srv04: 100
group_color: UMgroup01 allocation score on srv01: 200
group_color: UMgroup01 allocation score on srv02: -INFINITY
group_color: UMgroup01 allocation score on srv03: -INFINITY
group_color: UMgroup01 allocation score on srv04: 100
group_color: UmDummy01 allocation score on srv01: 100
group_color: UmDummy01 allocation score on srv02: 0
group_color: UmDummy01 allocation score on srv03: 0
group_color: UmDummy01 allocation score on srv04: 0
group_color: UmDummy02 allocation score on srv01: 100
group_color: UmDummy02 allocation score on srv02: 0
group_color: UmDummy02 allocation score on srv03: 0
group_color: UmDummy02 allocation score on srv04: 0
group_color: UmIPaddr allocation score on srv01: 100
group_color: UmIPaddr allocation score on srv02: 0
group_color: UmIPaddr allocation score on srv03: 0
group_color: UmIPaddr allocation score on srv04: 0
group_color: UmVIPcheck allocation score on srv01: 300
group_color: UmVIPcheck allocation score on srv02: -INFINITY
group_color: UmVIPcheck allocation score on srv03: -INFINITY
group_color: UmVIPcheck allocation score on srv04: 100
group_color: clnUMdummy01:0 allocation score on srv01: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv04: 100
group_color: clnUMdummy01:1 allocation score on srv01: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv04: -INFINITY
group_color: clnUMdummy02:0 allocation score on srv01: -INFINITY
group_color: clnUMdummy02:0 allocation score on srv02: 0
group_color: clnUMdummy02:0 allocation score on srv03: 0
group_color: clnUMdummy02:0 allocation score on srv04: 100
group_color: clnUMdummy02:1 allocation score on srv01: -INFINITY
group_color: clnUMdummy02:1 allocation score on srv02: 0
group_color: clnUMdummy02:1 allocation score on srv03: 0
group_color: clnUMdummy02:1 allocation score on srv04: -INFINITY
group_color: clnUmResource:0 allocation score on srv01: -INFINITY
group_color: clnUmResource:0 allocation score on srv02: -INFINITY
group_color: clnUmResource:0 allocation score on srv03: -INFINITY
group_color: clnUmResource:0 allocation score on srv04: 0
group_color: clnUmResource:1 allocation score on srv01: -INFINITY
group_color: clnUmResource:1 allocation score on srv02: -INFINITY
group_color: clnUmResource:1 allocation score on srv03: -INFINITY
group_color: clnUmResource:1 allocation score on srv04: -INFINITY
group_color: grpStonith1 allocation score on srv01: -INFINITY
group_color: grpStonith1 allocation score on srv02: 100
group_color: grpStonith1 allocation score on srv03: 100
group_color: grpStonith1 allocation score on srv04: 200
group_color: grpStonith2 allocation score on srv01: 200
group_color: grpStonith2 allocation score on srv02: -INFINITY
group_color: grpStonith2 allocation score on srv03: 100
group_color: grpStonith2 allocation score on srv04: 100
group_color: grpStonith3 allocation score on srv01: 100
group_color: grpStonith3 allocation score on srv02: 200
group_color: grpStonith3 allocation score on srv03: -INFINITY
group_color: grpStonith3 allocation score on srv04: 100
group_color: grpStonith4 allocation score on srv01: 100
group_color: grpStonith4 allocation score on srv02: 100
group_color: grpStonith4 allocation score on srv03: 200
group_color: grpStonith4 allocation score on srv04: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv01: 300
group_color: prmExPostgreSQLDB1 allocation score on srv02: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv03: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv04: 100
group_color: prmExPostgreSQLDB2 allocation score on srv01: -INFINITY
group_color: prmExPostgreSQLDB2 allocation score on srv02: 300
group_color: prmExPostgreSQLDB2 allocation score on srv03: -INFINITY
group_color: prmExPostgreSQLDB2 allocation score on srv04: 100
group_color: prmExPostgreSQLDB3 allocation score on srv01: -INFINITY
group_color: prmExPostgreSQLDB3 allocation score on srv02: -INFINITY
group_color: prmExPostgreSQLDB3 allocation score on srv03: 300
group_color: prmExPostgreSQLDB3 allocation score on srv04: 100
group_color: prmStonithN1 allocation score on srv01: -INFINITY
group_color: prmStonithN1 allocation score on srv02: 100
group_color: prmStonithN1 allocation score on srv03: 100
group_color: prmStonithN1 allocation score on srv04: 300
group_color: prmStonithN2 allocation score on srv01: 300
group_color: prmStonithN2 allocation score on srv02: -INFINITY
group_color: prmStonithN2 allocation score on srv03: 100
group_color: prmStonithN2 allocation score on srv04: 100
group_color: prmStonithN3 allocation score on srv01: 100
group_color: prmStonithN3 allocation score on srv02: 300
group_color: prmStonithN3 allocation score on srv03: -INFINITY
group_color: prmStonithN3 allocation score on srv04: 100
group_color: prmStonithN4 allocation score on srv01: 100
group_color: prmStonithN4 allocation score on srv02: 100
group_color: prmStonithN4 allocation score on srv03: 300
group_color: prmStonithN4 allocation score on srv04: -INFINITY
native_color: UmDummy01 allocation score on srv01: -INFINITY
native_color: UmDummy01 allocation score on srv02: -INFINITY
native_color: UmDummy01 allocation score on srv03: -INFINITY
native_color: UmDummy01 allocation score on srv04: 0
native_color: UmDummy02 allocation score on srv01: -INFINITY
native_color: UmDummy02 allocation score on srv02: -INFINITY
native_color: UmDummy02 allocation score on srv03: -INFINITY
native_color: UmDummy02 allocation score on srv04: 0
native_color: UmIPaddr allocation score on srv01: -INFINITY
native_color: UmIPaddr allocation score on srv02: -INFINITY
native_color: UmIPaddr allocation score on srv03: -INFINITY
native_color: UmIPaddr allocation score on srv04: 0
native_color: UmVIPcheck allocation score on srv01: -400
native_color: UmVIPcheck allocation score on srv02: -INFINITY
native_color: UmVIPcheck allocation score on srv03: -INFINITY
native_color: UmVIPcheck allocation score on srv04: 100
native_color: clnG3dummy01:0 allocation score on srv01: -INFINITY
native_color: clnG3dummy01:0 allocation score on srv02: 100
native_color: clnG3dummy01:0 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:0 allocation score on srv04: -INFINITY
native_color: clnG3dummy01:1 allocation score on srv01: 0
native_color: clnG3dummy01:1 allocation score on srv02: 0
native_color: clnG3dummy01:1 allocation score on srv03: 100
native_color: clnG3dummy01:1 allocation score on srv04: 0
native_color: clnG3dummy01:2 allocation score on srv01: 0
native_color: clnG3dummy01:2 allocation score on srv02: 0
native_color: clnG3dummy01:2 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:2 allocation score on srv04: 100
native_color: clnG3dummy01:3 allocation score on srv01: 100
native_color: clnG3dummy01:3 allocation score on srv02: 0
native_color: clnG3dummy01:3 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:3 allocation score on srv04: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv01: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv02: 100
native_color: clnG3dummy02:0 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv04: -INFINITY
native_color: clnG3dummy02:1 allocation score on srv01: 0
native_color: clnG3dummy02:1 allocation score on srv02: 0
native_color: clnG3dummy02:1 allocation score on srv03: 100
native_color: clnG3dummy02:1 allocation score on srv04: 0
native_color: clnG3dummy02:2 allocation score on srv01: 0
native_color: clnG3dummy02:2 allocation score on srv02: 0
native_color: clnG3dummy02:2 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:2 allocation score on srv04: 100
native_color: clnG3dummy02:3 allocation score on srv01: 100
native_color: clnG3dummy02:3 allocation score on srv02: 0
native_color: clnG3dummy02:3 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:3 allocation score on srv04: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv01: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv02: 100
native_color: clnPrmDiskd1:0 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv04: -INFINITY
native_color: clnPrmDiskd1:1 allocation score on srv01: 0
native_color: clnPrmDiskd1:1 allocation score on srv02: 0
native_color: clnPrmDiskd1:1 allocation score on srv03: 100
native_color: clnPrmDiskd1:1 allocation score on srv04: 0
native_color: clnPrmDiskd1:2 allocation score on srv01: 0
native_color: clnPrmDiskd1:2 allocation score on srv02: 0
native_color: clnPrmDiskd1:2 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:2 allocation score on srv04: 100
native_color: clnPrmDiskd1:3 allocation score on srv01: 100
native_color: clnPrmDiskd1:3 allocation score on srv02: 0
native_color: clnPrmDiskd1:3 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:3 allocation score on srv04: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv01: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv02: 100
native_color: clnPrmPingd:0 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv04: -INFINITY
native_color: clnPrmPingd:1 allocation score on srv01: 0
native_color: clnPrmPingd:1 allocation score on srv02: 0
native_color: clnPrmPingd:1 allocation score on srv03: 100
native_color: clnPrmPingd:1 allocation score on srv04: 0
native_color: clnPrmPingd:2 allocation score on srv01: 0
native_color: clnPrmPingd:2 allocation score on srv02: 0
native_color: clnPrmPingd:2 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:2 allocation score on srv04: 100
native_color: clnPrmPingd:3 allocation score on srv01: 100
native_color: clnPrmPingd:3 allocation score on srv02: 0
native_color: clnPrmPingd:3 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:3 allocation score on srv04: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv01: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
-native_color: clnUMdummy01:0 allocation score on srv04: 200
+native_color: clnUMdummy01:0 allocation score on srv04: 204
native_color: clnUMdummy01:1 allocation score on srv01: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv04: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv01: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv02: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv03: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv04: 100
native_color: clnUMdummy02:1 allocation score on srv01: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv02: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv03: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv04: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv01: 4300
native_color: prmExPostgreSQLDB1 allocation score on srv02: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv03: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv04: 4100
native_color: prmExPostgreSQLDB2 allocation score on srv01: -INFINITY
native_color: prmExPostgreSQLDB2 allocation score on srv02: 4300
native_color: prmExPostgreSQLDB2 allocation score on srv03: -INFINITY
native_color: prmExPostgreSQLDB2 allocation score on srv04: 4100
native_color: prmExPostgreSQLDB3 allocation score on srv01: -INFINITY
native_color: prmExPostgreSQLDB3 allocation score on srv02: -INFINITY
native_color: prmExPostgreSQLDB3 allocation score on srv03: 4300
native_color: prmExPostgreSQLDB3 allocation score on srv04: 4100
native_color: prmStonithN1 allocation score on srv01: -INFINITY
native_color: prmStonithN1 allocation score on srv02: 100
native_color: prmStonithN1 allocation score on srv03: 100
native_color: prmStonithN1 allocation score on srv04: 300
native_color: prmStonithN2 allocation score on srv01: 300
native_color: prmStonithN2 allocation score on srv02: -INFINITY
native_color: prmStonithN2 allocation score on srv03: 100
native_color: prmStonithN2 allocation score on srv04: 100
native_color: prmStonithN3 allocation score on srv01: 100
native_color: prmStonithN3 allocation score on srv02: 300
native_color: prmStonithN3 allocation score on srv03: -INFINITY
native_color: prmStonithN3 allocation score on srv04: 100
native_color: prmStonithN4 allocation score on srv01: 100
native_color: prmStonithN4 allocation score on srv02: 100
native_color: prmStonithN4 allocation score on srv03: 300
native_color: prmStonithN4 allocation score on srv04: -INFINITY
diff --git a/pengine/test10/colo_master_w_native.dot b/pengine/test10/colo_master_w_native.dot
new file mode 100644
index 0000000000..017abafc37
--- /dev/null
+++ b/pengine/test10/colo_master_w_native.dot
@@ -0,0 +1,63 @@
+ digraph "g" {
+"Cancel MS_RSC_NATIVE:1_monitor_15000 node1" -> "MS_RSC_NATIVE:1_promote_0 node1" [ style = bold]
+"Cancel MS_RSC_NATIVE:1_monitor_15000 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_demote_0 node2" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_NATIVE:0_demote_0 node2" -> "MS_RSC_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_monitor_15000 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_post_notify_demote_0 node2" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_post_notify_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_post_notify_promote_0 node2" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_post_notify_promote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_pre_notify_demote_0 node2" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_NATIVE:0_pre_notify_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_pre_notify_promote_0 node2" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_NATIVE:0_pre_notify_promote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_post_notify_demote_0 node1" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_post_notify_demote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_post_notify_promote_0 node1" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_post_notify_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_pre_notify_demote_0 node1" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_NATIVE:1_pre_notify_demote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_pre_notify_promote_0 node1" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_NATIVE:1_pre_notify_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_promote_0 node1" -> "MS_RSC_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_confirmed-post_notify_demoted_0" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_confirmed-post_notify_demoted_0" -> "MS_RSC_pre_notify_promote_0" [ style = bold]
+"MS_RSC_confirmed-post_notify_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-post_notify_promoted_0" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_confirmed-post_notify_promoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-pre_notify_demote_0" -> "MS_RSC_demote_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_demote_0" -> "MS_RSC_post_notify_demoted_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-pre_notify_promote_0" -> "MS_RSC_post_notify_promoted_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_promote_0" -> "MS_RSC_promote_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_demote_0" -> "MS_RSC_NATIVE:0_demote_0 node2" [ style = bold]
+"MS_RSC_demote_0" -> "MS_RSC_demoted_0" [ style = bold]
+"MS_RSC_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_demoted_0" -> "MS_RSC_post_notify_demoted_0" [ style = bold]
+"MS_RSC_demoted_0" -> "MS_RSC_promote_0" [ style = bold]
+"MS_RSC_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_NATIVE:0_post_notify_demote_0 node2" [ style = bold]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_NATIVE:1_post_notify_demote_0 node1" [ style = bold]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_post_notify_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_NATIVE:0_post_notify_promote_0 node2" [ style = bold]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_NATIVE:1_post_notify_promote_0 node1" [ style = bold]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_post_notify_promoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_NATIVE:0_pre_notify_demote_0 node2" [ style = bold]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_NATIVE:1_pre_notify_demote_0 node1" [ style = bold]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_pre_notify_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_NATIVE:0_pre_notify_promote_0 node2" [ style = bold]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_NATIVE:1_pre_notify_promote_0 node1" [ style = bold]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_pre_notify_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_promote_0" -> "MS_RSC_NATIVE:1_promote_0 node1" [ style = bold]
+"MS_RSC_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_promoted_0" -> "MS_RSC_post_notify_promoted_0" [ style = bold]
+"MS_RSC_promoted_0" [ style=bold color="green" fontcolor="orange"]
+}
diff --git a/pengine/test10/colo_master_w_native.exp b/pengine/test10/colo_master_w_native.exp
new file mode 100644
index 0000000000..c6c7d20a24
--- /dev/null
+++ b/pengine/test10/colo_master_w_native.exp
@@ -0,0 +1,340 @@
+<transition_graph cluster-delay="60s" stonith-timeout="60s" failed-stop-offset="INFINITY" failed-start-offset="INFINITY" batch-limit="30" transition_id="0">
+ <synapse id="0" priority="1000000">
+ <action_set>
+ <rsc_op id="57" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="38" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="1">
+ <action_set>
+ <rsc_op id="56" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="36" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="2" priority="1000000">
+ <action_set>
+ <rsc_op id="53" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_promote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="32" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="3">
+ <action_set>
+ <rsc_op id="52" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_promote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="30" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="4">
+ <action_set>
+ <rsc_op id="12" operation="monitor" operation_key="MS_RSC_NATIVE:0_monitor_15000" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_interval="15000" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_name="monitor" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="10" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="33" operation="notified" operation_key="MS_RSC_confirmed-post_notify_promoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="39" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="5">
+ <action_set>
+ <rsc_op id="10" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="34" operation="demote" operation_key="MS_RSC_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="6" priority="1000000">
+ <action_set>
+ <rsc_op id="59" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_demote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="38" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="7">
+ <action_set>
+ <rsc_op id="58" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_demote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="36" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="8" priority="1000000">
+ <action_set>
+ <rsc_op id="55" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="32" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="9">
+ <action_set>
+ <rsc_op id="54" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="30" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="10">
+ <action_set>
+ <rsc_op id="15" operation="promote" operation_key="MS_RSC_NATIVE:1_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="2" operation="cancel" operation_key="MS_RSC_NATIVE:1_monitor_15000" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="28" operation="promote" operation_key="MS_RSC_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="11">
+ <action_set>
+ <rsc_op id="2" operation="cancel" operation_key="MS_RSC_NATIVE:1_monitor_15000" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_interval="15000" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_name="monitor" CRM_meta_notify="true" CRM_meta_operation="monitor" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="12" priority="1000000">
+ <action_set>
+ <pseudo_event id="39" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="confirmed-post" CRM_meta_notify_operation="demote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="38" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="57" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="59" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_demote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="13" priority="1000000">
+ <action_set>
+ <pseudo_event id="38" operation="notify" operation_key="MS_RSC_post_notify_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_operation="demote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="35" operation="demoted" operation_key="MS_RSC_demoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="37" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="14">
+ <action_set>
+ <pseudo_event id="37" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="confirmed-pre" CRM_meta_notify_operation="demote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="36" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="56" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="58" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_demote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="15">
+ <action_set>
+ <pseudo_event id="36" operation="notify" operation_key="MS_RSC_pre_notify_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_operation="demote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="16" priority="1000000">
+ <action_set>
+ <pseudo_event id="35" operation="demoted" operation_key="MS_RSC_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="10" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="34" operation="demote" operation_key="MS_RSC_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="17">
+ <action_set>
+ <pseudo_event id="34" operation="demote" operation_key="MS_RSC_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="37" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="18" priority="1000000">
+ <action_set>
+ <pseudo_event id="33" operation="notified" operation_key="MS_RSC_confirmed-post_notify_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="confirmed-post" CRM_meta_notify_operation="promote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="32" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="53" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_promote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="55" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="19" priority="1000000">
+ <action_set>
+ <pseudo_event id="32" operation="notify" operation_key="MS_RSC_post_notify_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_operation="promote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="29" operation="promoted" operation_key="MS_RSC_promoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="31" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="20">
+ <action_set>
+ <pseudo_event id="31" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="confirmed-pre" CRM_meta_notify_operation="promote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="30" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="52" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_promote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="54" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="21">
+ <action_set>
+ <pseudo_event id="30" operation="notify" operation_key="MS_RSC_pre_notify_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_operation="promote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="39" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="22" priority="1000000">
+ <action_set>
+ <pseudo_event id="29" operation="promoted" operation_key="MS_RSC_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="15" operation="promote" operation_key="MS_RSC_NATIVE:1_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="23">
+ <action_set>
+ <pseudo_event id="28" operation="promote" operation_key="MS_RSC_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="31" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="35" operation="demoted" operation_key="MS_RSC_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+</transition_graph>
+
diff --git a/pengine/test10/colo_master_w_native.scores b/pengine/test10/colo_master_w_native.scores
new file mode 100644
index 0000000000..087963315b
--- /dev/null
+++ b/pengine/test10/colo_master_w_native.scores
@@ -0,0 +1,15 @@
+Allocation scores:
+MS_RSC_NATIVE:0 promotion score on node2: 10
+MS_RSC_NATIVE:1 promotion score on node1: INFINITY
+clone_color: MS_RSC allocation score on node1: 0
+clone_color: MS_RSC allocation score on node2: 0
+clone_color: MS_RSC_NATIVE:0 allocation score on node1: 0
+clone_color: MS_RSC_NATIVE:0 allocation score on node2: 11
+clone_color: MS_RSC_NATIVE:1 allocation score on node1: 6
+clone_color: MS_RSC_NATIVE:1 allocation score on node2: 0
+native_color: A allocation score on node1: 0
+native_color: A allocation score on node2: 0
+native_color: MS_RSC_NATIVE:0 allocation score on node1: 0
+native_color: MS_RSC_NATIVE:0 allocation score on node2: 11
+native_color: MS_RSC_NATIVE:1 allocation score on node1: 6
+native_color: MS_RSC_NATIVE:1 allocation score on node2: -INFINITY
diff --git a/pengine/test10/colo_master_w_native.summary b/pengine/test10/colo_master_w_native.summary
new file mode 100644
index 0000000000..ee12950647
--- /dev/null
+++ b/pengine/test10/colo_master_w_native.summary
@@ -0,0 +1,47 @@
+
+Current cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node1
+ Master/Slave Set: MS_RSC [MS_RSC_NATIVE]
+ Masters: [ node2 ]
+ Slaves: [ node1 ]
+
+Transition Summary:
+ * Demote MS_RSC_NATIVE:0 (Master -> Slave node2)
+ * Promote MS_RSC_NATIVE:1 (Slave -> Master node1)
+
+Executing cluster transition:
+ * Resource action: MS_RSC_NATIVE:1 cancel=15000 on node1
+ * Pseudo action: MS_RSC_pre_notify_demote_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-pre_notify_demote_0
+ * Pseudo action: MS_RSC_demote_0
+ * Resource action: MS_RSC_NATIVE:0 demote on node2
+ * Pseudo action: MS_RSC_demoted_0
+ * Pseudo action: MS_RSC_post_notify_demoted_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-post_notify_demoted_0
+ * Pseudo action: MS_RSC_pre_notify_promote_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-pre_notify_promote_0
+ * Pseudo action: MS_RSC_promote_0
+ * Resource action: MS_RSC_NATIVE:1 promote on node1
+ * Pseudo action: MS_RSC_promoted_0
+ * Pseudo action: MS_RSC_post_notify_promoted_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-post_notify_promoted_0
+ * Resource action: MS_RSC_NATIVE:0 monitor=15000 on node2
+
+Revised cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node1
+ Master/Slave Set: MS_RSC [MS_RSC_NATIVE]
+ Masters: [ node1 ]
+ Slaves: [ node2 ]
+
diff --git a/pengine/test10/colo_master_w_native.xml b/pengine/test10/colo_master_w_native.xml
new file mode 100644
index 0000000000..7be3c0fd05
--- /dev/null
+++ b/pengine/test10/colo_master_w_native.xml
@@ -0,0 +1,84 @@
+<cib epoch="9" num_updates="27" admin_epoch="0" validate-with="pacemaker-1.2" crm_feature_set="3.0.6" update-origin="node1" update-client="cibadmin" cib-last-written="Mon Jun 25 16:10:07 2012" have-quorum="1" dc-uuid="1031448768">
+ <configuration>
+ <crm_config>
+ <cluster_property_set id="cib-bootstrap-options">
+ <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.7-82fbb43"/>
+ <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
+ <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+ <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
+ </cluster_property_set>
+ </crm_config>
+ <nodes>
+ <node id="1048225984" type="normal" uname="node2"/>
+ <node id="1031448768" type="normal" uname="node1"/>
+ </nodes>
+ <resources>
+ <primitive class="ocf" id="A" provider="pacemaker" type="Dummy">
+ <operations>
+ <op id="A-monitor-10s" interval="10s" name="monitor"/>
+ </operations>
+ </primitive>
+ <master id="MS_RSC">
+ <meta_attributes id="ms_drbd_pgdrive-meta_attributes">
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-master-max" name="master-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-master-node-max" name="master-node-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-clone-max" name="clone-max" value="2"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-clone-node-max" name="clone-node-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-notify" name="notify" value="true"/>
+ </meta_attributes>
+ <primitive class="ocf" id="MS_RSC_NATIVE" provider="pacemaker" type="Stateful">
+ <operations>
+ <op id="drbd_pgdrive-start-0" interval="0" name="start" timeout="240"/>
+ <op id="drbd_pgdrive-stop-0" interval="0" name="stop" timeout="100"/>
+ <op id="drbd_pgdrive-monitor-15" interval="15" name="monitor"/>
+ </operations>
+ </primitive>
+ </master>
+ </resources>
+ <constraints>
+ <rsc_colocation id="ms_w_dummy" rsc="MS_RSC" rsc-role="Master" score="INFINITY" with-rsc="A"/>
+ </constraints>
+ </configuration>
+ <status>
+ <node_state id="1048225984" uname="node2" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1048225984">
+ <instance_attributes id="status-1048225984">
+ <nvpair id="status-1048225984-probe_complete" name="probe_complete" value="true"/>
+ <nvpair id="status-1048225984-master-MS_RSC_NATIVE.0" name="master-MS_RSC_NATIVE:0" value="10"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1048225984">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="4:3:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:7;4:3:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="5" rc-code="7" op-status="0" interval="0" last-run="1340658390" last-rc-change="1340658390" exec-time="303" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ <lrm_resource id="MS_RSC_NATIVE:0" type="Stateful" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="MS_RSC_NATIVE:0_post_notify_promote_0" operation_key="MS_RSC_NATIVE:0_notify_0" operation="notify" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="52:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;52:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="26" rc-code="0" op-status="0" interval="0" last-run="1340658544" last-rc-change="1340658544" exec-time="24" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:0_last_failure_0" operation_key="MS_RSC_NATIVE:0_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="6:7:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:8;6:7:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="29" rc-code="8" op-status="0" interval="0" last-run="1340658609" last-rc-change="1340658610" exec-time="275" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ <node_state id="1031448768" uname="node1" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1031448768">
+ <instance_attributes id="status-1031448768">
+ <nvpair id="status-1031448768-probe_complete" name="probe_complete" value="true"/>
+ <nvpair id="status-1031448768-master-MS_RSC_NATIVE.1" name="master-MS_RSC_NATIVE:1" value="5"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1031448768">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_start_0" operation="start" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="7:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;7:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="8" rc-code="0" op-status="0" interval="0" last-run="1340658390" last-rc-change="0" exec-time="21" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="A_monitor_10000" operation_key="A_monitor_10000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="8:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;8:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="11" rc-code="0" op-status="0" interval="10000" last-rc-change="0" exec-time="8" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ </lrm_resource>
+ <lrm_resource id="MS_RSC_NATIVE:1" type="Stateful" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_post_notify_promote_0" operation_key="MS_RSC_NATIVE:1_notify_0" operation="notify" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="54:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;54:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="29" rc-code="0" op-status="0" interval="0" last-run="1340658543" last-rc-change="1340658543" exec-time="64" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_monitor_15000" operation_key="MS_RSC_NATIVE:1_monitor_15000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="14:6:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;14:6:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="32" rc-code="0" op-status="0" interval="15000" last-rc-change="0" exec-time="16" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_pre_notify_start_0" operation_key="MS_RSC_NATIVE:1_notify_0" operation="notify" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="45:7:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;45:7:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="37" rc-code="0" op-status="0" interval="0" last-run="1340658609" last-rc-change="1340658609" exec-time="127" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ </status>
+</cib>
diff --git a/pengine/test10/colo_slave_w_native.dot b/pengine/test10/colo_slave_w_native.dot
new file mode 100644
index 0000000000..045dde63bd
--- /dev/null
+++ b/pengine/test10/colo_slave_w_native.dot
@@ -0,0 +1,70 @@
+ digraph "g" {
+"A_monitor_10000 node2" [ style=bold color="green" fontcolor="black"]
+"A_start_0 node2" -> "A_monitor_10000 node2" [ style = bold]
+"A_start_0 node2" [ style=bold color="green" fontcolor="black"]
+"A_stop_0 node1" -> "A_start_0 node2" [ style = bold]
+"A_stop_0 node1" -> "all_stopped" [ style = bold]
+"A_stop_0 node1" [ style=bold color="green" fontcolor="black"]
+"Cancel MS_RSC_NATIVE:1_monitor_15000 node1" -> "MS_RSC_NATIVE:1_promote_0 node1" [ style = bold]
+"Cancel MS_RSC_NATIVE:1_monitor_15000 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_demote_0 node2" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_NATIVE:0_demote_0 node2" -> "MS_RSC_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_monitor_15000 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_post_notify_demote_0 node2" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_post_notify_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_post_notify_promote_0 node2" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:0_post_notify_promote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_pre_notify_demote_0 node2" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_NATIVE:0_pre_notify_demote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:0_pre_notify_promote_0 node2" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_NATIVE:0_pre_notify_promote_0 node2" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_post_notify_demote_0 node1" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_post_notify_demote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_post_notify_promote_0 node1" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_post_notify_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_pre_notify_demote_0 node1" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_NATIVE:1_pre_notify_demote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_pre_notify_promote_0 node1" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_NATIVE:1_pre_notify_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_NATIVE:1_promote_0 node1" -> "MS_RSC_promoted_0" [ style = bold]
+"MS_RSC_NATIVE:1_promote_0 node1" [ style=bold color="green" fontcolor="black"]
+"MS_RSC_confirmed-post_notify_demoted_0" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_confirmed-post_notify_demoted_0" -> "MS_RSC_pre_notify_promote_0" [ style = bold]
+"MS_RSC_confirmed-post_notify_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-post_notify_promoted_0" -> "MS_RSC_NATIVE:0_monitor_15000 node2" [ style = bold]
+"MS_RSC_confirmed-post_notify_promoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-pre_notify_demote_0" -> "MS_RSC_demote_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_demote_0" -> "MS_RSC_post_notify_demoted_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_confirmed-pre_notify_promote_0" -> "MS_RSC_post_notify_promoted_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_promote_0" -> "MS_RSC_promote_0" [ style = bold]
+"MS_RSC_confirmed-pre_notify_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_demote_0" -> "MS_RSC_NATIVE:0_demote_0 node2" [ style = bold]
+"MS_RSC_demote_0" -> "MS_RSC_demoted_0" [ style = bold]
+"MS_RSC_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_demoted_0" -> "MS_RSC_post_notify_demoted_0" [ style = bold]
+"MS_RSC_demoted_0" -> "MS_RSC_promote_0" [ style = bold]
+"MS_RSC_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_NATIVE:0_post_notify_demote_0 node2" [ style = bold]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_NATIVE:1_post_notify_demote_0 node1" [ style = bold]
+"MS_RSC_post_notify_demoted_0" -> "MS_RSC_confirmed-post_notify_demoted_0" [ style = bold]
+"MS_RSC_post_notify_demoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_NATIVE:0_post_notify_promote_0 node2" [ style = bold]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_NATIVE:1_post_notify_promote_0 node1" [ style = bold]
+"MS_RSC_post_notify_promoted_0" -> "MS_RSC_confirmed-post_notify_promoted_0" [ style = bold]
+"MS_RSC_post_notify_promoted_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_NATIVE:0_pre_notify_demote_0 node2" [ style = bold]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_NATIVE:1_pre_notify_demote_0 node1" [ style = bold]
+"MS_RSC_pre_notify_demote_0" -> "MS_RSC_confirmed-pre_notify_demote_0" [ style = bold]
+"MS_RSC_pre_notify_demote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_NATIVE:0_pre_notify_promote_0 node2" [ style = bold]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_NATIVE:1_pre_notify_promote_0 node1" [ style = bold]
+"MS_RSC_pre_notify_promote_0" -> "MS_RSC_confirmed-pre_notify_promote_0" [ style = bold]
+"MS_RSC_pre_notify_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_promote_0" -> "MS_RSC_NATIVE:1_promote_0 node1" [ style = bold]
+"MS_RSC_promote_0" [ style=bold color="green" fontcolor="orange"]
+"MS_RSC_promoted_0" -> "MS_RSC_post_notify_promoted_0" [ style = bold]
+"MS_RSC_promoted_0" [ style=bold color="green" fontcolor="orange"]
+"all_stopped" [ style=bold color="green" fontcolor="orange"]
+}
diff --git a/pengine/test10/colo_slave_w_native.exp b/pengine/test10/colo_slave_w_native.exp
new file mode 100644
index 0000000000..a5f9ca6205
--- /dev/null
+++ b/pengine/test10/colo_slave_w_native.exp
@@ -0,0 +1,387 @@
+<transition_graph cluster-delay="60s" stonith-timeout="60s" failed-stop-offset="INFINITY" failed-start-offset="INFINITY" batch-limit="30" transition_id="0">
+ <synapse id="0">
+ <action_set>
+ <rsc_op id="9" operation="monitor" operation_key="A_monitor_10000" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_interval="10000" CRM_meta_name="monitor" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="8" operation="start" operation_key="A_start_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="1">
+ <action_set>
+ <rsc_op id="8" operation="start" operation_key="A_start_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="2">
+ <action_set>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="3" priority="1000000">
+ <action_set>
+ <rsc_op id="58" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="39" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="4">
+ <action_set>
+ <rsc_op id="57" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="37" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="5" priority="1000000">
+ <action_set>
+ <rsc_op id="54" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_promote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="33" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="6">
+ <action_set>
+ <rsc_op id="53" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_promote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="31" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="7">
+ <action_set>
+ <rsc_op id="13" operation="monitor" operation_key="MS_RSC_NATIVE:0_monitor_15000" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_interval="15000" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_name="monitor" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="11" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="34" operation="notified" operation_key="MS_RSC_confirmed-post_notify_promoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="40" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="8">
+ <action_set>
+ <rsc_op id="11" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:0" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="0" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="35" operation="demote" operation_key="MS_RSC_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="9" priority="1000000">
+ <action_set>
+ <rsc_op id="60" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_demote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="39" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="10">
+ <action_set>
+ <rsc_op id="59" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_demote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="demote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="37" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="11" priority="1000000">
+ <action_set>
+ <rsc_op id="56" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="33" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="12">
+ <action_set>
+ <rsc_op id="55" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_operation="promote" CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="31" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="13">
+ <action_set>
+ <rsc_op id="16" operation="promote" operation_key="MS_RSC_NATIVE:1_promote_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_active_resource=" " CRM_meta_notify_active_uname=" " CRM_meta_notify_demote_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_demote_uname="node2 " CRM_meta_notify_inactive_resource=" " CRM_meta_notify_master_resource="MS_RSC_NATIVE:0 " CRM_meta_notify_master_uname="node2 " CRM_meta_notify_promote_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_promote_uname="node1 " CRM_meta_notify_slave_resource="MS_RSC_NATIVE:1 " CRM_meta_notify_slave_uname="node1 " CRM_meta_notify_start_resource=" " CRM_meta_notify_start_uname=" " CRM_meta_notify_stop_resource=" " CRM_meta_notify_stop_uname=" " CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="2" operation="cancel" operation_key="MS_RSC_NATIVE:1_monitor_15000" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="29" operation="promote" operation_key="MS_RSC_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="14">
+ <action_set>
+ <rsc_op id="2" operation="cancel" operation_key="MS_RSC_NATIVE:1_monitor_15000" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="MS_RSC_NATIVE" long-id="MS_RSC_NATIVE:1" class="ocf" provider="pacemaker" type="Stateful"/>
+ <attributes CRM_meta_clone="1" CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_interval="15000" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_name="monitor" CRM_meta_notify="true" CRM_meta_operation="monitor" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="15" priority="1000000">
+ <action_set>
+ <pseudo_event id="40" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="confirmed-post" CRM_meta_notify_operation="demote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="39" operation="notify" operation_key="MS_RSC_post_notify_demoted_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="58" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="60" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_demote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="16" priority="1000000">
+ <action_set>
+ <pseudo_event id="39" operation="notify" operation_key="MS_RSC_post_notify_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demoted" CRM_meta_notify_key_type="post" CRM_meta_notify_operation="demote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="36" operation="demoted" operation_key="MS_RSC_demoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="38" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="17">
+ <action_set>
+ <pseudo_event id="38" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="confirmed-pre" CRM_meta_notify_operation="demote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="37" operation="notify" operation_key="MS_RSC_pre_notify_demote_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="57" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="59" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_demote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="18">
+ <action_set>
+ <pseudo_event id="37" operation="notify" operation_key="MS_RSC_pre_notify_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="demote" CRM_meta_notify_key_type="pre" CRM_meta_notify_operation="demote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="19" priority="1000000">
+ <action_set>
+ <pseudo_event id="36" operation="demoted" operation_key="MS_RSC_demoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="11" operation="demote" operation_key="MS_RSC_NATIVE:0_demote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="35" operation="demote" operation_key="MS_RSC_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="20">
+ <action_set>
+ <pseudo_event id="35" operation="demote" operation_key="MS_RSC_demote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="38" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_demote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="21" priority="1000000">
+ <action_set>
+ <pseudo_event id="34" operation="notified" operation_key="MS_RSC_confirmed-post_notify_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="confirmed-post" CRM_meta_notify_operation="promote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="33" operation="notify" operation_key="MS_RSC_post_notify_promoted_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="54" operation="notify" operation_key="MS_RSC_NATIVE:0_post_notify_promote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="56" operation="notify" operation_key="MS_RSC_NATIVE:1_post_notify_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="22" priority="1000000">
+ <action_set>
+ <pseudo_event id="33" operation="notify" operation_key="MS_RSC_post_notify_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promoted" CRM_meta_notify_key_type="post" CRM_meta_notify_operation="promote" CRM_meta_notify_type="post" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="30" operation="promoted" operation_key="MS_RSC_promoted_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="32" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="23">
+ <action_set>
+ <pseudo_event id="32" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="confirmed-pre" CRM_meta_notify_operation="promote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="31" operation="notify" operation_key="MS_RSC_pre_notify_promote_0"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="53" operation="notify" operation_key="MS_RSC_NATIVE:0_pre_notify_promote_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ <trigger>
+ <rsc_op id="55" operation="notify" operation_key="MS_RSC_NATIVE:1_pre_notify_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="24">
+ <action_set>
+ <pseudo_event id="31" operation="notify" operation_key="MS_RSC_pre_notify_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_notify_key_operation="promote" CRM_meta_notify_key_type="pre" CRM_meta_notify_operation="promote" CRM_meta_notify_type="pre" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="40" operation="notified" operation_key="MS_RSC_confirmed-post_notify_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="25" priority="1000000">
+ <action_set>
+ <pseudo_event id="30" operation="promoted" operation_key="MS_RSC_promoted_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="16" operation="promote" operation_key="MS_RSC_NATIVE:1_promote_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="26">
+ <action_set>
+ <pseudo_event id="29" operation="promote" operation_key="MS_RSC_promote_0">
+ <attributes CRM_meta_clone_max="2" CRM_meta_clone_node_max="1" CRM_meta_globally_unique="false" CRM_meta_master_max="1" CRM_meta_master_node_max="1" CRM_meta_notify="true" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <pseudo_event id="32" operation="notified" operation_key="MS_RSC_confirmed-pre_notify_promote_0"/>
+ </trigger>
+ <trigger>
+ <pseudo_event id="36" operation="demoted" operation_key="MS_RSC_demoted_0"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="27">
+ <action_set>
+ <pseudo_event id="3" operation="all_stopped" operation_key="all_stopped">
+ <attributes crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+</transition_graph>
+
diff --git a/pengine/test10/colo_slave_w_native.scores b/pengine/test10/colo_slave_w_native.scores
new file mode 100644
index 0000000000..1cb0071994
--- /dev/null
+++ b/pengine/test10/colo_slave_w_native.scores
@@ -0,0 +1,15 @@
+Allocation scores:
+MS_RSC_NATIVE:0 promotion score on node2: -INFINITY
+MS_RSC_NATIVE:1 promotion score on node1: 5
+clone_color: MS_RSC allocation score on node1: 0
+clone_color: MS_RSC allocation score on node2: 0
+clone_color: MS_RSC_NATIVE:0 allocation score on node1: 0
+clone_color: MS_RSC_NATIVE:0 allocation score on node2: 11
+clone_color: MS_RSC_NATIVE:1 allocation score on node1: 6
+clone_color: MS_RSC_NATIVE:1 allocation score on node2: 0
+native_color: A allocation score on node1: 0
+native_color: A allocation score on node2: 5000
+native_color: MS_RSC_NATIVE:0 allocation score on node1: 0
+native_color: MS_RSC_NATIVE:0 allocation score on node2: 11
+native_color: MS_RSC_NATIVE:1 allocation score on node1: 6
+native_color: MS_RSC_NATIVE:1 allocation score on node2: -INFINITY
diff --git a/pengine/test10/colo_slave_w_native.summary b/pengine/test10/colo_slave_w_native.summary
new file mode 100644
index 0000000000..2f0f644447
--- /dev/null
+++ b/pengine/test10/colo_slave_w_native.summary
@@ -0,0 +1,52 @@
+
+Current cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node1
+ Master/Slave Set: MS_RSC [MS_RSC_NATIVE]
+ Masters: [ node2 ]
+ Slaves: [ node1 ]
+
+Transition Summary:
+ * Move A (Started node1 -> node2)
+ * Demote MS_RSC_NATIVE:0 (Master -> Slave node2)
+ * Promote MS_RSC_NATIVE:1 (Slave -> Master node1)
+
+Executing cluster transition:
+ * Resource action: A stop on node1
+ * Resource action: MS_RSC_NATIVE:1 cancel=15000 on node1
+ * Pseudo action: MS_RSC_pre_notify_demote_0
+ * Pseudo action: all_stopped
+ * Resource action: A start on node2
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-pre_notify_demote_0
+ * Pseudo action: MS_RSC_demote_0
+ * Resource action: A monitor=10000 on node2
+ * Resource action: MS_RSC_NATIVE:0 demote on node2
+ * Pseudo action: MS_RSC_demoted_0
+ * Pseudo action: MS_RSC_post_notify_demoted_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-post_notify_demoted_0
+ * Pseudo action: MS_RSC_pre_notify_promote_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-pre_notify_promote_0
+ * Pseudo action: MS_RSC_promote_0
+ * Resource action: MS_RSC_NATIVE:1 promote on node1
+ * Pseudo action: MS_RSC_promoted_0
+ * Pseudo action: MS_RSC_post_notify_promoted_0
+ * Resource action: MS_RSC_NATIVE:0 notify on node2
+ * Resource action: MS_RSC_NATIVE:1 notify on node1
+ * Pseudo action: MS_RSC_confirmed-post_notify_promoted_0
+ * Resource action: MS_RSC_NATIVE:0 monitor=15000 on node2
+
+Revised cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node2
+ Master/Slave Set: MS_RSC [MS_RSC_NATIVE]
+ Masters: [ node1 ]
+ Slaves: [ node2 ]
+
diff --git a/pengine/test10/colo_slave_w_native.xml b/pengine/test10/colo_slave_w_native.xml
new file mode 100644
index 0000000000..41ff3133c5
--- /dev/null
+++ b/pengine/test10/colo_slave_w_native.xml
@@ -0,0 +1,85 @@
+<cib epoch="9" num_updates="27" admin_epoch="0" validate-with="pacemaker-1.2" crm_feature_set="3.0.6" update-origin="node1" update-client="cibadmin" cib-last-written="Mon Jun 25 16:10:07 2012" have-quorum="1" dc-uuid="1031448768">
+ <configuration>
+ <crm_config>
+ <cluster_property_set id="cib-bootstrap-options">
+ <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.7-82fbb43"/>
+ <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
+ <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+ <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
+ </cluster_property_set>
+ </crm_config>
+ <nodes>
+ <node id="1048225984" type="normal" uname="node2"/>
+ <node id="1031448768" type="normal" uname="node1"/>
+ </nodes>
+ <resources>
+ <primitive class="ocf" id="A" provider="pacemaker" type="Dummy">
+ <operations>
+ <op id="A-monitor-10s" interval="10s" name="monitor"/>
+ </operations>
+ </primitive>
+ <master id="MS_RSC">
+ <meta_attributes id="ms_drbd_pgdrive-meta_attributes">
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-master-max" name="master-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-master-node-max" name="master-node-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-clone-max" name="clone-max" value="2"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-clone-node-max" name="clone-node-max" value="1"/>
+ <nvpair id="ms_drbd_pgdrive-meta_attributes-notify" name="notify" value="true"/>
+ </meta_attributes>
+ <primitive class="ocf" id="MS_RSC_NATIVE" provider="pacemaker" type="Stateful">
+ <operations>
+ <op id="drbd_pgdrive-start-0" interval="0" name="start" timeout="240"/>
+ <op id="drbd_pgdrive-stop-0" interval="0" name="stop" timeout="100"/>
+ <op id="drbd_pgdrive-monitor-15" interval="15" name="monitor"/>
+ </operations>
+ </primitive>
+ </master>
+ </resources>
+ <constraints>
+ <rsc_location id="loc1" rsc="A" node="node2" score="5000" />
+ <rsc_colocation id="ms_w_dummy" rsc="MS_RSC" rsc-role="Slave" score="INFINITY" with-rsc="A"/>
+ </constraints>
+ </configuration>
+ <status>
+ <node_state id="1048225984" uname="node2" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1048225984">
+ <instance_attributes id="status-1048225984">
+ <nvpair id="status-1048225984-probe_complete" name="probe_complete" value="true"/>
+ <nvpair id="status-1048225984-master-MS_RSC_NATIVE.0" name="master-MS_RSC_NATIVE:0" value="10"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1048225984">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="4:3:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:7;4:3:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="5" rc-code="7" op-status="0" interval="0" last-run="1340658390" last-rc-change="1340658390" exec-time="303" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ <lrm_resource id="MS_RSC_NATIVE:0" type="Stateful" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="MS_RSC_NATIVE:0_post_notify_promote_0" operation_key="MS_RSC_NATIVE:0_notify_0" operation="notify" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="52:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;52:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="26" rc-code="0" op-status="0" interval="0" last-run="1340658544" last-rc-change="1340658544" exec-time="24" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:0_last_failure_0" operation_key="MS_RSC_NATIVE:0_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="6:7:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:8;6:7:7:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="29" rc-code="8" op-status="0" interval="0" last-run="1340658609" last-rc-change="1340658610" exec-time="275" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ <node_state id="1031448768" uname="node1" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1031448768">
+ <instance_attributes id="status-1031448768">
+ <nvpair id="status-1031448768-probe_complete" name="probe_complete" value="true"/>
+ <nvpair id="status-1031448768-master-MS_RSC_NATIVE.1" name="master-MS_RSC_NATIVE:1" value="5"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1031448768">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_start_0" operation="start" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="7:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;7:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="8" rc-code="0" op-status="0" interval="0" last-run="1340658390" last-rc-change="0" exec-time="21" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="A_monitor_10000" operation_key="A_monitor_10000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="8:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;8:3:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="11" rc-code="0" op-status="0" interval="10000" last-rc-change="0" exec-time="8" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ </lrm_resource>
+ <lrm_resource id="MS_RSC_NATIVE:1" type="Stateful" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_post_notify_promote_0" operation_key="MS_RSC_NATIVE:1_notify_0" operation="notify" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="54:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;54:5:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="29" rc-code="0" op-status="0" interval="0" last-run="1340658543" last-rc-change="1340658543" exec-time="64" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_monitor_15000" operation_key="MS_RSC_NATIVE:1_monitor_15000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.0.6" transition-key="14:6:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;14:6:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="32" rc-code="0" op-status="0" interval="15000" last-rc-change="0" exec-time="16" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ <lrm_rsc_op id="MS_RSC_NATIVE:1_pre_notify_start_0" operation_key="MS_RSC_NATIVE:1_notify_0" operation="notify" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="45:7:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" transition-magic="0:0;45:7:0:07f842b7-036e-4af3-bfee-413b9fbc5d29" call-id="37" rc-code="0" op-status="0" interval="0" last-run="1340658609" last-rc-change="1340658609" exec-time="127" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ </status>
+</cib>
diff --git a/pengine/test10/coloc_fp_logic.dot b/pengine/test10/coloc_fp_logic.dot
new file mode 100644
index 0000000000..5a900e4ae6
--- /dev/null
+++ b/pengine/test10/coloc_fp_logic.dot
@@ -0,0 +1,9 @@
+ digraph "g" {
+"A_monitor_10000 node2" [ style=bold color="green" fontcolor="black"]
+"A_start_0 node2" -> "A_monitor_10000 node2" [ style = bold]
+"A_start_0 node2" [ style=bold color="green" fontcolor="black"]
+"A_stop_0 node1" -> "A_start_0 node2" [ style = bold]
+"A_stop_0 node1" -> "all_stopped" [ style = bold]
+"A_stop_0 node1" [ style=bold color="green" fontcolor="black"]
+"all_stopped" [ style=bold color="green" fontcolor="orange"]
+}
diff --git a/pengine/test10/coloc_fp_logic.exp b/pengine/test10/coloc_fp_logic.exp
new file mode 100644
index 0000000000..c94e40e4a7
--- /dev/null
+++ b/pengine/test10/coloc_fp_logic.exp
@@ -0,0 +1,50 @@
+<transition_graph cluster-delay="60s" stonith-timeout="60s" failed-stop-offset="INFINITY" failed-start-offset="INFINITY" batch-limit="30" transition_id="0">
+ <synapse id="0">
+ <action_set>
+ <rsc_op id="9" operation="monitor" operation_key="A_monitor_10000" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_interval="10000" CRM_meta_name="monitor" CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="8" operation="start" operation_key="A_start_0" on_node="node2" on_node_uuid="1048225984"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="1">
+ <action_set>
+ <rsc_op id="8" operation="start" operation_key="A_start_0" on_node="node2" on_node_uuid="1048225984">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+ <synapse id="2">
+ <action_set>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768">
+ <primitive id="A" class="ocf" provider="pacemaker" type="Dummy"/>
+ <attributes CRM_meta_timeout="20000" crm_feature_set="3.0.6"/>
+ </rsc_op>
+ </action_set>
+ <inputs/>
+ </synapse>
+ <synapse id="3">
+ <action_set>
+ <pseudo_event id="3" operation="all_stopped" operation_key="all_stopped">
+ <attributes crm_feature_set="3.0.6"/>
+ </pseudo_event>
+ </action_set>
+ <inputs>
+ <trigger>
+ <rsc_op id="7" operation="stop" operation_key="A_stop_0" on_node="node1" on_node_uuid="1031448768"/>
+ </trigger>
+ </inputs>
+ </synapse>
+</transition_graph>
+
diff --git a/pengine/test10/coloc_fp_logic.scores b/pengine/test10/coloc_fp_logic.scores
new file mode 100644
index 0000000000..c8fa648223
--- /dev/null
+++ b/pengine/test10/coloc_fp_logic.scores
@@ -0,0 +1,5 @@
+Allocation scores:
+native_color: A allocation score on node1: 100
+native_color: A allocation score on node2: 60000
+native_color: B allocation score on node1: 6
+native_color: B allocation score on node2: 100
diff --git a/pengine/test10/coloc_fp_logic.summary b/pengine/test10/coloc_fp_logic.summary
new file mode 100644
index 0000000000..b783c66bfc
--- /dev/null
+++ b/pengine/test10/coloc_fp_logic.summary
@@ -0,0 +1,22 @@
+
+Current cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node1
+ B (ocf::pacemaker:Dummy): Started node2
+
+Transition Summary:
+ * Move A (Started node1 -> node2)
+
+Executing cluster transition:
+ * Resource action: A stop on node1
+ * Pseudo action: all_stopped
+ * Resource action: A start on node2
+ * Resource action: A monitor=10000 on node2
+
+Revised cluster status:
+Online: [ node2 node1 ]
+
+ A (ocf::pacemaker:Dummy): Started node2
+ B (ocf::pacemaker:Dummy): Started node2
+
diff --git a/pengine/test10/coloc_fp_logic.xml b/pengine/test10/coloc_fp_logic.xml
new file mode 100644
index 0000000000..c84c817edf
--- /dev/null
+++ b/pengine/test10/coloc_fp_logic.xml
@@ -0,0 +1,74 @@
+<cib epoch="8" num_updates="30" admin_epoch="0" validate-with="pacemaker-1.2" crm_feature_set="3.0.6" update-origin="node1" update-client="cibadmin" cib-last-written="Tue Jul 3 14:15:52 2012" have-quorum="1" dc-uuid="1048225984">
+ <configuration>
+ <crm_config>
+ <cluster_property_set id="cib-bootstrap-options">
+ <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.7-1a62592"/>
+ <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
+ <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+ <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
+ </cluster_property_set>
+ </crm_config>
+ <nodes>
+ <node id="1048225984" type="normal" uname="node2"/>
+ <node id="1031448768" type="normal" uname="node1"/>
+ </nodes>
+ <resources>
+ <primitive class="ocf" id="A" provider="pacemaker" type="Dummy">
+ <operations>
+ <op id="A-monitor-10s" interval="10s" name="monitor"/>
+ </operations>
+ </primitive>
+ <primitive class="ocf" id="B" provider="pacemaker" type="Dummy">
+ <operations>
+ <op id="B-monitor-10s" interval="10s" name="monitor"/>
+ </operations>
+ </primitive>
+ </resources>
+ <constraints>
+ <rsc_colocation id="colo" rsc="A" score="60000" with-rsc="B"/>
+ </constraints>
+ <rsc_defaults>
+ <meta_attributes id="rsc-options">
+ <nvpair id="rsc-options-resource-stickiness" name="resource-stickiness" value="100"/>
+ </meta_attributes>
+ </rsc_defaults>
+ </configuration>
+ <status>
+ <node_state id="1048225984" uname="node2" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1048225984">
+ <instance_attributes id="status-1048225984">
+ <nvpair id="status-1048225984-probe_complete" name="probe_complete" value="true"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1048225984">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="4:1:7:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:7;4:1:7:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="5" rc-code="7" op-status="0" interval="0" last-run="1341342952" last-rc-change="1341342953" exec-time="214" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ <lrm_resource id="B" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="B_last_0" operation_key="B_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="11:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:0;11:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="14" rc-code="0" op-status="0" interval="0" last-run="1341342954" last-rc-change="0" exec-time="30" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="B_monitor_10000" operation_key="B_monitor_10000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="12:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:0;12:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="17" rc-code="0" op-status="0" interval="10000" last-rc-change="0" exec-time="29" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ <node_state id="1031448768" uname="node1" ha="active" in_ccm="true" crmd="online" join="member" expected="member" crm-debug-origin="do_update_resource" shutdown="0">
+ <transient_attributes id="1031448768">
+ <instance_attributes id="status-1031448768">
+ <nvpair id="status-1031448768-probe_complete" name="probe_complete" value="true"/>
+ </instance_attributes>
+ </transient_attributes>
+ <lrm id="1031448768">
+ <lrm_resources>
+ <lrm_resource id="A" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="A_last_0" operation_key="A_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="9:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:0;9:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="14" rc-code="0" op-status="0" interval="0" last-run="1341342953" last-rc-change="0" exec-time="14" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ <lrm_rsc_op id="A_monitor_10000" operation_key="A_monitor_10000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="10:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:0;10:1:0:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="17" rc-code="0" op-status="0" interval="10000" last-rc-change="0" exec-time="11" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd"/>
+ </lrm_resource>
+ <lrm_resource id="B" type="Dummy" class="ocf" provider="pacemaker">
+ <lrm_rsc_op id="B_last_0" operation_key="B_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="8:1:7:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" transition-magic="0:7;8:1:7:03e4bb5f-f762-43ae-a1b0-d2319b3a598c" call-id="10" rc-code="7" op-status="0" interval="0" last-run="1341342952" last-rc-change="1341342952" exec-time="20" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" state op_sleep " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
+ </lrm_resource>
+ </lrm_resources>
+ </lrm>
+ </node_state>
+ </status>
+</cib>
diff --git a/pengine/test10/colocate-primitive-with-clone.scores b/pengine/test10/colocate-primitive-with-clone.scores
index eb6d600777..413cc92e64 100644
--- a/pengine/test10/colocate-primitive-with-clone.scores
+++ b/pengine/test10/colocate-primitive-with-clone.scores
@@ -1,453 +1,453 @@
Allocation scores:
clone_color: clnDiskd1 allocation score on srv01: 0
-clone_color: clnDiskd1 allocation score on srv02: 500
-clone_color: clnDiskd1 allocation score on srv03: 500
+clone_color: clnDiskd1 allocation score on srv02: 1
+clone_color: clnDiskd1 allocation score on srv03: 1
clone_color: clnDiskd1 allocation score on srv04: 500
clone_color: clnG3dummy01:0 allocation score on srv01: 0
clone_color: clnG3dummy01:0 allocation score on srv02: 100
clone_color: clnG3dummy01:0 allocation score on srv03: 0
clone_color: clnG3dummy01:0 allocation score on srv04: 0
clone_color: clnG3dummy01:1 allocation score on srv01: 0
clone_color: clnG3dummy01:1 allocation score on srv02: 0
clone_color: clnG3dummy01:1 allocation score on srv03: 100
clone_color: clnG3dummy01:1 allocation score on srv04: 0
clone_color: clnG3dummy01:2 allocation score on srv01: 0
clone_color: clnG3dummy01:2 allocation score on srv02: 0
clone_color: clnG3dummy01:2 allocation score on srv03: 0
clone_color: clnG3dummy01:2 allocation score on srv04: 100
clone_color: clnG3dummy01:3 allocation score on srv01: 0
clone_color: clnG3dummy01:3 allocation score on srv02: 0
clone_color: clnG3dummy01:3 allocation score on srv03: 0
clone_color: clnG3dummy01:3 allocation score on srv04: 0
clone_color: clnG3dummy02:0 allocation score on srv01: 0
clone_color: clnG3dummy02:0 allocation score on srv02: 100
clone_color: clnG3dummy02:0 allocation score on srv03: 0
clone_color: clnG3dummy02:0 allocation score on srv04: 0
clone_color: clnG3dummy02:1 allocation score on srv01: 0
clone_color: clnG3dummy02:1 allocation score on srv02: 0
clone_color: clnG3dummy02:1 allocation score on srv03: 100
clone_color: clnG3dummy02:1 allocation score on srv04: 0
clone_color: clnG3dummy02:2 allocation score on srv01: 0
clone_color: clnG3dummy02:2 allocation score on srv02: 0
clone_color: clnG3dummy02:2 allocation score on srv03: 0
clone_color: clnG3dummy02:2 allocation score on srv04: 100
clone_color: clnG3dummy02:3 allocation score on srv01: 0
clone_color: clnG3dummy02:3 allocation score on srv02: 0
clone_color: clnG3dummy02:3 allocation score on srv03: 0
clone_color: clnG3dummy02:3 allocation score on srv04: 0
clone_color: clnG3dummy1 allocation score on srv01: 0
-clone_color: clnG3dummy1 allocation score on srv02: 500
-clone_color: clnG3dummy1 allocation score on srv03: 500
+clone_color: clnG3dummy1 allocation score on srv02: 1
+clone_color: clnG3dummy1 allocation score on srv03: 1
clone_color: clnG3dummy1 allocation score on srv04: 500
clone_color: clnG3dummy2 allocation score on srv01: 0
-clone_color: clnG3dummy2 allocation score on srv02: 500
-clone_color: clnG3dummy2 allocation score on srv03: 500
+clone_color: clnG3dummy2 allocation score on srv02: 1
+clone_color: clnG3dummy2 allocation score on srv03: 1
clone_color: clnG3dummy2 allocation score on srv04: 500
clone_color: clnPingd allocation score on srv01: 0
-clone_color: clnPingd allocation score on srv02: 500
-clone_color: clnPingd allocation score on srv03: 500
+clone_color: clnPingd allocation score on srv02: 1
+clone_color: clnPingd allocation score on srv03: 1
clone_color: clnPingd allocation score on srv04: 500
clone_color: clnPrmDiskd1:0 allocation score on srv01: 0
clone_color: clnPrmDiskd1:0 allocation score on srv02: 100
clone_color: clnPrmDiskd1:0 allocation score on srv03: 0
clone_color: clnPrmDiskd1:0 allocation score on srv04: 0
clone_color: clnPrmDiskd1:1 allocation score on srv01: 0
clone_color: clnPrmDiskd1:1 allocation score on srv02: 0
clone_color: clnPrmDiskd1:1 allocation score on srv03: 100
clone_color: clnPrmDiskd1:1 allocation score on srv04: 0
clone_color: clnPrmDiskd1:2 allocation score on srv01: 0
clone_color: clnPrmDiskd1:2 allocation score on srv02: 0
clone_color: clnPrmDiskd1:2 allocation score on srv03: 0
clone_color: clnPrmDiskd1:2 allocation score on srv04: 100
clone_color: clnPrmDiskd1:3 allocation score on srv01: 0
clone_color: clnPrmDiskd1:3 allocation score on srv02: 0
clone_color: clnPrmDiskd1:3 allocation score on srv03: 0
clone_color: clnPrmDiskd1:3 allocation score on srv04: 0
clone_color: clnPrmPingd:0 allocation score on srv01: 0
clone_color: clnPrmPingd:0 allocation score on srv02: 100
clone_color: clnPrmPingd:0 allocation score on srv03: 0
clone_color: clnPrmPingd:0 allocation score on srv04: 0
clone_color: clnPrmPingd:1 allocation score on srv01: 0
clone_color: clnPrmPingd:1 allocation score on srv02: 0
clone_color: clnPrmPingd:1 allocation score on srv03: 100
clone_color: clnPrmPingd:1 allocation score on srv04: 0
clone_color: clnPrmPingd:2 allocation score on srv01: 0
clone_color: clnPrmPingd:2 allocation score on srv02: 0
clone_color: clnPrmPingd:2 allocation score on srv03: 0
clone_color: clnPrmPingd:2 allocation score on srv04: 100
clone_color: clnPrmPingd:3 allocation score on srv01: 0
clone_color: clnPrmPingd:3 allocation score on srv02: 0
clone_color: clnPrmPingd:3 allocation score on srv03: 0
clone_color: clnPrmPingd:3 allocation score on srv04: 0
clone_color: clnUMdummy01:0 allocation score on srv01: 0
clone_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
clone_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
clone_color: clnUMdummy01:0 allocation score on srv04: 100
clone_color: clnUMdummy01:1 allocation score on srv01: 0
clone_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
clone_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
clone_color: clnUMdummy01:1 allocation score on srv04: 0
clone_color: clnUMdummy02:0 allocation score on srv01: 0
clone_color: clnUMdummy02:0 allocation score on srv02: 0
clone_color: clnUMdummy02:0 allocation score on srv03: 0
clone_color: clnUMdummy02:0 allocation score on srv04: 100
clone_color: clnUMdummy02:1 allocation score on srv01: 0
clone_color: clnUMdummy02:1 allocation score on srv02: 0
clone_color: clnUMdummy02:1 allocation score on srv03: 0
clone_color: clnUMdummy02:1 allocation score on srv04: 0
clone_color: clnUMgroup01 allocation score on srv01: 0
clone_color: clnUMgroup01 allocation score on srv02: -INFINITY
clone_color: clnUMgroup01 allocation score on srv03: -INFINITY
clone_color: clnUMgroup01 allocation score on srv04: 0
clone_color: clnUmResource:0 allocation score on srv01: 0
clone_color: clnUmResource:0 allocation score on srv02: -INFINITY
clone_color: clnUmResource:0 allocation score on srv03: -INFINITY
clone_color: clnUmResource:0 allocation score on srv04: 0
clone_color: clnUmResource:1 allocation score on srv01: 0
clone_color: clnUmResource:1 allocation score on srv02: -INFINITY
clone_color: clnUmResource:1 allocation score on srv03: -INFINITY
clone_color: clnUmResource:1 allocation score on srv04: 0
group_color: OVDBgroup02-1 allocation score on srv01: -INFINITY
group_color: OVDBgroup02-1 allocation score on srv02: -INFINITY
group_color: OVDBgroup02-1 allocation score on srv03: -INFINITY
group_color: OVDBgroup02-1 allocation score on srv04: 100
group_color: OVDBgroup02-2 allocation score on srv01: -INFINITY
group_color: OVDBgroup02-2 allocation score on srv02: 200
group_color: OVDBgroup02-2 allocation score on srv03: -INFINITY
group_color: OVDBgroup02-2 allocation score on srv04: 100
group_color: OVDBgroup02-3 allocation score on srv01: -INFINITY
group_color: OVDBgroup02-3 allocation score on srv02: -INFINITY
group_color: OVDBgroup02-3 allocation score on srv03: 200
group_color: OVDBgroup02-3 allocation score on srv04: 100
group_color: UMgroup01 allocation score on srv01: -INFINITY
group_color: UMgroup01 allocation score on srv02: -INFINITY
group_color: UMgroup01 allocation score on srv03: -INFINITY
group_color: UMgroup01 allocation score on srv04: 100
group_color: UmDummy01 allocation score on srv01: 0
group_color: UmDummy01 allocation score on srv02: 0
group_color: UmDummy01 allocation score on srv03: 0
group_color: UmDummy01 allocation score on srv04: 0
group_color: UmDummy02 allocation score on srv01: 0
group_color: UmDummy02 allocation score on srv02: 0
group_color: UmDummy02 allocation score on srv03: 0
group_color: UmDummy02 allocation score on srv04: 0
group_color: UmIPaddr allocation score on srv01: 0
group_color: UmIPaddr allocation score on srv02: 0
group_color: UmIPaddr allocation score on srv03: 0
group_color: UmIPaddr allocation score on srv04: 0
group_color: UmVIPcheck allocation score on srv01: -INFINITY
group_color: UmVIPcheck allocation score on srv02: -INFINITY
group_color: UmVIPcheck allocation score on srv03: -INFINITY
group_color: UmVIPcheck allocation score on srv04: 100
group_color: clnUMdummy01:0 allocation score on srv01: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
group_color: clnUMdummy01:0 allocation score on srv04: 100
group_color: clnUMdummy01:1 allocation score on srv01: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
group_color: clnUMdummy01:1 allocation score on srv04: -INFINITY
group_color: clnUMdummy02:0 allocation score on srv01: -INFINITY
group_color: clnUMdummy02:0 allocation score on srv02: 0
group_color: clnUMdummy02:0 allocation score on srv03: 0
group_color: clnUMdummy02:0 allocation score on srv04: 100
group_color: clnUMdummy02:1 allocation score on srv01: -INFINITY
group_color: clnUMdummy02:1 allocation score on srv02: 0
group_color: clnUMdummy02:1 allocation score on srv03: 0
group_color: clnUMdummy02:1 allocation score on srv04: -INFINITY
group_color: clnUmResource:0 allocation score on srv01: -INFINITY
group_color: clnUmResource:0 allocation score on srv02: -INFINITY
group_color: clnUmResource:0 allocation score on srv03: -INFINITY
group_color: clnUmResource:0 allocation score on srv04: 0
group_color: clnUmResource:1 allocation score on srv01: -INFINITY
group_color: clnUmResource:1 allocation score on srv02: -INFINITY
group_color: clnUmResource:1 allocation score on srv03: -INFINITY
group_color: clnUmResource:1 allocation score on srv04: -INFINITY
group_color: grpStonith1 allocation score on srv01: -INFINITY
group_color: grpStonith1 allocation score on srv02: 100
group_color: grpStonith1 allocation score on srv03: 100
group_color: grpStonith1 allocation score on srv04: 200
group_color: grpStonith2 allocation score on srv01: 200
group_color: grpStonith2 allocation score on srv02: -INFINITY
group_color: grpStonith2 allocation score on srv03: 100
group_color: grpStonith2 allocation score on srv04: 100
group_color: grpStonith3 allocation score on srv01: 100
group_color: grpStonith3 allocation score on srv02: 200
group_color: grpStonith3 allocation score on srv03: -INFINITY
group_color: grpStonith3 allocation score on srv04: 100
group_color: grpStonith4 allocation score on srv01: 100
group_color: grpStonith4 allocation score on srv02: 100
group_color: grpStonith4 allocation score on srv03: 200
group_color: grpStonith4 allocation score on srv04: -INFINITY
group_color: prmApPostgreSQLDB1 allocation score on srv01: 0
group_color: prmApPostgreSQLDB1 allocation score on srv02: 0
group_color: prmApPostgreSQLDB1 allocation score on srv03: 0
group_color: prmApPostgreSQLDB1 allocation score on srv04: 100
group_color: prmApPostgreSQLDB2 allocation score on srv01: 0
group_color: prmApPostgreSQLDB2 allocation score on srv02: 100
group_color: prmApPostgreSQLDB2 allocation score on srv03: 0
group_color: prmApPostgreSQLDB2 allocation score on srv04: 0
group_color: prmApPostgreSQLDB3 allocation score on srv01: 0
group_color: prmApPostgreSQLDB3 allocation score on srv02: 0
group_color: prmApPostgreSQLDB3 allocation score on srv03: 100
group_color: prmApPostgreSQLDB3 allocation score on srv04: 0
group_color: prmExPostgreSQLDB1 allocation score on srv01: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv02: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv03: -INFINITY
group_color: prmExPostgreSQLDB1 allocation score on srv04: 200
group_color: prmExPostgreSQLDB2 allocation score on srv01: -INFINITY
group_color: prmExPostgreSQLDB2 allocation score on srv02: 300
group_color: prmExPostgreSQLDB2 allocation score on srv03: -INFINITY
group_color: prmExPostgreSQLDB2 allocation score on srv04: 100
group_color: prmExPostgreSQLDB3 allocation score on srv01: -INFINITY
group_color: prmExPostgreSQLDB3 allocation score on srv02: -INFINITY
group_color: prmExPostgreSQLDB3 allocation score on srv03: 300
group_color: prmExPostgreSQLDB3 allocation score on srv04: 100
group_color: prmFsPostgreSQLDB1-1 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB1-1 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB1-1 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB1-1 allocation score on srv04: 100
group_color: prmFsPostgreSQLDB1-2 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB1-2 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB1-2 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB1-2 allocation score on srv04: 100
group_color: prmFsPostgreSQLDB1-3 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB1-3 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB1-3 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB1-3 allocation score on srv04: 100
group_color: prmFsPostgreSQLDB2-1 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB2-1 allocation score on srv02: 100
group_color: prmFsPostgreSQLDB2-1 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB2-1 allocation score on srv04: 0
group_color: prmFsPostgreSQLDB2-2 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB2-2 allocation score on srv02: 100
group_color: prmFsPostgreSQLDB2-2 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB2-2 allocation score on srv04: 0
group_color: prmFsPostgreSQLDB2-3 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB2-3 allocation score on srv02: 100
group_color: prmFsPostgreSQLDB2-3 allocation score on srv03: 0
group_color: prmFsPostgreSQLDB2-3 allocation score on srv04: 0
group_color: prmFsPostgreSQLDB3-1 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB3-1 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB3-1 allocation score on srv03: 100
group_color: prmFsPostgreSQLDB3-1 allocation score on srv04: 0
group_color: prmFsPostgreSQLDB3-2 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB3-2 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB3-2 allocation score on srv03: 100
group_color: prmFsPostgreSQLDB3-2 allocation score on srv04: 0
group_color: prmFsPostgreSQLDB3-3 allocation score on srv01: 0
group_color: prmFsPostgreSQLDB3-3 allocation score on srv02: 0
group_color: prmFsPostgreSQLDB3-3 allocation score on srv03: 100
group_color: prmFsPostgreSQLDB3-3 allocation score on srv04: 0
group_color: prmIpPostgreSQLDB1 allocation score on srv01: 0
group_color: prmIpPostgreSQLDB1 allocation score on srv02: 0
group_color: prmIpPostgreSQLDB1 allocation score on srv03: 0
group_color: prmIpPostgreSQLDB1 allocation score on srv04: 100
group_color: prmIpPostgreSQLDB2 allocation score on srv01: 0
group_color: prmIpPostgreSQLDB2 allocation score on srv02: 100
group_color: prmIpPostgreSQLDB2 allocation score on srv03: 0
group_color: prmIpPostgreSQLDB2 allocation score on srv04: 0
group_color: prmIpPostgreSQLDB3 allocation score on srv01: 0
group_color: prmIpPostgreSQLDB3 allocation score on srv02: 0
group_color: prmIpPostgreSQLDB3 allocation score on srv03: 100
group_color: prmIpPostgreSQLDB3 allocation score on srv04: 0
group_color: prmStonithN1 allocation score on srv01: -INFINITY
group_color: prmStonithN1 allocation score on srv02: 100
group_color: prmStonithN1 allocation score on srv03: 100
group_color: prmStonithN1 allocation score on srv04: 300
group_color: prmStonithN2 allocation score on srv01: 200
group_color: prmStonithN2 allocation score on srv02: -INFINITY
group_color: prmStonithN2 allocation score on srv03: 200
group_color: prmStonithN2 allocation score on srv04: 100
group_color: prmStonithN3 allocation score on srv01: 100
group_color: prmStonithN3 allocation score on srv02: 300
group_color: prmStonithN3 allocation score on srv03: -INFINITY
group_color: prmStonithN3 allocation score on srv04: 100
group_color: prmStonithN4 allocation score on srv01: 100
group_color: prmStonithN4 allocation score on srv02: 100
group_color: prmStonithN4 allocation score on srv03: 300
group_color: prmStonithN4 allocation score on srv04: -INFINITY
native_color: UmDummy01 allocation score on srv01: -INFINITY
native_color: UmDummy01 allocation score on srv02: -INFINITY
native_color: UmDummy01 allocation score on srv03: -INFINITY
native_color: UmDummy01 allocation score on srv04: 0
native_color: UmDummy02 allocation score on srv01: -INFINITY
native_color: UmDummy02 allocation score on srv02: -INFINITY
native_color: UmDummy02 allocation score on srv03: -INFINITY
native_color: UmDummy02 allocation score on srv04: 0
native_color: UmIPaddr allocation score on srv01: -INFINITY
native_color: UmIPaddr allocation score on srv02: -INFINITY
native_color: UmIPaddr allocation score on srv03: -INFINITY
native_color: UmIPaddr allocation score on srv04: 0
native_color: UmVIPcheck allocation score on srv01: -INFINITY
native_color: UmVIPcheck allocation score on srv02: -INFINITY
native_color: UmVIPcheck allocation score on srv03: -INFINITY
native_color: UmVIPcheck allocation score on srv04: 100
native_color: clnG3dummy01:0 allocation score on srv01: -INFINITY
native_color: clnG3dummy01:0 allocation score on srv02: 100
native_color: clnG3dummy01:0 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:0 allocation score on srv04: -INFINITY
native_color: clnG3dummy01:1 allocation score on srv01: -INFINITY
native_color: clnG3dummy01:1 allocation score on srv02: 0
native_color: clnG3dummy01:1 allocation score on srv03: 100
native_color: clnG3dummy01:1 allocation score on srv04: 0
native_color: clnG3dummy01:2 allocation score on srv01: -INFINITY
native_color: clnG3dummy01:2 allocation score on srv02: 0
native_color: clnG3dummy01:2 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:2 allocation score on srv04: 100
native_color: clnG3dummy01:3 allocation score on srv01: -INFINITY
native_color: clnG3dummy01:3 allocation score on srv02: -INFINITY
native_color: clnG3dummy01:3 allocation score on srv03: -INFINITY
native_color: clnG3dummy01:3 allocation score on srv04: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv01: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv02: 100
native_color: clnG3dummy02:0 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:0 allocation score on srv04: -INFINITY
native_color: clnG3dummy02:1 allocation score on srv01: -INFINITY
native_color: clnG3dummy02:1 allocation score on srv02: 0
native_color: clnG3dummy02:1 allocation score on srv03: 100
native_color: clnG3dummy02:1 allocation score on srv04: 0
native_color: clnG3dummy02:2 allocation score on srv01: -INFINITY
native_color: clnG3dummy02:2 allocation score on srv02: 0
native_color: clnG3dummy02:2 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:2 allocation score on srv04: 100
native_color: clnG3dummy02:3 allocation score on srv01: -INFINITY
native_color: clnG3dummy02:3 allocation score on srv02: -INFINITY
native_color: clnG3dummy02:3 allocation score on srv03: -INFINITY
native_color: clnG3dummy02:3 allocation score on srv04: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv01: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv02: 100
native_color: clnPrmDiskd1:0 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:0 allocation score on srv04: -INFINITY
native_color: clnPrmDiskd1:1 allocation score on srv01: -INFINITY
native_color: clnPrmDiskd1:1 allocation score on srv02: 0
native_color: clnPrmDiskd1:1 allocation score on srv03: 100
native_color: clnPrmDiskd1:1 allocation score on srv04: 0
native_color: clnPrmDiskd1:2 allocation score on srv01: -INFINITY
native_color: clnPrmDiskd1:2 allocation score on srv02: 0
native_color: clnPrmDiskd1:2 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:2 allocation score on srv04: 100
native_color: clnPrmDiskd1:3 allocation score on srv01: -INFINITY
native_color: clnPrmDiskd1:3 allocation score on srv02: -INFINITY
native_color: clnPrmDiskd1:3 allocation score on srv03: -INFINITY
native_color: clnPrmDiskd1:3 allocation score on srv04: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv01: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv02: 100
native_color: clnPrmPingd:0 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:0 allocation score on srv04: -INFINITY
native_color: clnPrmPingd:1 allocation score on srv01: -INFINITY
native_color: clnPrmPingd:1 allocation score on srv02: 0
native_color: clnPrmPingd:1 allocation score on srv03: 100
native_color: clnPrmPingd:1 allocation score on srv04: 0
native_color: clnPrmPingd:2 allocation score on srv01: -INFINITY
native_color: clnPrmPingd:2 allocation score on srv02: 0
native_color: clnPrmPingd:2 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:2 allocation score on srv04: 100
native_color: clnPrmPingd:3 allocation score on srv01: -INFINITY
native_color: clnPrmPingd:3 allocation score on srv02: -INFINITY
native_color: clnPrmPingd:3 allocation score on srv03: -INFINITY
native_color: clnPrmPingd:3 allocation score on srv04: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv01: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv02: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv03: -INFINITY
native_color: clnUMdummy01:0 allocation score on srv04: 200
native_color: clnUMdummy01:1 allocation score on srv01: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv02: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv03: -INFINITY
native_color: clnUMdummy01:1 allocation score on srv04: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv01: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv02: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv03: -INFINITY
native_color: clnUMdummy02:0 allocation score on srv04: 100
native_color: clnUMdummy02:1 allocation score on srv01: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv02: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv03: -INFINITY
native_color: clnUMdummy02:1 allocation score on srv04: -INFINITY
native_color: prmApPostgreSQLDB1 allocation score on srv01: -INFINITY
native_color: prmApPostgreSQLDB1 allocation score on srv02: -INFINITY
native_color: prmApPostgreSQLDB1 allocation score on srv03: -INFINITY
native_color: prmApPostgreSQLDB1 allocation score on srv04: 100
native_color: prmApPostgreSQLDB2 allocation score on srv01: -INFINITY
native_color: prmApPostgreSQLDB2 allocation score on srv02: 100
native_color: prmApPostgreSQLDB2 allocation score on srv03: -INFINITY
native_color: prmApPostgreSQLDB2 allocation score on srv04: -INFINITY
native_color: prmApPostgreSQLDB3 allocation score on srv01: -INFINITY
native_color: prmApPostgreSQLDB3 allocation score on srv02: -INFINITY
native_color: prmApPostgreSQLDB3 allocation score on srv03: 100
native_color: prmApPostgreSQLDB3 allocation score on srv04: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv01: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv02: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv03: -INFINITY
native_color: prmExPostgreSQLDB1 allocation score on srv04: 700
native_color: prmExPostgreSQLDB2 allocation score on srv01: -INFINITY
native_color: prmExPostgreSQLDB2 allocation score on srv02: 800
native_color: prmExPostgreSQLDB2 allocation score on srv03: -INFINITY
native_color: prmExPostgreSQLDB2 allocation score on srv04: 100
native_color: prmExPostgreSQLDB3 allocation score on srv01: -INFINITY
native_color: prmExPostgreSQLDB3 allocation score on srv02: -INFINITY
native_color: prmExPostgreSQLDB3 allocation score on srv03: 800
native_color: prmExPostgreSQLDB3 allocation score on srv04: 100
native_color: prmFsPostgreSQLDB1-1 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB1-1 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB1-1 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB1-1 allocation score on srv04: 500
native_color: prmFsPostgreSQLDB1-2 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB1-2 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB1-2 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB1-2 allocation score on srv04: 400
native_color: prmFsPostgreSQLDB1-3 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB1-3 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB1-3 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB1-3 allocation score on srv04: 300
native_color: prmFsPostgreSQLDB2-1 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB2-1 allocation score on srv02: 500
native_color: prmFsPostgreSQLDB2-1 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB2-1 allocation score on srv04: -INFINITY
native_color: prmFsPostgreSQLDB2-2 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB2-2 allocation score on srv02: 400
native_color: prmFsPostgreSQLDB2-2 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB2-2 allocation score on srv04: -INFINITY
native_color: prmFsPostgreSQLDB2-3 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB2-3 allocation score on srv02: 300
native_color: prmFsPostgreSQLDB2-3 allocation score on srv03: -INFINITY
native_color: prmFsPostgreSQLDB2-3 allocation score on srv04: -INFINITY
native_color: prmFsPostgreSQLDB3-1 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB3-1 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB3-1 allocation score on srv03: 500
native_color: prmFsPostgreSQLDB3-1 allocation score on srv04: -INFINITY
native_color: prmFsPostgreSQLDB3-2 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB3-2 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB3-2 allocation score on srv03: 400
native_color: prmFsPostgreSQLDB3-2 allocation score on srv04: -INFINITY
native_color: prmFsPostgreSQLDB3-3 allocation score on srv01: -INFINITY
native_color: prmFsPostgreSQLDB3-3 allocation score on srv02: -INFINITY
native_color: prmFsPostgreSQLDB3-3 allocation score on srv03: 300
native_color: prmFsPostgreSQLDB3-3 allocation score on srv04: -INFINITY
native_color: prmIpPostgreSQLDB1 allocation score on srv01: -INFINITY
native_color: prmIpPostgreSQLDB1 allocation score on srv02: -INFINITY
native_color: prmIpPostgreSQLDB1 allocation score on srv03: -INFINITY
native_color: prmIpPostgreSQLDB1 allocation score on srv04: 200
native_color: prmIpPostgreSQLDB2 allocation score on srv01: -INFINITY
native_color: prmIpPostgreSQLDB2 allocation score on srv02: 200
native_color: prmIpPostgreSQLDB2 allocation score on srv03: -INFINITY
native_color: prmIpPostgreSQLDB2 allocation score on srv04: -INFINITY
native_color: prmIpPostgreSQLDB3 allocation score on srv01: -INFINITY
native_color: prmIpPostgreSQLDB3 allocation score on srv02: -INFINITY
native_color: prmIpPostgreSQLDB3 allocation score on srv03: 200
native_color: prmIpPostgreSQLDB3 allocation score on srv04: -INFINITY
native_color: prmStonithN1 allocation score on srv01: -INFINITY
native_color: prmStonithN1 allocation score on srv02: 100
native_color: prmStonithN1 allocation score on srv03: 100
native_color: prmStonithN1 allocation score on srv04: 300
native_color: prmStonithN2 allocation score on srv01: 200
native_color: prmStonithN2 allocation score on srv02: -INFINITY
native_color: prmStonithN2 allocation score on srv03: 200
native_color: prmStonithN2 allocation score on srv04: 100
native_color: prmStonithN3 allocation score on srv01: 100
native_color: prmStonithN3 allocation score on srv02: 300
native_color: prmStonithN3 allocation score on srv03: -INFINITY
native_color: prmStonithN3 allocation score on srv04: 100
native_color: prmStonithN4 allocation score on srv01: 100
native_color: prmStonithN4 allocation score on srv02: 100
native_color: prmStonithN4 allocation score on srv03: 300
native_color: prmStonithN4 allocation score on srv04: -INFINITY
diff --git a/pengine/test10/master-colocation.scores b/pengine/test10/master-colocation.scores
index fd465bd094..49dff08188 100644
--- a/pengine/test10/master-colocation.scores
+++ b/pengine/test10/master-colocation.scores
@@ -1,27 +1,27 @@
Allocation scores:
clone_color: conntrackd-stateful:0 allocation score on box1: 105
clone_color: conntrackd-stateful:0 allocation score on box2: 0
clone_color: conntrackd-stateful:1 allocation score on box1: 0
clone_color: conntrackd-stateful:1 allocation score on box2: 105
clone_color: ms-conntrackd allocation score on box1: 0
clone_color: ms-conntrackd allocation score on box2: 0
conntrackd-stateful:0 promotion score on box1: -INFINITY
-conntrackd-stateful:1 promotion score on box2: 605
+conntrackd-stateful:1 promotion score on box2: INFINITY
group_color: externalip allocation score on box1: 0
group_color: externalip allocation score on box2: 100
group_color: internalip allocation score on box1: 0
group_color: internalip allocation score on box2: 100
group_color: sship allocation score on box1: 0
group_color: sship allocation score on box2: 100
group_color: virtualips allocation score on box1: 0
group_color: virtualips allocation score on box2: 0
native_color: conntrackd-stateful:0 allocation score on box1: 105
native_color: conntrackd-stateful:0 allocation score on box2: 0
native_color: conntrackd-stateful:1 allocation score on box1: -INFINITY
native_color: conntrackd-stateful:1 allocation score on box2: 105
native_color: externalip allocation score on box1: 0
native_color: externalip allocation score on box2: 300
native_color: internalip allocation score on box1: -INFINITY
native_color: internalip allocation score on box2: 200
native_color: sship allocation score on box1: -INFINITY
native_color: sship allocation score on box2: 100

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 7:27 AM (21 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018431
Default Alt Text
(494 KB)

Event Timeline