Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F7632480
utils.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
utils.c
View Options
/* $Id: utils.c,v 1.11 2006/08/14 09:14:45 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/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;
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(item);
}
}
node_t *
pe_find_node_id(GListPtr nodes, const char *id)
{
unsigned lpc = 0;
node_t *node = NULL;
for(lpc = 0; lpc < g_list_length(nodes); lpc++) {
node = g_list_nth_data(nodes, lpc);
if(safe_str_eq(node->details->id, id)) {
return node;
}
}
/* error */
return NULL;
}
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_CHECK(new_node != NULL, return 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
*/
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;
}
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>");
}
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(action != NULL) {
if(save_action) {
action->id = data_set->action_id++;
} else {
action->id = 0;
}
action->rsc = rsc;
action->task = task;
action->node = on_node;
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);
}
action->uuid = key;
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->node == NULL) {
action->runnable = FALSE;
} else if(rsc->is_managed == FALSE) {
crm_log_maybe(warn_level, "Action %s %s is for %s (unmanaged)",
action->uuid, task, rsc->id);
action->optional = TRUE;
/* action->runnable = FALSE; */
#if 0
} else if(action->node->details->unclean) {
crm_log_maybe(warn_level, "Action %s on %s is unrunnable (unclean)",
action->uuid, action->node?action->node->details->uname:"<none>");
action->runnable = FALSE;
#endif
} else if(action->node->details->online == FALSE) {
action->runnable = FALSE;
crm_log_maybe(warn_level, "Action %s on %s is unrunnable (offline)",
action->uuid, action->node->details->uname);
if(action->rsc->is_managed
&& save_action
&& a_task == stop_rsc) {
crm_log_maybe(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 %s (cancelled : quorum)",
action->node->details->uname,
action->task, rsc->id);
} 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 %s (cancelled : quorum freeze)",
action->node->details->uname,
action->task, rsc->id);
}
} else {
crm_debug_3("Action %s is runnable", action->uuid);
action->runnable = TRUE;
}
if(save_action) {
switch(a_task) {
case stop_rsc:
rsc->stopping = TRUE;
break;
case start_rsc:
rsc->starting = FALSE;
if(action->runnable) {
rsc->starting = TRUE;
}
break;
default:
break;
}
}
}
return action;
}
void
unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set)
{
int lpc = 0;
const char *class = NULL;
const char *value = NULL;
const char *fields[] = {
XML_LRM_ATTR_INTERVAL,
"timeout",
"start_delay",
};
CRM_CHECK(action->rsc != NULL, return);
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) {
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)";
}
class = g_hash_table_lookup(action->rsc->meta, "class");
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";
} else if(safe_str_eq(value, "ignore")) {
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->fail_role = RSC_ROLE_STOPPED;
value = "stop resource";
} else if(safe_str_eq(value, "restart")
|| safe_str_eq(value, "nothing")) {
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) {
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);
}
if(g_hash_table_lookup(action->meta, "timeout") == NULL) {
g_hash_table_insert(
action->meta, crm_strdup("timeout"),
crm_strdup(pe_pref(data_set->config_hash, "default-action-timeout")));
}
for(;lpc < DIMOF(fields); lpc++) {
value = g_hash_table_lookup(action->meta, fields[lpc]);
if(value != NULL) {
char *tmp_ms = NULL;
int tmp_i = crm_get_msec(value);
if(tmp_i < 0) {
tmp_i = 0;
}
tmp_ms = crm_itoa(tmp_i);
g_hash_table_replace(
action->meta, crm_strdup(fields[lpc]), tmp_ms);
}
}
}
crm_data_t *
find_rsc_op_entry(resource_t *rsc, const char *key)
{
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;
}
match_key = generate_op_key(
rsc->id, name, crm_get_msec(interval));
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) {
crm_log_maybe(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
log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details)
{
const char *node_uname = NULL;
const char *node_uuid = NULL;
if(action == NULL) {
crm_log_maybe(log_level, "%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
if(action->pseudo) {
node_uname = NULL;
node_uuid = NULL;
} else if(action->node != NULL) {
node_uname = action->node->details->uname;
node_uuid = action->node->details->id;
} else {
node_uname = "<none>";
node_uuid = NULL;
}
switch(text2task(action->task)) {
case stonith_node:
case shutdown_crm:
crm_log_maybe(log_level,
"%s%s%sAction %d: %s%s%s%s%s%s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->uuid,
node_uname?"\ton ":"",
node_uname?node_uname:"",
node_uuid?"\t\t(":"",
node_uuid?node_uuid:"",
node_uuid?")":"");
break;
default:
crm_log_maybe(log_level,
"%s%s%sAction %d: %s %s%s%s%s%s%s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->uuid,
safe_val3("<none>", action, rsc, id),
node_uname?"\ton ":"",
node_uname?node_uname:"",
node_uuid?"\t\t(":"",
node_uuid?node_uuid:"",
node_uuid?")":"");
break;
}
if(details) {
crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#if 1
crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#endif
crm_log_maybe(log_level+1, "\t\t====== End");
} else {
crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_list_length(action->actions_before),
g_list_length(action->actions_after));
}
}
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->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;
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)
{
CRM_CHECK(rsc->variant == pe_native, return);
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;
}
}
}
void
order_actions(
action_t *lh_action, action_t *rh_action, enum pe_ordering order)
{
action_wrapper_t *wrapper = NULL;
GListPtr list = NULL;
crm_debug_2("Ordering Action %s before %s",
lh_action->uuid, rh_action->uuid);
log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE);
log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE);
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = rh_action;
wrapper->type = order;
list = lh_action->actions_after;
list = g_list_append(list, wrapper);
lh_action->actions_after = list;
wrapper = NULL;
}
if(order != pe_ordering_recover) {
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = lh_action;
wrapper->type = order;
list = rh_action->actions_before;
list = g_list_append(list, wrapper);
rh_action->actions_before = list;
}
}
}
const char *
get_interval(crm_data_t *xml_op)
{
const char *interval_s = NULL;
interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
#if CRM_DEPRECATED_SINCE_2_0_4
if(interval_s == NULL) {
crm_data_t *params = NULL;
params = find_xml_node(xml_op, XML_TAG_PARAMS, FALSE);
if(params != NULL) {
interval_s = crm_element_value(
params, XML_LRM_ATTR_INTERVAL);
}
}
#endif
CRM_CHECK(interval_s != NULL,
crm_err("Invalid rsc op: %s", ID(xml_op)); return "0");
return interval_s;
}
#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 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,&a_status, &a_rc), sort_return(0));
CRM_CHECK(decode_transition_magic(
b_key,&b_uuid,&b_id,&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));
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Oct 16, 3:27 PM (5 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2536556
Default Alt Text
utils.c (31 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment