Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3686493
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
104 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/crm/pengine/utils.c b/lib/crm/pengine/utils.c
index ab560869bf..6a2b5b708f 100644
--- a/lib/crm/pengine/utils.c
+++ b/lib/crm/pengine/utils.c
@@ -1,1214 +1,1249 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <crm_internal.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <glib.h>
#include <crm/pengine/rules.h>
#include <utils.h>
void print_str_str(gpointer key, gpointer value, gpointer user_data);
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
void unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set);
void
pe_free_shallow(GListPtr alist)
{
pe_free_shallow_adv(alist, TRUE);
}
void
pe_free_shallow_adv(GListPtr alist, gboolean with_data)
{
GListPtr item;
GListPtr item_next = alist;
if(with_data == FALSE && alist != NULL) {
g_list_free(alist);
return;
}
while(item_next != NULL) {
item = item_next;
item_next = item_next->next;
if(with_data) {
/* crm_debug_5("freeing %p", item->data); */
crm_free(item->data);
}
item->data = NULL;
item->next = NULL;
g_list_free_1(item);
}
}
node_t *
node_copy(node_t *this_node)
{
node_t *new_node = NULL;
CRM_CHECK(this_node != NULL, return NULL);
crm_malloc0(new_node, sizeof(node_t));
CRM_ASSERT(new_node != NULL);
crm_debug_5("Copying %p (%s) to %p",
this_node, this_node->details->uname, new_node);
new_node->weight = this_node->weight;
new_node->fixed = this_node->fixed;
new_node->details = this_node->details;
return new_node;
}
/* are the contents of list1 and list2 equal
* nodes with weight < 0 are ignored if filter == TRUE
*
* slow but linear
*
*/
gboolean
node_list_eq(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node;
GListPtr lhs = list1;
GListPtr rhs = list2;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node_id(rhs, node->details->id);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
lhs = list2;
rhs = list1;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node_id(rhs, node->details->id);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
return TRUE;
}
-/* the intersection of list1 and list2
- */
+/* any node in list1 or list2 and not in the other gets a score of -INFINITY */
+GListPtr
+node_list_exclude(GListPtr list1, GListPtr list2)
+{
+ node_t *other_node = NULL;
+ GListPtr result = NULL;
+
+ result = node_list_dup(list1, FALSE, FALSE);
+
+ slist_iter(
+ node, node_t, result, lpc,
+
+ other_node = pe_find_node_id(list2, node->details->id);
+
+ if(other_node == NULL) {
+ node->weight = -INFINITY;
+ } else {
+ node->weight = merge_weights(node->weight, other_node->weight);
+ }
+ );
+
+ slist_iter(
+ node, node_t, list2, lpc,
+
+ other_node = pe_find_node_id(result, node->details->id);
+
+ if(other_node == NULL) {
+ node_t *new_node = node_copy(node);
+ new_node->weight = -INFINITY;
+ result = g_list_append(result, new_node);
+ }
+ );
+
+ return result;
+}
+
+/* the intersection of list1 and list2 */
GListPtr
node_list_and(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
unsigned lpc = 0;
for(lpc = 0; lpc < g_list_length(list1); lpc++) {
node_t *node = (node_t*)g_list_nth_data(list1, lpc);
node_t *other_node = pe_find_node_id(list2, node->details->id);
node_t *new_node = NULL;
if(other_node != NULL) {
new_node = node_copy(node);
}
if(new_node != NULL) {
crm_debug_4("%s: %d + %d", node->details->uname,
other_node->weight, new_node->weight);
new_node->weight = merge_weights(
new_node->weight, other_node->weight);
crm_debug_3("New node weight for %s: %d",
new_node->details->uname, new_node->weight);
if(filter && new_node->weight < 0) {
crm_free(new_node);
new_node = NULL;
}
}
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
}
return result;
}
/* list1 - list2 */
GListPtr
node_list_minus(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = pe_find_node_id(list2, node->details->id);
node_t *new_node = NULL;
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Minus result len: %d", g_list_length(result));
return result;
}
/* list1 + list2 - (intersection of list1 and list2) */
GListPtr
node_list_xor(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node_id(list2, node->details->id);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
slist_iter(
node, node_t, list2, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node_id(list1, node->details->id);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Xor result len: %d", g_list_length(result));
return result;
}
GListPtr
node_list_or(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node = NULL;
GListPtr result = NULL;
gboolean needs_filter = FALSE;
result = node_list_dup(list1, FALSE, filter);
slist_iter(
node, node_t, list2, lpc,
if(node == NULL) {
continue;
}
other_node = (node_t*)pe_find_node_id(
result, node->details->id);
if(other_node != NULL) {
crm_debug_4("%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);
if(filter && node->weight < 0) {
needs_filter = TRUE;
}
} else if(filter == FALSE || node->weight >= 0) {
node_t *new_node = node_copy(node);
result = g_list_append(result, new_node);
}
);
/* not the neatest way, but the most expedient for now */
if(filter && needs_filter) {
GListPtr old_result = result;
result = node_list_dup(old_result, FALSE, filter);
pe_free_shallow_adv(old_result, TRUE);
}
return result;
}
GListPtr
node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
this_node, node_t, list1, lpc,
node_t *new_node = NULL;
if(filter && this_node->weight < 0) {
continue;
}
new_node = node_copy(this_node);
if(reset) {
new_node->weight = 0;
}
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
);
return result;
}
void dump_node_scores(int level, resource_t *rsc, const char *comment, GListPtr nodes)
{
GListPtr list = nodes;
if(rsc) {
list = rsc->allowed_nodes;
}
slist_iter(
node, node_t, list, lpc,
if(rsc) {
do_crm_log(level, "%s: %s allocation score on %s: %d",
comment, rsc->id, node->details->uname, node->weight);
} else {
do_crm_log(level, "%s: %s = %d", comment, node->details->uname, node->weight);
}
);
if(rsc && rsc->children) {
slist_iter(
child, resource_t, rsc->children, lpc,
dump_node_scores(level, child, comment, nodes);
);
}
}
gint sort_rsc_index(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL && b == NULL) { return 0; }
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(resource1->sort_index > resource2->sort_index) {
return -1;
}
if(resource1->sort_index < resource2->sort_index) {
return 1;
}
return 0;
}
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL && b == NULL) { return 0; }
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(resource1->priority > resource2->priority) {
return -1;
}
if(resource1->priority < resource2->priority) {
return 1;
}
return 0;
}
action_t *
custom_action(resource_t *rsc, char *key, const char *task,
node_t *on_node, gboolean optional, gboolean save_action,
pe_working_set_t *data_set)
{
action_t *action = NULL;
GListPtr possible_matches = NULL;
CRM_CHECK(key != NULL, return NULL);
CRM_CHECK(task != NULL, return NULL);
if(save_action && rsc != NULL) {
possible_matches = find_actions(rsc->actions, key, on_node);
}
if(possible_matches != NULL) {
crm_free(key);
if(g_list_length(possible_matches) > 1) {
pe_warn("Action %s for %s on %s exists %d times",
task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>",
g_list_length(possible_matches));
}
action = g_list_nth_data(possible_matches, 0);
crm_debug_4("Found existing action (%d) %s for %s on %s",
action->id, task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
g_list_free(possible_matches);
}
if(action == NULL) {
if(save_action) {
crm_debug_2("Creating%s action %d: %s for %s on %s",
optional?"":" manditory", data_set->action_id, key, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
}
crm_malloc0(action, sizeof(action_t));
if(save_action) {
action->id = data_set->action_id++;
} else {
action->id = 0;
}
action->rsc = rsc;
CRM_ASSERT(task != NULL);
action->task = crm_strdup(task);
action->node = on_node;
action->uuid = key;
action->actions_before = NULL;
action->actions_after = NULL;
action->failure_is_fatal = TRUE;
action->pseudo = FALSE;
action->dumped = FALSE;
action->runnable = TRUE;
action->processed = FALSE;
action->optional = optional;
action->seen_count = 0;
action->extra = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
action->meta = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
if(save_action) {
data_set->actions = g_list_append(
data_set->actions, action);
}
if(rsc != NULL) {
action->op_entry = find_rsc_op_entry(rsc, key);
unpack_operation(
action, action->op_entry, data_set);
if(save_action) {
rsc->actions = g_list_append(
rsc->actions, action);
}
}
if(save_action) {
crm_debug_4("Action %d created", action->id);
}
}
if(optional == FALSE && action->optional) {
crm_debug_2("Action %d (%s) marked manditory",
action->id, action->uuid);
action->optional = FALSE;
}
if(rsc != NULL) {
enum action_tasks a_task = text2task(action->task);
int warn_level = LOG_DEBUG_3;
if(save_action) {
warn_level = LOG_WARNING;
}
if(action->node != NULL && action->op_entry != NULL) {
unpack_instance_attributes(
action->op_entry, XML_TAG_ATTR_SETS,
action->node->details->attrs,
action->extra, NULL, data_set->now);
}
if(action->pseudo) {
/* leave untouched */
} else if(action->node == NULL) {
action->runnable = FALSE;
} else if(is_not_set(rsc->flags, pe_rsc_managed)) {
do_crm_log(warn_level, "Action %s (unmanaged)",
action->uuid);
action->optional = TRUE;
/* action->runnable = FALSE; */
} else if(action->node->details->online == FALSE) {
action->runnable = FALSE;
do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
action->uuid, action->node->details->uname);
if(is_set(action->rsc->flags, pe_rsc_managed)
&& save_action
&& a_task == stop_rsc) {
do_crm_log(warn_level, "Marking node %s unclean",
action->node->details->uname);
action->node->details->unclean = TRUE;
}
} else if(action->needs == rsc_req_nothing) {
crm_debug_3("Action %s doesnt require anything",
action->uuid);
action->runnable = TRUE;
#if 0
/*
* No point checking this
* - if we dont have quorum we cant stonith anyway
*/
} else if(action->needs == rsc_req_stonith) {
crm_debug_3("Action %s requires only stonith", action->uuid);
action->runnable = TRUE;
#endif
} else if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy == no_quorum_stop) {
action->runnable = FALSE;
crm_debug("%s\t%s (cancelled : quorum)",
action->node->details->uname,
action->uuid);
} else if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy == no_quorum_freeze) {
crm_debug_3("Check resource is already active");
if(rsc->fns->active(rsc, TRUE) == FALSE) {
action->runnable = FALSE;
crm_debug("%s\t%s (cancelled : quorum freeze)",
action->node->details->uname,
action->uuid);
}
} else {
crm_debug_3("Action %s is runnable", action->uuid);
action->runnable = TRUE;
}
if(save_action) {
switch(a_task) {
case stop_rsc:
set_bit(rsc->flags, pe_rsc_stopping);
break;
case start_rsc:
clear_bit(rsc->flags, pe_rsc_starting);
if(action->runnable) {
set_bit(rsc->flags, pe_rsc_starting);
}
break;
default:
break;
}
}
}
return action;
}
void
unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set)
{
int value_i = 0;
int start_delay = 0;
char *value_ms = NULL;
const char *class = NULL;
const char *value = NULL;
const char *field = NULL;
CRM_CHECK(action->rsc != NULL, return);
class = g_hash_table_lookup(action->rsc->meta, "class");
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "prereq");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) {
value = g_hash_table_lookup(action->rsc->meta, "start_prereq");
}
if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) {
/* todo: integrate stop as an option? */
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(safe_str_eq(value, "nothing")) {
action->needs = rsc_req_nothing;
} else if(safe_str_eq(value, "quorum")) {
action->needs = rsc_req_quorum;
} else if(safe_str_eq(value, "fencing")) {
action->needs = rsc_req_stonith;
} else if(data_set->no_quorum_policy == no_quorum_ignore
|| safe_str_eq(class, "stonith")) {
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(data_set->no_quorum_policy == no_quorum_freeze
&& data_set->stonith_enabled) {
action->needs = rsc_req_stonith;
value = "fencing (default)";
} else {
action->needs = rsc_req_quorum;
value = "quorum (default)";
}
if(safe_str_eq(class, "stonith")) {
if(action->needs == rsc_req_stonith) {
crm_config_err("Stonith resources (eg. %s) cannot require"
" fencing to start", action->rsc->id);
}
action->needs = rsc_req_nothing;
value = "nothing (fencing override)";
}
crm_debug_3("\tAction %s requires: %s", action->task, value);
value = NULL;
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "on_fail");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
value = g_hash_table_lookup(
action->rsc->meta, "on_stopfail");
if(value != NULL) {
#if CRM_DEPRECATED_SINCE_2_0_2
crm_config_err("The \"on_stopfail\" attribute used in"
" %s has been deprecated since 2.0.2",
action->rsc->id);
#else
crm_config_err("The \"on_stopfail\" attribute used in"
" %s has been deprecated since 2.0.2"
" and is now disabled", action->rsc->id);
value = NULL;
#endif
crm_config_err("Please use specify the \"on_fail\""
" attribute on the \"stop\" operation"
" instead");
}
}
if(value == NULL) {
} else if(safe_str_eq(value, "block")) {
action->on_fail = action_fail_block;
} else if(safe_str_eq(value, "fence")) {
action->on_fail = action_fail_fence;
value = "node fencing";
if(data_set->stonith_enabled == FALSE) {
crm_config_err("Specifying on_fail=fence and"
" stonith-enabled=false makes no sense");
action->on_fail = action_fail_stop;
action->fail_role = RSC_ROLE_STOPPED;
value = "stop resource";
}
} else if(safe_str_eq(value, "ignore")
|| safe_str_eq(value, "nothing")) {
action->on_fail = action_fail_ignore;
value = "ignore";
} else if(safe_str_eq(value, "migrate")) {
action->on_fail = action_fail_migrate;
value = "force migration";
} else if(safe_str_eq(value, "stop")) {
action->on_fail = action_fail_stop;
action->fail_role = RSC_ROLE_STOPPED;
value = "stop resource";
} else if(safe_str_eq(value, "restart")) {
action->on_fail = action_fail_recover;
value = "restart (and possibly migrate)";
} else {
pe_err("Resource %s: Unknown failure type (%s)",
action->rsc->id, value);
value = NULL;
}
/* defaults */
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
if(data_set->stonith_enabled) {
action->on_fail = action_fail_fence;
value = "resource fence (default)";
} else {
action->on_fail = action_fail_block;
value = "resource block (default)";
}
} else if(value == NULL
&& safe_str_eq(action->task, CRMD_ACTION_MIGRATED)) {
action->on_fail = action_migrate_failure;
value = "atomic migration recovery (default)";
} else if(value == NULL) {
action->on_fail = action_fail_recover;
value = "restart (and possibly migrate) (default)";
}
crm_debug_3("\t%s failure handling: %s", action->task, value);
value = NULL;
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "role_after_failure");
}
if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
action->fail_role = text2role(value);
}
/* defaults */
if(action->fail_role == RSC_ROLE_UNKNOWN) {
if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
action->fail_role = RSC_ROLE_SLAVE;
} else {
action->fail_role = RSC_ROLE_STARTED;
}
}
crm_debug_3("\t%s failure results in: %s",
action->task, role2text(action->fail_role));
if(xml_obj != NULL) {
xml_prop_iter(xml_obj, p_name, p_value,
if(p_value != NULL) {
g_hash_table_insert(action->meta, crm_strdup(p_name),
crm_strdup(p_value));
}
);
unpack_instance_attributes(xml_obj, XML_TAG_META_SETS,
NULL, action->meta, NULL, data_set->now);
unpack_instance_attributes(xml_obj, XML_TAG_ATTR_SETS,
NULL, action->meta, NULL, data_set->now);
}
field = XML_LRM_ATTR_INTERVAL;
value = g_hash_table_lookup(action->meta, field);
if(value != NULL) {
value_i = crm_get_msec(value);
CRM_CHECK(value_i >= 0, value_i = 0);
value_ms = crm_itoa(value_i);
g_hash_table_replace(action->meta, crm_strdup(field), value_ms);
}
field = "start_delay";
value = g_hash_table_lookup(action->meta, field);
if(value != NULL) {
value_i = crm_get_msec(value);
if(value_i < 0) {
value_i = 0;
}
start_delay = value_i;
value_ms = crm_itoa(value_i);
g_hash_table_replace(action->meta, crm_strdup(field), value_ms);
}
field = "timeout";
value = g_hash_table_lookup(action->meta, field);
if(value == NULL) {
value = pe_pref(
data_set->config_hash, "default-action-timeout");
}
value_i = crm_get_msec(value);
if(value_i < 0) {
value_i = 0;
}
value_i += start_delay;
value_ms = crm_itoa(value_i);
g_hash_table_replace(action->meta, crm_strdup(field), value_ms);
}
crm_data_t *
find_rsc_op_entry(resource_t *rsc, const char *key)
{
int number = 0;
const char *name = NULL;
const char *value = NULL;
const char *interval = NULL;
char *match_key = NULL;
crm_data_t *op = NULL;
xml_child_iter_filter(
rsc->ops_xml, operation, "op",
name = crm_element_value(operation, "name");
interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
value = crm_element_value(operation, "disabled");
if(crm_is_true(value)) {
crm_debug_2("%s disabled", ID(operation));
continue;
}
number = crm_get_msec(interval);
if(number < 0) {
continue;
}
match_key = generate_op_key(rsc->id, name, number);
if(safe_str_eq(key, match_key)) {
op = operation;
}
crm_free(match_key);
if(op != NULL) {
return op;
}
);
crm_debug_3("No match for %s", key);
return op;
}
void
print_node(const char *pre_text, node_t *node, gboolean details)
{
if(node == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%sNode %s: (weight=%d, fixed=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ",
node->details->uname,
node->weight,
node->fixed?"True":"False");
if(details && node != NULL && node->details != NULL) {
char *pe_mutable = crm_strdup("\t\t");
crm_debug_4("\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs,
print_str_str, pe_mutable);
crm_free(pe_mutable);
crm_debug_4("\t\t=== Resources");
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE);
);
}
}
/*
* Used by the HashTable for-loop
*/
void print_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_debug_4("%s%s %s ==> %s",
user_data==NULL?"":(char*)user_data,
user_data==NULL?"":": ",
(char*)key,
(char*)value);
}
void
print_resource(
int log_level, const char *pre_text, resource_t *rsc, gboolean details)
{
long options = pe_print_log;
if(rsc == NULL) {
do_crm_log(log_level-1, "%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
if(details) {
options |= pe_print_details;
}
rsc->fns->print(rsc, pre_text, options, &log_level);
}
void
pe_free_action(action_t *action)
{
if(action == NULL) {
return;
}
pe_free_shallow(action->actions_before);/* action_warpper_t* */
pe_free_shallow(action->actions_after); /* action_warpper_t* */
g_hash_table_destroy(action->extra);
g_hash_table_destroy(action->meta);
crm_free(action->task);
crm_free(action->uuid);
crm_free(action);
}
GListPtr
find_recurring_actions(GListPtr input, node_t *not_on_node)
{
const char *value = NULL;
GListPtr result = NULL;
CRM_CHECK(input != NULL, return NULL);
slist_iter(
action, action_t, input, lpc,
value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
if(value == NULL) {
/* skip */
} else if(safe_str_eq(value, "0")) {
/* skip */
} else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
/* skip */
} else if(not_on_node == NULL) {
crm_debug_5("(null) Found: %s", action->uuid);
result = g_list_append(result, action);
} else if(action->node == NULL) {
/* skip */
} else if(action->node->details != not_on_node->details) {
crm_debug_5("Found: %s", action->uuid);
result = g_list_append(result, action);
}
);
return result;
}
GListPtr
find_actions(GListPtr input, const char *key, node_t *on_node)
{
GListPtr result = NULL;
CRM_CHECK(key != NULL, return NULL);
slist_iter(
action, action_t, input, lpc,
crm_debug_5("Matching %s against %s", key, action->uuid);
if(safe_str_neq(key, action->uuid)) {
continue;
} else if(on_node == NULL) {
result = g_list_append(result, action);
} else if(action->node == NULL) {
/* skip */
crm_debug_2("While looking for %s action on %s, "
"found an unallocated one. Assigning"
" it to the requested node...",
key, on_node->details->uname);
action->node = on_node;
result = g_list_append(result, action);
} else if(safe_str_eq(on_node->details->id,
action->node->details->id)) {
result = g_list_append(result, action);
}
);
return result;
}
GListPtr
find_actions_exact(GListPtr input, const char *key, node_t *on_node)
{
GListPtr result = NULL;
CRM_CHECK(key != NULL, return NULL);
slist_iter(
action, action_t, input, lpc,
crm_debug_5("Matching %s against %s", key, action->uuid);
if(safe_str_neq(key, action->uuid)) {
crm_debug_3("Key mismatch: %s vs. %s",
key, action->uuid);
continue;
} else if(on_node == NULL || action->node == NULL) {
crm_debug_3("on_node=%p, action->node=%p",
on_node, action->node);
continue;
} else if(safe_str_eq(on_node->details->id,
action->node->details->id)) {
result = g_list_append(result, action);
}
crm_debug_2("Node mismatch: %s vs. %s",
on_node->details->id, action->node->details->id);
);
return result;
}
void
set_id(crm_data_t * xml_obj, const char *prefix, int child)
{
int id_len = 0;
gboolean use_prefix = TRUE;
gboolean use_child = TRUE;
char *new_id = NULL;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
id_len = 1 + strlen(id);
if(child > 999) {
pe_err("Are you insane?!?"
" The CRM does not support > 1000 children per resource");
return;
} else if(child < 0) {
use_child = FALSE;
} else {
id_len += 4; /* child */
}
if(prefix == NULL || safe_str_eq(id, prefix)) {
use_prefix = FALSE;
} else {
id_len += (1 + strlen(prefix));
}
crm_malloc0(new_id, id_len);
if(use_child) {
snprintf(new_id, id_len, "%s%s%s:%d",
use_prefix?prefix:"", use_prefix?":":"", id, child);
} else {
snprintf(new_id, id_len, "%s%s%s",
use_prefix?prefix:"", use_prefix?":":"", id);
}
crm_xml_add(xml_obj, XML_ATTR_ID, new_id);
crm_free(new_id);
}
static void
resource_node_score(resource_t *rsc, node_t *node, int score, const char *tag)
{
node_t *match = NULL;
if(rsc->children) {
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
resource_node_score(child_rsc, node, score, tag);
);
}
crm_debug_2("Setting %s for %s on %s: %d",
tag, rsc->id, node->details->uname, score);
match = pe_find_node_id(rsc->allowed_nodes, node->details->id);
if(match == NULL) {
match = node_copy(node);
match->weight = 0;
rsc->allowed_nodes = g_list_append(rsc->allowed_nodes, match);
}
match->weight = merge_weights(match->weight, score);
}
void
resource_location(resource_t *rsc, node_t *node, int score, const char *tag,
pe_working_set_t *data_set)
{
if(node != NULL) {
resource_node_score(rsc, node, score, tag);
} else if(data_set != NULL) {
slist_iter(
node, node_t, data_set->nodes, lpc,
resource_node_score(rsc, node, score, tag);
);
} else {
slist_iter(
node, node_t, rsc->allowed_nodes, lpc,
resource_node_score(rsc, node, score, tag);
);
}
if(node == NULL && score == -INFINITY) {
if(rsc->allocated_to) {
crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
crm_free(rsc->allocated_to);
rsc->allocated_to = NULL;
}
}
}
#define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int
gint
sort_op_by_callid(gconstpointer a, gconstpointer b)
{
char *a_uuid = NULL;
char *b_uuid = NULL;
const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID);
const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID);
const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC);
const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC);
const char *a_xml_id = ID(a);
const char *b_xml_id = ID(b);
int dummy = -1;
int a_id = -1;
int b_id = -1;
int a_rc = -1;
int b_rc = -1;
int a_status = -1;
int b_status = -1;
int a_call_id = -1;
int b_call_id = -1;
if(safe_str_eq(a_xml_id, b_xml_id)) {
/* We have duplicate lrm_rsc_op entries in the status
* section which is unliklely to be a good thing
* - we can handle it easily enough, but we need to get
* to the bottom of why its happening.
*/
pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
sort_return(0);
}
CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0));
a_call_id = crm_parse_int(a_task_id, NULL);
b_call_id = crm_parse_int(b_task_id, NULL);
if(a_call_id == -1 && b_call_id == -1) {
/* both are pending ops so it doesnt matter since
* stops are never pending
*/
sort_return(0);
} else if(a_call_id >= 0 && a_call_id < b_call_id) {
crm_debug_4("%s (%d) < %s (%d) : call id",
ID(a), a_call_id, ID(b), b_call_id);
sort_return(-1);
} else if(b_call_id >= 0 && a_call_id > b_call_id) {
crm_debug_4("%s (%d) > %s (%d) : call id",
ID(a), a_call_id, ID(b), b_call_id);
sort_return(1);
}
crm_debug_5("%s (%d) == %s (%d) : continuing",
ID(a), a_call_id, ID(b), b_call_id);
/* now process pending ops */
CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0));
CRM_CHECK(decode_transition_magic(
a_key, &a_uuid, &a_id, &dummy, &a_status, &a_rc),
sort_return(0));
CRM_CHECK(decode_transition_magic(
b_key, &b_uuid, &b_id, &dummy, &b_status, &b_rc),
sort_return(0));
/* try and determin the relative age of the operation...
* some pending operations (ie. a start) may have been supuerceeded
* by a subsequent stop
*
* [a|b]_id == -1 means its a shutdown operation and _always_ comes last
*/
if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
/*
* some of the logic in here may be redundant...
*
* if the UUID from the TE doesnt match then one better
* be a pending operation.
* pending operations dont survive between elections and joins
* because we query the LRM directly
*/
CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0));
CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0));
if(b_call_id == -1) {
crm_debug_2("%s (%d) < %s (%d) : transition + call id",
ID(a), a_call_id, ID(b), b_call_id);
sort_return(-1);
}
if(a_call_id == -1) {
crm_debug_2("%s (%d) > %s (%d) : transition + call id",
ID(a), a_call_id, ID(b), b_call_id);
sort_return(1);
}
} else if((a_id >= 0 && a_id < b_id) || b_id == -1) {
crm_debug_3("%s (%d) < %s (%d) : transition",
ID(a), a_id, ID(b), b_id);
sort_return(-1);
} else if((b_id >= 0 && a_id > b_id) || a_id == -1) {
crm_debug_3("%s (%d) > %s (%d) : transition",
ID(a), a_id, ID(b), b_id);
sort_return(1);
}
/* we should never end up here */
crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default",
ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid);
CRM_CHECK(FALSE, sort_return(0));
}
diff --git a/lib/crm/pengine/utils.h b/lib/crm/pengine/utils.h
index 15d1e3c2cf..15e8b858e5 100644
--- a/lib/crm/pengine/utils.h
+++ b/lib/crm/pengine/utils.h
@@ -1,124 +1,125 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PE_UTILS__H
#define PE_UTILS__H
#include <crm/pengine/common.h>
#include <crm/pengine/status.h>
extern node_t *node_copy(node_t *this_node) ;
/* Binary like operators for lists of nodes */
+extern GListPtr node_list_exclude(GListPtr list1, GListPtr list2);
extern GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter);
extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_minus(GListPtr list1,GListPtr list2,gboolean filter);
extern gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter);
extern void pe_free_shallow(GListPtr alist);
extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data);
/* For creating the transition graph */
extern crm_data_t *action2xml(action_t *action, gboolean as_input);
/* Printing functions for debug */
extern void print_node(
const char *pre_text, node_t *node, gboolean details);
extern void print_resource(
int log_level, const char *pre_text, resource_t *rsc, gboolean details);
extern void dump_node_scores(int level, resource_t *rsc, const char *comment, GListPtr nodes);
/* Sorting functions */
extern gint sort_rsc_priority(gconstpointer a, gconstpointer b);
extern gint sort_rsc_index(gconstpointer a, gconstpointer b);
extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key);
extern action_t *custom_action(
resource_t *rsc, char *key, const char *task, node_t *on_node,
gboolean optional, gboolean foo, pe_working_set_t *data_set);
#define delete_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DELETE, 0)
#define delete_action(rsc, node, optional) custom_action( \
rsc, delete_key(rsc), CRMD_ACTION_DELETE, node, \
optional, TRUE, data_set);
#define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0)
#define stopped_action(rsc, node, optional) custom_action( \
rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node, \
optional, TRUE, data_set);
#define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0)
#define stop_action(rsc, node, optional) custom_action( \
rsc, stop_key(rsc), CRMD_ACTION_STOP, node, \
optional, TRUE, data_set);
#define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0)
#define start_action(rsc, node, optional) custom_action( \
rsc, start_key(rsc), CRMD_ACTION_START, node, \
optional, TRUE, data_set)
#define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0)
#define started_action(rsc, node, optional) custom_action( \
rsc, started_key(rsc), CRMD_ACTION_STARTED, node, \
optional, TRUE, data_set)
#define promote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTE, 0)
#define promote_action(rsc, node, optional) custom_action( \
rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node, \
optional, TRUE, data_set)
#define promoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTED, 0)
#define promoted_action(rsc, node, optional) custom_action( \
rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node, \
optional, TRUE, data_set)
#define demote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTE, 0)
#define demote_action(rsc, node, optional) custom_action( \
rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node, \
optional, TRUE, data_set)
#define demoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTED, 0)
#define demoted_action(rsc, node, optional) custom_action( \
rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node, \
optional, TRUE, data_set)
extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node);
extern GListPtr find_actions_exact(
GListPtr input, const char *key, node_t *on_node);
extern GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node);
extern void set_id(crm_data_t *xml_obj, const char *prefix, int child);
extern void pe_free_action(action_t *action);
extern void
resource_location(resource_t *rsc, node_t *node, int score, const char *tag,
pe_working_set_t *data_set);
extern gint sort_op_by_callid(gconstpointer a, gconstpointer b);
#endif
diff --git a/pengine/clone.c b/pengine/clone.c
index 4c23047f1c..96fba49220 100644
--- a/pengine/clone.c
+++ b/pengine/clone.c
@@ -1,1504 +1,1504 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <crm_internal.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#include <lib/crm/pengine/utils.h>
#define VARIANT_CLONE 1
#include <lib/crm/pengine/variant.h>
gint sort_clone_instance(gconstpointer a, gconstpointer b);
void clone_create_notifications(
resource_t *rsc, action_t *action, action_t *action_complete,
pe_working_set_t *data_set);
void child_stopping_constraints(
clone_variant_data_t *clone_data,
resource_t *self, resource_t *child, resource_t *last,
pe_working_set_t *data_set);
void child_starting_constraints(
clone_variant_data_t *clone_data,
resource_t *self, resource_t *child, resource_t *last,
pe_working_set_t *data_set);
static node_t *
parent_node_instance(const resource_t *rsc, node_t *node)
{
node_t *ret = NULL;
if(node != NULL) {
ret = pe_find_node_id(
rsc->parent->allowed_nodes, node->details->id);
}
return ret;
}
static gboolean did_fail(const resource_t *rsc)
{
if(is_set(rsc->flags, pe_rsc_failed)) {
return TRUE;
}
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
if(did_fail(child_rsc)) {
return TRUE;
}
);
return FALSE;
}
gint sort_clone_instance(gconstpointer a, gconstpointer b)
{
int level = LOG_DEBUG_3;
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
*/
do_crm_log(level+1, "%s ? %s", resource1->id, resource2->id);
if(resource1->running_on && resource2->running_on) {
if(g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) {
do_crm_log(level, "%s < %s: running_on", resource1->id, resource2->id);
return -1;
} else if(g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) {
do_crm_log(level, "%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_find_node_id(resource1->allowed_nodes, node1->details->id);
if(match->weight < 0) {
do_crm_log(level, "%s: current location is unavailable", resource1->id);
node1 = NULL;
can1 = FALSE;
}
}
if(node2) {
node_t *match = pe_find_node_id(resource2->allowed_nodes, node2->details->id);
if(match->weight < 0) {
do_crm_log(level, "%s: current location is unavailable", resource2->id);
node2 = NULL;
can2 = FALSE;
}
}
if(can1 != can2) {
if(can1) {
do_crm_log(level, "%s < %s: availability of current location", resource1->id, resource2->id);
return -1;
}
do_crm_log(level, "%s > %s: availability of current location", resource1->id, resource2->id);
return 1;
}
if(resource1->priority < resource2->priority) {
do_crm_log(level, "%s < %s: priority", resource1->id, resource2->id);
return 1;
} else if(resource1->priority > resource2->priority) {
do_crm_log(level, "%s > %s: priority", resource1->id, resource2->id);
return -1;
}
if(node1 == NULL && node2 == NULL) {
do_crm_log(level, "%s == %s: not active",
resource1->id, resource2->id);
return 0;
}
if(node1 != node2) {
if(node1 == NULL) {
do_crm_log(level, "%s > %s: active", resource1->id, resource2->id);
return 1;
} else if(node2 == NULL) {
do_crm_log(level, "%s < %s: active", resource1->id, resource2->id);
return -1;
}
}
can1 = can_run_resources(node1);
can2 = can_run_resources(node2);
if(can1 != can2) {
if(can1) {
do_crm_log(level, "%s < %s: can", resource1->id, resource2->id);
return -1;
}
do_crm_log(level, "%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) {
do_crm_log(level, "%s < %s: not allowed", resource1->id, resource2->id);
return -1;
} else if(node1 == NULL && node2 != NULL) {
do_crm_log(level, "%s > %s: not allowed", resource1->id, resource2->id);
return 1;
}
if(node1 == NULL) {
do_crm_log(level, "%s == %s: not allowed", resource1->id, resource2->id);
return 0;
}
if(node1->count < node2->count) {
do_crm_log(level, "%s < %s: count", resource1->id, resource2->id);
return -1;
} else if(node1->count > node2->count) {
do_crm_log(level, "%s > %s: count", resource1->id, resource2->id);
return 1;
}
if(node1->weight < node2->weight) {
do_crm_log(level, "%s < %s: node score", resource1->id, resource2->id);
return 1;
} else if(node1->weight > node2->weight) {
do_crm_log(level, "%s > %s: node score", resource1->id, resource2->id);
return -1;
}
can1 = did_fail(resource1);
can2 = did_fail(resource2);
if(can1 != can2) {
if(can1) {
do_crm_log(level, "%s > %s: failed", resource1->id, resource2->id);
return 1;
}
do_crm_log(level, "%s < %s: failed", resource1->id, resource2->id);
return -1;
}
do_crm_log(level, "%s == %s: default %d", resource1->id, resource2->id, node2->weight);
return 0;
}
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;
}
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) {
return local_node;
} else {
crm_debug_2("%s cannot run on %s: node full",
rsc->id, node->details->uname);
}
bail:
if(node) {
common_update_score(rsc, node->details->id, -INFINITY);
}
return NULL;
}
static node_t *
color_instance(resource_t *rsc, pe_working_set_t *data_set)
{
node_t *chosen = NULL;
node_t *local_node = NULL;
crm_debug_2("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("Dependancy loop detected involving %s", rsc->id);
return NULL;
}
if(rsc->allowed_nodes) {
slist_iter(try_node, node_t, rsc->allowed_nodes, lpc,
can_run_instance(rsc, try_node);
);
}
chosen = rsc->cmds->color(rsc, data_set);
if(chosen) {
local_node = pe_find_node_id(
rsc->parent->allowed_nodes, chosen->details->id);
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_list_length(rsc->parent->allowed_nodes));
}
}
return chosen;
}
static void append_parent_colocation(resource_t *rsc, resource_t *child, gboolean all)
{
slist_iter(cons, rsc_colocation_t, rsc->rsc_cons, lpc,
if(all || cons->score < 0) {
child->rsc_cons = g_list_append(child->rsc_cons, cons);
}
);
slist_iter(cons, rsc_colocation_t, rsc->rsc_cons_lhs, lpc,
if(all || cons->score < 0) {
child->rsc_cons_lhs = g_list_append(child->rsc_cons_lhs, cons);
}
);
}
node_t *
clone_color(resource_t *rsc, pe_working_set_t *data_set)
{
int allocated = 0;
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("Dependancy loop detected involving %s", rsc->id);
return NULL;
}
set_bit(rsc->flags, pe_rsc_allocating);
crm_debug_2("Processing %s", rsc->id);
/* this information is used by sort_clone_instance() when deciding in which
* order to allocate clone instances
*/
slist_iter(
constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc,
rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights(
constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
constraint->score/INFINITY, TRUE);
);
dump_node_scores(scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes);
/* count now tracks the number of clones currently allocated */
slist_iter(node, node_t, rsc->allowed_nodes, lpc,
node->count = 0;
);
slist_iter(child, resource_t, rsc->children, lpc,
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) {
local_node->count++;
} else {
crm_err("%s is running on %s which isn't allowed",
child->id, child_node->details->uname);
}
}
);
rsc->children = g_list_sort(rsc->children, sort_clone_instance);
/* count now tracks the number of clones we have allocated */
slist_iter(node, node_t, rsc->allowed_nodes, lpc,
node->count = 0;
);
rsc->allowed_nodes = g_list_sort(
rsc->allowed_nodes, sort_node_weight);
slist_iter(node, node_t, rsc->allowed_nodes, lpc,
if(can_run_resources(node) == FALSE) {
available_nodes++;
}
);
slist_iter(child, resource_t, rsc->children, lpc,
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 (clone_data->clone_max < available_nodes) {
/* Only include positive colocation preferences of dependant resources
* if not every node will get a copy of the clone
*/
append_parent_colocation(rsc, child, TRUE);
} else {
append_parent_colocation(rsc, child, FALSE);
}
if(color_instance(child, 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);
return NULL;
}
static void
clone_update_pseudo_status(
resource_t *rsc, gboolean *stopping, gboolean *starting)
{
if(rsc->children) {
slist_iter(child, resource_t, rsc->children, lpc,
clone_update_pseudo_status(child, stopping, starting)
);
return;
}
CRM_ASSERT(stopping != NULL);
CRM_ASSERT(starting != NULL);
slist_iter(
action, action_t, rsc->actions, lpc,
if(*starting && *stopping) {
return;
} else if(action->optional) {
crm_debug_3("Skipping optional: %s", action->uuid);
continue;
} else if(action->pseudo == FALSE && action->runnable == FALSE){
crm_debug_3("Skipping unrunnable: %s", action->uuid);
continue;
} else if(safe_str_eq(CRMD_ACTION_STOP, action->task)) {
crm_debug_2("Stopping due to: %s", action->uuid);
*stopping = TRUE;
} else if(safe_str_eq(CRMD_ACTION_START, action->task)) {
if(action->runnable == FALSE) {
crm_debug_3("Skipping pseudo-op: %s run=%d, pseudo=%d",
action->uuid, action->runnable, action->pseudo);
} else {
crm_debug_2("Starting due to: %s", action->uuid);
crm_debug_3("%s run=%d, pseudo=%d",
action->uuid, action->runnable, action->pseudo);
*starting = TRUE;
}
}
);
}
void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
gboolean child_starting = FALSE;
gboolean child_stopping = FALSE;
action_t *stop = NULL;
action_t *start = NULL;
action_t *action_complete = NULL;
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_debug_2("Creating actions for %s", rsc->id);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->create_actions(child_rsc, data_set);
clone_update_pseudo_status(
child_rsc, &child_stopping, &child_starting);
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);
action_complete = custom_action(
rsc, started_key(rsc),
CRMD_ACTION_STARTED, NULL, !child_starting, TRUE, data_set);
start->pseudo = TRUE;
start->runnable = TRUE;
action_complete->pseudo = TRUE;
action_complete->runnable = TRUE;
action_complete->priority = INFINITY;
/* crm_err("Upgrading priority for %s to INFINITY", action_complete->uuid); */
child_starting_constraints(clone_data, rsc, NULL, last_start_rsc, data_set);
clone_create_notifications(
rsc, start, action_complete, data_set);
/* stop */
stop = stop_action(rsc, NULL, !child_stopping);
action_complete = custom_action(
rsc, stopped_key(rsc),
CRMD_ACTION_STOPPED, NULL, !child_stopping, TRUE, data_set);
stop->pseudo = TRUE;
stop->runnable = TRUE;
action_complete->pseudo = TRUE;
action_complete->runnable = TRUE;
action_complete->priority = INFINITY;
/* crm_err("Upgrading priority for %s to INFINITY", action_complete->uuid); */
child_stopping_constraints(clone_data, rsc, NULL, last_stop_rsc, data_set);
clone_create_notifications(rsc, stop, action_complete, data_set);
rsc->actions = rsc->actions;
if(stop->post_notified != NULL && start->pre_notify != NULL) {
order_actions(stop->post_notified, start->pre_notify, pe_order_optional);
}
}
void
clone_create_notifications(
resource_t *rsc, action_t *action, action_t *action_complete,
pe_working_set_t *data_set)
{
/*
* pre_notify -> pre_notify_complete -> pseudo_action
* -> (real actions) -> pseudo_action_complete
* -> post_notify -> post_notify_complete
*
* if the pre_noitfy requires confirmation,
* then a list of confirmations will be added as triggers
* to pseudo_action in clone_expand()
*/
action_t *notify = NULL;
action_t *notify_complete = NULL;
enum action_tasks task;
char *notify_key = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if(is_not_set(rsc->flags, pe_rsc_notify)) {
return;
}
task = text2task(action->task);
/* create pre_notify */
notify_key = generate_notify_key(
rsc->id, "pre", action->task);
notify = custom_action(rsc, notify_key,
CRMD_ACTION_NOTIFY, NULL,
action->optional, TRUE, data_set);
add_hash_param(notify->meta, "notify_type", "pre");
add_hash_param(notify->meta, "notify_operation", action->task);
if(clone_data->notify_confirm) {
add_hash_param(notify->meta, "notify_confirm", "yes");
} else {
add_hash_param(notify->meta, "notify_confirm", "no");
}
/* create pre_notify_complete */
notify_key = generate_notify_key(
rsc->id, "confirmed-pre", action->task);
notify_complete = custom_action(rsc, notify_key,
CRMD_ACTION_NOTIFIED, NULL,
action->optional, TRUE, data_set);
add_hash_param(notify_complete->meta, "notify_type", "pre");
add_hash_param(notify_complete->meta, "notify_operation", action->task);
if(clone_data->notify_confirm) {
add_hash_param(notify->meta, "notify_confirm", "yes");
} else {
add_hash_param(notify->meta, "notify_confirm", "no");
}
notify->pseudo = TRUE;
notify->runnable = TRUE;
notify_complete->pseudo = TRUE;
notify_complete->runnable = TRUE;
/* pre_notify before pre_notify_complete */
custom_action_order(
rsc, NULL, notify,
rsc, NULL, notify_complete,
pe_order_optional, data_set);
/* pre_notify_complete before action */
custom_action_order(
rsc, NULL, notify_complete,
rsc, NULL, action,
pe_order_optional, data_set);
action->pre_notify = notify;
action->pre_notified = notify_complete;
/* create post_notify */
notify_key = generate_notify_key
(rsc->id, "post", action->task);
notify = custom_action(rsc, notify_key,
CRMD_ACTION_NOTIFY, NULL,
action_complete->optional, TRUE, data_set);
add_hash_param(notify->meta, "notify_type", "post");
add_hash_param(notify->meta, "notify_operation", action->task);
if(clone_data->notify_confirm) {
add_hash_param(notify->meta, "notify_confirm", "yes");
} else {
add_hash_param(notify->meta, "notify_confirm", "no");
}
/* action_complete before post_notify */
custom_action_order(
rsc, NULL, action_complete,
rsc, NULL, notify,
pe_order_optional, data_set);
/* create post_notify_complete */
notify_key = generate_notify_key(
rsc->id, "confirmed-post", action->task);
notify_complete = custom_action(rsc, notify_key,
CRMD_ACTION_NOTIFIED, NULL,
action->optional, TRUE, data_set);
add_hash_param(notify_complete->meta, "notify_type", "pre");
add_hash_param(notify_complete->meta, "notify_operation", action->task);
if(clone_data->notify_confirm) {
add_hash_param(notify->meta, "notify_confirm", "yes");
} else {
add_hash_param(notify->meta, "notify_confirm", "no");
}
notify->pseudo = TRUE;
notify->runnable = TRUE;
notify->priority = INFINITY;
notify->runnable = action_complete->runnable;
notify_complete->pseudo = TRUE;
notify_complete->runnable = TRUE;
notify_complete->priority = INFINITY;
notify_complete->runnable = action_complete->runnable;
/* post_notify before post_notify_complete */
custom_action_order(
rsc, NULL, notify,
rsc, NULL, notify_complete,
pe_order_optional, data_set);
action->post_notify = notify;
action->post_notified = notify_complete;
if(safe_str_eq(action->task, CRMD_ACTION_STOP)) {
/* post_notify_complete before start */
custom_action_order(
rsc, NULL, notify_complete,
rsc, start_key(rsc), NULL,
pe_order_optional, data_set);
} else if(safe_str_eq(action->task, CRMD_ACTION_START)) {
/* post_notify_complete before promote */
custom_action_order(
rsc, NULL, notify_complete,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
} else if(safe_str_eq(action->task, CRMD_ACTION_DEMOTE)) {
/* post_notify_complete before promote */
custom_action_order(
rsc, NULL, notify_complete,
rsc, stop_key(rsc), NULL,
pe_order_optional, data_set);
}
}
void
child_starting_constraints(
clone_variant_data_t *clone_data,
resource_t *rsc, resource_t *child, resource_t *last,
pe_working_set_t *data_set)
{
if(child == NULL && last == NULL) {
crm_debug("%s has no active children", rsc->id);
return;
}
if(child != NULL) {
order_start_start(
rsc, child, pe_order_runnable_left|pe_order_implies_left_printed);
custom_action_order(
child, start_key(child), NULL,
rsc, started_key(rsc), NULL,
pe_order_implies_right_printed, data_set);
}
if(clone_data->ordered) {
if(child == NULL) {
/* last child start before global started */
custom_action_order(
last, start_key(last), NULL,
rsc, started_key(rsc), NULL,
pe_order_runnable_left, data_set);
} else if(last == NULL) {
/* global start before first child start */
order_start_start(
rsc, child, pe_order_implies_left);
} else {
/* child/child relative start */
order_start_start(last, child, pe_order_implies_left);
}
}
}
void
child_stopping_constraints(
clone_variant_data_t *clone_data,
resource_t *rsc, resource_t *child, resource_t *last,
pe_working_set_t *data_set)
{
if(child == NULL && last == NULL) {
crm_debug("%s has no active children", rsc->id);
return;
}
if(child != NULL) {
order_stop_stop(rsc, child, pe_order_shutdown|pe_order_implies_left_printed);
custom_action_order(
child, stop_key(child), NULL,
rsc, stopped_key(rsc), NULL,
pe_order_implies_right_printed, data_set);
}
if(clone_data->ordered) {
if(last == NULL) {
/* first child stop before global stopped */
custom_action_order(
child, stop_key(child), NULL,
rsc, stopped_key(rsc), NULL,
pe_order_runnable_left, data_set);
} else if(child == NULL) {
/* global stop before last child stop */
order_stop_stop(
rsc, last, pe_order_implies_left);
} else {
/* child/child relative stop */
order_stop_stop(child, last, pe_order_implies_left);
}
}
}
void
clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
resource_t *last_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
native_internal_constraints(rsc, data_set);
/* global stop before stopped */
custom_action_order(
rsc, stop_key(rsc), NULL,
rsc, stopped_key(rsc), NULL,
pe_order_runnable_left, data_set);
/* global start before started */
custom_action_order(
rsc, start_key(rsc), NULL,
rsc, started_key(rsc), NULL,
pe_order_runnable_left, data_set);
/* global stopped before start */
custom_action_order(
rsc, stopped_key(rsc), NULL,
rsc, start_key(rsc), NULL,
pe_order_optional, data_set);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->internal_constraints(child_rsc, data_set);
child_starting_constraints(
clone_data, rsc, child_rsc, last_rsc, data_set);
child_stopping_constraints(
clone_data, rsc, child_rsc, last_rsc, data_set);
last_rsc = child_rsc;
);
}
resource_t*
find_compatible_child(
resource_t *local_child, resource_t *rsc, enum rsc_role_e filter, gboolean current)
{
node_t *local_node = NULL;
node_t *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 == NULL) {
crm_debug("Can't colocate unrunnable child %s with %s",
local_child->id, rsc->id);
return NULL;
}
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
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_debug_2("Filtered %s", child_rsc->id);
continue;
}
if(node && local_node && node->details == local_node->details) {
crm_info("Colocating %s with %s on %s",
local_child->id, child_rsc->id, node->details->uname);
return child_rsc;
}
);
crm_debug("Can't colocate child %s with %s",
local_child->id, rsc->id);
return NULL;
}
void clone_rsc_colocation_lh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
gboolean do_interleave = FALSE;
resource_t *rsc = constraint->rsc_lh;
clone_variant_data_t *clone_data = NULL;
clone_variant_data_t *clone_data_rh = NULL;
if(rsc == 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;
} else {
crm_debug_4("Processing constraints from %s", rsc->id);
}
get_clone_variant_data(clone_data, rsc);
if(constraint->rsc_rh->variant == pe_clone
|| constraint->rsc_rh->variant == pe_master) {
get_clone_variant_data(
clone_data_rh, constraint->rsc_rh);
if(clone_data->clone_node_max
!= clone_data_rh->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->interleave) {
do_interleave = TRUE;
} else if(constraint->score >= INFINITY) {
GListPtr lhs = NULL, rhs = NULL;
lhs = rsc_lh->allowed_nodes;
slist_iter(
child_rsc, resource_t, rsc_rh->children, lpc,
node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
if(chosen != NULL) {
rhs = g_list_append(rhs, chosen);
}
);
- rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE);
+ rsc_lh->allowed_nodes = node_list_exclude(lhs, rhs);
pe_free_shallow_adv(rhs, FALSE);
pe_free_shallow(lhs);
return;
}
} else if(constraint->score >= INFINITY) {
crm_config_err("Manditory co-location of clones (%s) with other"
" non-clone (%s) resources is not supported",
rsc_lh->id, rsc_rh->id);
return;
}
if(do_interleave) {
resource_t *rh_child = NULL;
slist_iter(lh_child, resource_t, rsc->children, lpc,
CRM_ASSERT(lh_child != NULL);
rh_child = find_compatible_child(
lh_child, rsc_rh, RSC_ROLE_UNKNOWN, FALSE);
if(rh_child == NULL) {
crm_debug_2("No match found for %s", lh_child->id);
continue;
}
crm_debug("Interleaving %s with %s", lh_child->id, rh_child->id);
lh_child->cmds->rsc_colocation_lh(
lh_child, rh_child, constraint);
);
return;
}
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint);
);
}
void clone_rsc_colocation_rh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
clone_variant_data_t *clone_data = NULL;
CRM_CHECK(rsc_lh != NULL, return);
CRM_CHECK(rsc_lh->variant == pe_native, return);
get_clone_variant_data(clone_data, rsc_rh);
crm_debug_3("Processing constraint %s: %d", constraint->id, constraint->score);
if(rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
} else if(is_set(rsc_rh->flags, pe_rsc_provisional)) {
crm_debug_3("%s is still provisional", rsc_rh->id);
return;
} else if(constraint->score >= INFINITY) {
GListPtr lhs = NULL, rhs = NULL;
lhs = rsc_lh->allowed_nodes;
slist_iter(
child_rsc, resource_t, rsc_rh->children, lpc,
node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
if(chosen != NULL) {
rhs = g_list_append(rhs, chosen);
}
);
- rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE);
+ rsc_lh->allowed_nodes = node_list_exclude(lhs, rhs);
pe_free_shallow_adv(rhs, FALSE);
pe_free_shallow(lhs);
return;
}
slist_iter(
child_rsc, resource_t, rsc_rh->children, lpc,
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
);
}
void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set)
{
resource_t *r1 = NULL;
resource_t *r2 = NULL;
gboolean do_interleave = FALSE;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug_2("%s->%s", order->lh_action_task, order->rh_action_task);
r1 = uber_parent(rsc);
r2 = uber_parent(order->rh_rsc);
if(r1 == r2) {
native_rsc_order_lh(rsc, order, data_set);
return;
}
if(order->rh_rsc->variant == pe_clone
|| order->rh_rsc->variant == pe_master) {
clone_variant_data_t *clone_data_rh = NULL;
get_clone_variant_data(clone_data_rh, order->rh_rsc);
if(clone_data->clone_node_max != clone_data_rh->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",
rsc->id, order->rh_rsc->id);
/* only the LHS side needs to be labeled as interleave */
} else if(clone_data->interleave) {
do_interleave = TRUE;
}
}
if(do_interleave && order->rh_rsc) {
resource_t *lh_child = NULL;
resource_t *rh_saved = order->rh_rsc;
gboolean current = FALSE;
if(strstr(order->lh_action_task, "_stop_0") || strstr(order->lh_action_task, "_demote_0")) {
current = TRUE;
}
slist_iter(
rh_child, resource_t, rh_saved->children, lpc,
CRM_ASSERT(rh_child != NULL);
lh_child = find_compatible_child(rh_child, rsc, RSC_ROLE_UNKNOWN, current);
if(lh_child == NULL) {
crm_debug_2("No match found for %s", rh_child->id);
continue;
}
crm_debug("Interleaving %s with %s", lh_child->id, rh_child->id);
order->rh_rsc = rh_child;
lh_child->cmds->rsc_order_lh(lh_child, order, data_set);
order->rh_rsc = rh_saved;
);
} else {
#if 0
if(order->type != pe_order_optional) {
crm_debug("Upgraded ordering constraint %d - 0x%.6x", order->id, order->type);
native_rsc_order_lh(rsc, order, data_set);
}
#endif
if(order->type & pe_order_implies_left) {
if(rsc->variant == order->rh_rsc->variant) {
crm_debug_2("Clone-to-clone ordering: %s -> %s 0x%.6x",
order->lh_action_task, order->rh_action_task, order->type);
/* stop instances on the same nodes as stopping RHS instances */
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
native_rsc_order_lh(child_rsc, order, data_set);
);
} else {
/* stop everything */
crm_debug_2("Clone-to-* ordering: %s -> %s 0x%.6x",
order->lh_action_task, order->rh_action_task, order->type);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
native_rsc_order_lh(child_rsc, order, data_set);
);
}
}
convert_non_atomic_task(rsc, order, FALSE);
native_rsc_order_lh(rsc, order, data_set);
}
if(is_set(rsc->flags, pe_rsc_notify)) {
order->type = pe_order_optional;
convert_non_atomic_task(rsc, order, TRUE);
native_rsc_order_lh(rsc, order, data_set);
}
}
void clone_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug_2("%s->%s", lh_action->uuid, order->rh_action_task);
if(safe_str_eq(CRM_OP_PROBED, lh_action->uuid)) {
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->rsc_order_rh(lh_action, child_rsc, order);
);
if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED
&& rsc->fns->state(rsc, FALSE) > RSC_ROLE_STOPPED) {
order->type |= pe_order_implies_right;
}
}
native_rsc_order_rh(lh_action, rsc, order);
}
void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug_3("Processing location constraint %s for %s",
constraint->id, rsc->id);
native_rsc_location(rsc, constraint);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->rsc_location(child_rsc, constraint);
);
}
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, int clones,
char **rsc_list, char **node_list, char **uuid_list)
{
const char *uname = NULL;
const char *rsc_id = NULL;
const char *last_rsc_id = NULL;
CRM_CHECK(list != NULL, return);
if(rsc_list) {
CRM_CHECK(*rsc_list == NULL, *rsc_list = NULL);
}
if(node_list) {
CRM_CHECK(*node_list == NULL, *node_list = NULL);
}
slist_iter(entry, notify_entry_t, list, lpc,
CRM_CHECK(entry != NULL, continue);
CRM_CHECK(entry->rsc != NULL, continue);
CRM_CHECK(entry->node != NULL, continue);
rsc_id = entry->rsc->id;
uname = entry->node->details->uname;
CRM_ASSERT(uname != NULL);
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_debug_5("Adding %s (%dc) at offset %d",
rsc_id, len-2, existing_len);
crm_realloc(*rsc_list, len + existing_len);
sprintf(*rsc_list + existing_len, "%s ", rsc_id);
}
if(node_list != NULL) {
int existing_len = 0;
int len = 2 + strlen(uname);
if(node_list && *node_list) {
existing_len = strlen(*node_list);
}
crm_debug_5("Adding %s (%dc) at offset %d",
uname, len-2, existing_len);
crm_realloc(*node_list, len + existing_len);
sprintf(*node_list + existing_len, "%s ", uname);
}
);
}
static void mark_notifications_required(resource_t *rsc, enum action_tasks task, gboolean top)
{
char *key = NULL;
char *key_complete = NULL;
const char *task_s = task2text(task);
if(top) {
key = generate_op_key(rsc->id, task_s, 0);
key_complete = generate_op_key(rsc->id, task2text(task+1), 0);
}
slist_iter(action, action_t, rsc->actions, lpc,
if(action->optional == FALSE) {
continue;
}
if(safe_str_eq(action->uuid, key)
|| safe_str_eq(action->uuid, key_complete)) {
crm_debug_3("Marking top-level action %s as required", action->uuid);
action->optional = FALSE;
}
if(strstr(action->uuid, task_s)) {
if(safe_str_eq(CRMD_ACTION_NOTIFIED, action->task)
|| safe_str_eq(CRMD_ACTION_NOTIFY, action->task)) {
crm_debug_3("Marking %s as required", action->uuid);
action->optional = FALSE;
}
}
);
slist_iter(
child, resource_t, rsc->children, lpc,
mark_notifications_required(child, task, FALSE);
);
}
void clone_expand(resource_t *rsc, pe_working_set_t *data_set)
{
char *rsc_list = NULL;
char *node_list = NULL;
char *uuid_list = NULL;
notify_data_t *n_data = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_malloc0(n_data, sizeof(notify_data_t));
n_data->keys = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
crm_debug_2("Processing actions from %s", rsc->id);
if(is_set(rsc->flags, pe_rsc_notify)) {
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
slist_iter(
op, action_t, rsc->actions, lpc2,
child_rsc->cmds->create_notify_element(
child_rsc, op, n_data, data_set);
);
);
}
/* expand the notify data */
if(is_set(rsc->flags, pe_rsc_notify) && n_data->stop) {
n_data->stop = g_list_sort(
n_data->stop, sort_notify_entries);
rsc_list = NULL; node_list = NULL;
expand_list(n_data->stop, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_stop_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_stop_uname"), node_list);
if(rsc_list != NULL) {
mark_notifications_required(rsc, stop_rsc, TRUE);
}
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->start) {
n_data->start = g_list_sort(
n_data->start, sort_notify_entries);
rsc_list = NULL; node_list = NULL;
expand_list(n_data->start, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_start_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_start_uname"), node_list);
mark_notifications_required(rsc, start_rsc, TRUE);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->demote) {
n_data->demote = g_list_sort(
n_data->demote, sort_notify_entries);
rsc_list = NULL; node_list = NULL;
expand_list(n_data->demote, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_demote_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_demote_uname"), node_list);
mark_notifications_required(rsc, action_demote, TRUE);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->promote) {
n_data->promote = g_list_sort(
n_data->promote, sort_notify_entries);
rsc_list = NULL; node_list = NULL; uuid_list = NULL;
expand_list(n_data->promote, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_promote_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_promote_uname"), node_list);
mark_notifications_required(rsc, action_promote, TRUE);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->active) {
n_data->active = g_list_sort(
n_data->active, sort_notify_entries);
rsc_list = NULL; node_list = NULL; uuid_list = NULL;
expand_list(n_data->active, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_active_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_active_uname"), node_list);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->slave) {
n_data->slave = g_list_sort(
n_data->slave, sort_notify_entries);
rsc_list = NULL; node_list = NULL; uuid_list = NULL;
expand_list(n_data->slave, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_slave_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_slave_uname"), node_list);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->master) {
n_data->master = g_list_sort(
n_data->master, sort_notify_entries);
rsc_list = NULL; node_list = NULL; uuid_list = NULL;
expand_list(n_data->master, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_master_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_master_uname"), node_list);
}
if(is_set(rsc->flags, pe_rsc_notify) && n_data->inactive) {
n_data->inactive = g_list_sort(
n_data->inactive, sort_notify_entries);
rsc_list = NULL; node_list = NULL; uuid_list = NULL;
expand_list(n_data->inactive, clone_data->clone_max,
&rsc_list, &node_list, &uuid_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_inactive_resource"), rsc_list);
g_hash_table_insert(
n_data->keys,
crm_strdup("notify_inactive_uname"), node_list);
}
/* yes, we DO need this second loop */
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->cmds->expand(child_rsc, data_set);
);
/* slist_iter( */
/* action, action_t, rsc->actions, lpc2, */
/* if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { */
/* action->meta_xml = notify_xml; */
/* } */
/* ); */
native_expand(rsc, data_set);
/* destroy the notify_data */
pe_free_shallow(n_data->stop);
pe_free_shallow(n_data->start);
pe_free_shallow(n_data->demote);
pe_free_shallow(n_data->promote);
pe_free_shallow(n_data->master);
pe_free_shallow(n_data->slave);
pe_free_shallow(n_data->active);
pe_free_shallow(n_data->inactive);
g_hash_table_destroy(n_data->keys);
crm_free(n_data);
}
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);
}
static resource_t *find_instance_on(resource_t *rsc, node_t *node)
{
slist_iter(child, resource_t, rsc->children, lpc,
slist_iter(known ,node_t, child->known_on, lpc2,
if(node->details == known->details) {
return child;
}
);
);
return NULL;
}
gboolean
clone_create_probe(resource_t *rsc, node_t *node, action_t *complete,
gboolean force, pe_working_set_t *data_set)
{
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(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 */
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
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);
}
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
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;
}
diff --git a/pengine/master.c b/pengine/master.c
index 89dd98eb30..390d767d42 100644
--- a/pengine/master.c
+++ b/pengine/master.c
@@ -1,851 +1,854 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <crm_internal.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <lib/crm/pengine/utils.h>
#include <utils.h>
#define VARIANT_CLONE 1
#include <lib/crm/pengine/variant.h>
extern gint sort_clone_instance(gconstpointer a, gconstpointer b);
+void node_list_update_one(GListPtr list1, node_t *other, int score);
extern void clone_create_notifications(
resource_t *rsc, action_t *action, action_t *action_complete,
pe_working_set_t *data_set);
extern 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_debug_4("Ordered version (last node)");
/* last child promote before promoted started */
custom_action_order(
last, promote_key(last), NULL,
rsc, promoted_key(rsc), NULL,
type, data_set);
}
return;
}
/* child promote before global promoted */
custom_action_order(
child, promote_key(child), NULL,
rsc, promoted_key(rsc), NULL,
type, data_set);
/* global promote before child promote */
custom_action_order(
rsc, promote_key(rsc), NULL,
child, promote_key(child), NULL,
type, data_set);
if(clone_data->ordered) {
crm_debug_4("Ordered version");
if(last == NULL) {
/* global promote before first child promote */
last = rsc;
} /* else: child/child relative promote */
order_start_start(last, child, type);
custom_action_order(
last, promote_key(last), NULL,
child, promote_key(child), NULL,
type, data_set);
} else {
crm_debug_4("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_debug_4("Ordered version (last node)");
/* global demote before first child demote */
custom_action_order(
rsc, demote_key(rsc), NULL,
last, demote_key(last), NULL,
pe_order_implies_left, data_set);
}
return;
}
/* child demote before global demoted */
custom_action_order(
child, demote_key(child), NULL,
rsc, demoted_key(rsc), NULL,
pe_order_implies_right_printed, data_set);
/* global demote before child demote */
custom_action_order(
rsc, demote_key(rsc), NULL,
child, demote_key(child), NULL,
pe_order_implies_left_printed, data_set);
if(clone_data->ordered && last != NULL) {
crm_debug_4("Ordered version");
/* child/child relative demote */
custom_action_order(child, demote_key(child), NULL,
last, demote_key(last), NULL,
type, data_set);
} else if(clone_data->ordered) {
crm_debug_4("Ordered version (1st node)");
/* first child stop before global stopped */
custom_action_order(
child, demote_key(child), NULL,
rsc, demoted_key(rsc), NULL,
type, data_set);
} else {
crm_debug_4("Un-ordered version");
}
}
static void
master_update_pseudo_status(
resource_t *rsc, gboolean *demoting, gboolean *promoting)
{
if(rsc->children) {
slist_iter(child, resource_t, rsc->children, lpc,
master_update_pseudo_status(child, demoting, promoting)
);
return;
}
CRM_ASSERT(demoting != NULL);
CRM_ASSERT(promoting != NULL);
slist_iter(
action, action_t, rsc->actions, lpc,
if(*promoting && *demoting) {
return;
} else if(action->optional) {
continue;
} else if(safe_str_eq(CRMD_ACTION_DEMOTE, action->task)) {
*demoting = TRUE;
} else if(safe_str_eq(CRMD_ACTION_PROMOTE, action->task)) {
*promoting = TRUE;
}
);
}
#define apply_master_location(list) \
slist_iter( \
cons, rsc_to_node_t, list, lpc2, \
cons_node = NULL; \
if(cons->role_filter == RSC_ROLE_MASTER) { \
crm_debug_2("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_debug_2("\t%s: %d->%d (%d)", child_rsc->id, \
child_rsc->priority, new_priority, cons_node->weight); \
child_rsc->priority = new_priority; \
} \
);
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;
int level = LOG_DEBUG_2;
#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) {
slist_iter(
child, resource_t, rsc->children, lpc,
if(can_be_master(child) == NULL) {
do_crm_log(level, "Child %s of %s can't be promoted", child->id, rsc->id);
return NULL;
}
);
}
node = rsc->fns->location(rsc, NULL, FALSE);
if(rsc->priority < 0) {
do_crm_log(level, "%s cannot be master: preference: %d",
rsc->id, rsc->priority);
return NULL;
} else if(node == NULL) {
do_crm_log(level, "%s cannot be master: not allocated",
rsc->id);
return NULL;
} else if(can_run_resources(node) == FALSE) {
do_crm_log(level, "Node cant run any resources: %s",
node->details->uname);
return NULL;
}
get_clone_variant_data(clone_data, parent);
local_node = pe_find_node_id(
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) {
return local_node;
} else {
do_crm_log(level, "%s cannot be master on %s: node full",
rsc->id, node->details->uname);
}
return NULL;
}
static gint sort_master_instance(gconstpointer a, gconstpointer b)
{
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 ) {
return rc;
}
if(role1 > role2) {
return -1;
} else if(role1 < role2) {
return 1;
}
return sort_clone_instance(a, b);
}
static void master_promotion_order(resource_t *rsc)
{
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_debug_2("Merging weights for %s", rsc->id);
slist_iter(
child, resource_t, rsc->children, lpc,
crm_debug_2("%s: %d", child->id, child->sort_index);
);
dump_node_scores(LOG_DEBUG_3, rsc, "Before", rsc->allowed_nodes);
slist_iter(
child, resource_t, rsc->children, lpc,
chosen = child->fns->location(child, NULL, FALSE);
if(chosen == NULL || child->sort_index < 0) {
crm_debug_3("Skipping %s", child->id);
continue;
}
node = (node_t*)pe_find_node_id(
rsc->allowed_nodes, chosen->details->id);
CRM_ASSERT(node != NULL);
/* adds in master preferences and rsc_location.role=Master */
node->weight = merge_weights(child->sort_index, node->weight);
);
dump_node_scores(LOG_DEBUG_3, rsc, "Middle", rsc->allowed_nodes);
slist_iter(
constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc,
/* (re-)adds location preferences of resource that wish to be
* colocated with the master instance
*/
if(constraint->role_rh == RSC_ROLE_MASTER) {
rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights(
constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
constraint->score/INFINITY, TRUE);
}
);
dump_node_scores(LOG_DEBUG_3, rsc, "After", rsc->allowed_nodes);
/* write them back and sort */
slist_iter(
child, resource_t, rsc->children, lpc,
chosen = child->fns->location(child, NULL, FALSE);
if(chosen == NULL || child->sort_index < 0) {
crm_debug_2("%s: %d", child->id, child->sort_index);
continue;
}
node = (node_t*)pe_find_node_id(
rsc->allowed_nodes, chosen->details->id);
CRM_ASSERT(node != NULL);
child->sort_index = node->weight;
crm_debug_2("%s: %d", child->id, child->sort_index);
);
rsc->children = g_list_sort(rsc->children, sort_master_instance);
}
int
master_score(resource_t *rsc, node_t *node, int not_set_value)
{
char *attr_name;
char *name = rsc->id;
const char *attr_value;
int score = not_set_value, len = 0;
if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED) {
return score;
}
if(rsc->running_on) {
node_t *match = pe_find_node_id(rsc->allowed_nodes, node->details->id);
if(match->weight < 0) {
crm_debug_2("%s on %s has score: %d - ignoring master pref",
rsc->id, match->details->uname, match->weight);
return score;
}
}
#if 0
if(rsc->clone_name) {
name = rsc->clone_name;
crm_err("%s ::= %s", rsc->id, rsc->clone_name);
}
#endif
len = 8 + strlen(name);
crm_malloc0(attr_name, len);
sprintf(attr_name, "master-%s", name);
crm_debug_3("looking for %s on %s", attr_name,
node->details->uname);
attr_value = g_hash_table_lookup(
node->details->attrs, attr_name);
if(attr_value == NULL) {
crm_free(attr_name);
len = 8 + strlen(rsc->long_name);
crm_malloc0(attr_name, len);
sprintf(attr_name, "master-%s", rsc->long_name);
crm_debug_3("looking for %s on %s", attr_name,
node->details->uname);
attr_value = g_hash_table_lookup(
node->details->attrs, attr_name);
}
if(attr_value != NULL) {
crm_debug_2("%s[%s] = %s", attr_name,
node->details->uname, crm_str(attr_value));
score = char2score(attr_value);
}
crm_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;
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;
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
slist_iter(
node, node_t, child_rsc->allowed_nodes, lpc,
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);
new_score = merge_weights(node->weight, score);
if(new_score != node->weight) {
crm_debug_2("\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_debug_2("\t%s: Updating priority (%d->%d)",
child_rsc->id, child_rsc->priority, new_score);
child_rsc->priority = new_score;
}
);
);
}
static void set_role(resource_t *rsc, enum rsc_role_e role, gboolean current)
{
if(current) {
if(rsc->variant == pe_native && rsc->running_on != NULL && rsc->role > role) {
crm_debug_6("Filtering change %s.role = %s (was %s)", rsc->id, role2text(role), role2text(rsc->role));
} else if(rsc->role < role) {
crm_debug_5("Set %s.role = %s (was %s)", rsc->id, role2text(role), role2text(rsc->role));
rsc->role = role;
}
} else {
if(rsc->next_role < role) {
crm_debug_5("Set %s.next_role = %s (was %s)", rsc->id, role2text(role), role2text(rsc->next_role));
rsc->next_role = role;
if(role == RSC_ROLE_MASTER) {
add_hash_param(rsc->parameters, crm_meta_name("role"), role2text(role));
}
}
}
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
set_role(child_rsc, role, current);
);
}
node_t *
master_color(resource_t *rsc, pe_working_set_t *data_set)
{
int promoted = 0;
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);
apply_master_prefs(rsc);
clone_color(rsc, data_set);
/* count now tracks the number of masters allocated */
slist_iter(node, node_t, rsc->allowed_nodes, lpc,
node->count = 0;
);
/*
* assign priority
*/
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
GListPtr list = NULL;
crm_debug_2("Assigning priority for %s", child_rsc->id);
if(child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
set_role(child_rsc, RSC_ROLE_SLAVE, 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:
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:
/* the only reason we should be here is if
* we're re-creating actions after a stonith
*/
promoted++;
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);
slist_iter(
cons, rsc_colocation_t, child_rsc->rsc_cons, lpc2,
child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons);
);
child_rsc->sort_index = child_rsc->priority;
crm_debug_2("Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);
if(next_role == RSC_ROLE_MASTER) {
child_rsc->sort_index = INFINITY;
}
);
master_promotion_order(rsc);
/* mark the first N as masters */
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
chosen = NULL;
crm_debug_2("Processing %s", child_rsc->id);
chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
do_crm_log(scores_log_level, "%s promotion score on %s: %d",
child_rsc->id, chosen?chosen->details->uname:"none", child_rsc->sort_index);
chosen = NULL; /* nuke 'chosen' so that we don't promote more than the
* required number of instances
*/
if(promoted < clone_data->master_max) {
chosen = can_be_master(child_rsc);
}
crm_debug("%s master score: %d", child_rsc->id, child_rsc->priority);
if(chosen == NULL) {
next_role = child_rsc->fns->state(child_rsc, FALSE);
if(next_role == RSC_ROLE_STARTED) {
set_role(child_rsc, RSC_ROLE_SLAVE, FALSE);
}
continue;
}
chosen->count++;
crm_info("Promoting %s (%s %s)",
child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
set_role(child_rsc, RSC_ROLE_MASTER, FALSE);
clone_data->masters_allocated++;
promoted++;
);
crm_info("%s: Promoted %d instances of a possible %d to master",
rsc->id, promoted, clone_data->master_max);
return NULL;
}
void master_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
action_t *action = NULL;
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);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
gboolean child_promoting = FALSE;
gboolean child_demoting = FALSE;
crm_debug_2("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_debug_2("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),
CRMD_ACTION_PROMOTED, NULL, !any_promoting, TRUE, data_set);
action->pseudo = TRUE;
action->runnable = FALSE;
action_complete->pseudo = TRUE;
action_complete->runnable = FALSE;
action_complete->priority = INFINITY;
if(clone_data->masters_allocated > 0) {
action->runnable = TRUE;
action_complete->runnable = TRUE;
}
child_promoting_constraints(clone_data, pe_order_optional,
rsc, NULL, last_promote_rsc, data_set);
clone_create_notifications(rsc, action, action_complete, data_set);
/* demote */
action = demote_action(rsc, NULL, !any_demoting);
action_complete = custom_action(
rsc, demoted_key(rsc),
CRMD_ACTION_DEMOTED, NULL, !any_demoting, TRUE, data_set);
action_complete->priority = INFINITY;
action->pseudo = TRUE;
action->runnable = TRUE;
action_complete->pseudo = TRUE;
action_complete->runnable = TRUE;
child_demoting_constraints(clone_data, pe_order_optional,
rsc, NULL, last_demote_rsc, data_set);
clone_create_notifications(rsc, action, action_complete, data_set);
/* restore the correct priority */
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
child_rsc->priority = rsc->priority;
);
}
void
master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
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 */
custom_action_order(
rsc, stopped_key(rsc), NULL,
rsc, start_key(rsc), NULL,
pe_order_optional, data_set);
/* global stopped before promote */
custom_action_order(
rsc, stopped_key(rsc), NULL,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
/* global demoted before start */
custom_action_order(
rsc, demoted_key(rsc), NULL,
rsc, start_key(rsc), NULL,
pe_order_optional, data_set);
/* global started before promote */
custom_action_order(
rsc, started_key(rsc), NULL,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
/* global demoted before stop */
custom_action_order(
rsc, demoted_key(rsc), NULL,
rsc, stop_key(rsc), NULL,
pe_order_optional, data_set);
/* global demote before demoted */
custom_action_order(
rsc, demote_key(rsc), NULL,
rsc, demoted_key(rsc), NULL,
pe_order_optional, data_set);
/* global demoted before promote */
custom_action_order(
rsc, demoted_key(rsc), NULL,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
slist_iter(
child_rsc, resource_t, rsc->children, lpc,
/* child demote before promote */
custom_action_order(
child_rsc, demote_key(child_rsc), NULL,
child_rsc, promote_key(child_rsc), NULL,
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_list_update_one(GListPtr list1, node_t *other, int score)
+void node_list_update_one(GListPtr list1, node_t *other, int score)
{
node_t *node = NULL;
if(other == NULL) {
return;
}
node = (node_t*)pe_find_node_id(list1, other->details->id);
if(node != NULL) {
crm_debug_2("%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)
{
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_debug_3("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_debug_2("Processing constraint %s: %d", constraint->id, constraint->score);
if(constraint->role_rh == RSC_ROLE_UNKNOWN) {
slist_iter(
child_rsc, resource_t, rsc_rh->children, lpc,
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
);
} else if(is_set(rsc_lh->flags, pe_rsc_provisional)) {
GListPtr lhs = NULL, rhs = NULL;
lhs = rsc_lh->allowed_nodes;
-
slist_iter(
child_rsc, resource_t, rsc_rh->children, lpc,
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_debug_3("Processing: %s", child_rsc->id);
if(chosen != NULL
&& next_role == constraint->role_rh) {
- crm_debug_3("Applying: %s %s", child_rsc->id,
- role2text(next_role));
- node_list_update_one(rsc_lh->allowed_nodes, chosen, constraint->score);
+ crm_debug_3("Applying: %s %s %s %d", child_rsc->id,
+ role2text(next_role), chosen->details->uname, constraint->score);
+ if(constraint->score < INFINITY) {
+ node_list_update_one(rsc_lh->allowed_nodes, chosen, constraint->score);
+ }
rhs = g_list_append(rhs, chosen);
}
);
/* Only do this if its not a master-master colocation
* Doing this unconditionally would prevent the slaves from being started
*/
- if(constraint->score > 0
- && (constraint->role_lh != RSC_ROLE_MASTER
- || constraint->role_rh != RSC_ROLE_MASTER)) {
- rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE);
- pe_free_shallow(lhs);
+ if(constraint->role_lh != RSC_ROLE_MASTER
+ || constraint->role_rh != RSC_ROLE_MASTER) {
+ if(constraint->score > 0) {
+ rsc_lh->allowed_nodes = node_list_exclude(lhs, rhs);
+ pe_free_shallow(lhs);
+ }
}
pe_free_shallow_adv(rhs, FALSE);
} 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_debug_2("%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;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 21, 10:42 AM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1664801
Default Alt Text
(104 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment