Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/pengine/native.c b/crm/pengine/native.c
index 0455fa8be3..5dede1b795 100644
--- a/crm/pengine/native.c
+++ b/crm/pengine/native.c
@@ -1,1612 +1,1607 @@
/* $Id: native.c,v 1.161 2006/08/17 07:17:15 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 <pengine.h>
#include <crm/pengine/rules.h>
#include <lib/crm/pengine/utils.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define DELETE_THEN_REFRESH 1
#define VARIANT_NATIVE 1
#include <lib/crm/pengine/variant.h>
resource_t *ultimate_parent(resource_t *rsc);
void node_list_update(GListPtr list1, GListPtr list2, int factor);
void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void create_notifications(resource_t *rsc, pe_working_set_t *data_set);
void Recurring(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set);
void pe_pre_notify(
resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set);
void pe_post_notify(
resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set);
gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set);
void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set);
gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
extern gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, },
/* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, },
/* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
};
gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, },
/* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, },
/* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, },
/* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, },
/* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, },
};
static gboolean
native_choose_node(resource_t *rsc)
{
/*
1. Sort by weight
2. color.chosen_node = the node (of those with the highest wieght)
with the fewest resources
3. remove color.chosen_node from all other colors
*/
GListPtr nodes = NULL;
node_t *chosen = NULL;
if(rsc->provisional == FALSE) {
return rsc->allocated_to?TRUE:FALSE;
}
crm_debug_3("Choosing node for %s from %d candidates",
rsc->id, g_list_length(rsc->allowed_nodes));
if(rsc->allowed_nodes) {
rsc->allowed_nodes = g_list_sort(
rsc->allowed_nodes, sort_node_weight);
nodes = rsc->allowed_nodes;
chosen = g_list_nth_data(nodes, 0);
}
return native_assign_node(rsc, nodes, chosen);
}
void native_set_cmds(resource_t *rsc)
{
}
int native_num_allowed_nodes(resource_t *rsc)
{
int num_nodes = 0;
if(rsc->next_role == RSC_ROLE_STOPPED) {
return 0;
}
crm_debug_4("Default case");
slist_iter(
this_node, node_t, rsc->allowed_nodes, lpc,
crm_debug_3("Rsc %s Checking %s: %d",
rsc->id, this_node->details->uname,
this_node->weight);
if(this_node->details->shutdown
|| this_node->details->online == FALSE) {
this_node->weight = -INFINITY;
}
if(this_node->weight < 0) {
continue;
/* } else if(this_node->details->unclean) { */
/* continue; */
}
num_nodes++;
);
crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes);
return num_nodes;
}
resource_t *
ultimate_parent(resource_t *rsc)
{
resource_t *parent = rsc;
while(parent->parent) {
parent = parent->parent;
}
return parent;
}
node_t *
native_color(resource_t *rsc, pe_working_set_t *data_set)
{
if(rsc->parent && rsc->parent->is_allocating == FALSE) {
/* never allocate children on their own */
crm_debug("Escalating allocation of %s to its parent: %s",
rsc->id, rsc->parent->id);
rsc->parent->cmds->color(rsc->parent, data_set);
}
print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE);
if(rsc->provisional == FALSE) {
return rsc->allocated_to;
}
if(rsc->is_allocating) {
crm_debug("Dependancy loop detected involving %s", rsc->id);
return NULL;
}
rsc->is_allocating = TRUE;
rsc->rsc_cons = g_list_sort(rsc->rsc_cons, sort_cons_strength);
slist_iter(
constraint, rsc_colocation_t, rsc->rsc_cons, lpc,
crm_debug_3("%s: Pre-Processing %s", rsc->id, constraint->id);
if(rsc->provisional && constraint->rsc_rh->provisional) {
crm_info("Combine scores from %s and %s",
rsc->id, constraint->rsc_rh->id);
node_list_update(constraint->rsc_rh->allowed_nodes,
rsc->allowed_nodes,
constraint->score/INFINITY);
}
constraint->rsc_rh->cmds->color(
constraint->rsc_rh, data_set);
rsc->cmds->rsc_colocation_lh(
rsc, constraint->rsc_rh, constraint);
);
print_resource(LOG_DEBUG, "Allocating: ", rsc, FALSE);
if(rsc->next_role == RSC_ROLE_STOPPED) {
crm_debug_2("Making sure %s doesn't get allocated", rsc->id);
/* make sure it doesnt come up again */
resource_location(
rsc, NULL, -INFINITY, "target_role", data_set);
}
if(rsc->provisional && native_choose_node(rsc) ) {
crm_debug_3("Allocated resource %s to %s",
rsc->id, rsc->allocated_to->details->uname);
} else if(rsc->allocated_to == NULL) {
if(rsc->orphan == FALSE) {
pe_warn("Resource %s cannot run anywhere", rsc->id);
} else {
crm_info("Stopping orphan resource %s", rsc->id);
}
} else {
crm_debug("Pre-Allocated resource %s to %s",
rsc->id, rsc->allocated_to->details->uname);
}
rsc->is_allocating = FALSE;
print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE);
return rsc->allocated_to;
}
void
Recurring(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set)
{
char *key = NULL;
const char *name = NULL;
const char *value = NULL;
const char *interval = NULL;
const char *node_uname = NULL;
int interval_ms = 0;
action_t *mon = NULL;
gboolean is_optional = TRUE;
GListPtr possible_matches = NULL;
crm_debug_2("Creating recurring actions for %s", rsc->id);
if(node != NULL) {
node_uname = node->details->uname;
}
xml_child_iter_filter(
rsc->ops_xml, operation, "op",
is_optional = TRUE;
name = crm_element_value(operation, "name");
interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
interval_ms = crm_get_msec(interval);
if(interval_ms <= 0) {
continue;
}
value = crm_element_value(operation, "disabled");
if(crm_is_true(value)) {
continue;
}
key = generate_op_key(rsc->id, name, interval_ms);
if(start != NULL) {
crm_debug_3("Marking %s %s due to %s",
key, start->optional?"optional":"manditory",
start->uuid);
is_optional = start->optional;
} else {
crm_debug_2("Marking %s optional", key);
is_optional = TRUE;
}
/* start a monitor for an already active resource */
possible_matches = find_actions_exact(rsc->actions, key, node);
if(possible_matches == NULL) {
is_optional = FALSE;
crm_debug_3("Marking %s manditory: not active", key);
}
value = crm_element_value(operation, "role");
if((rsc->next_role == RSC_ROLE_MASTER && value == NULL)
|| (value != NULL && text2role(value) != rsc->next_role)) {
int log_level = LOG_DEBUG_2;
const char *foo = "Ignoring";
if(is_optional) {
char *local_key = crm_strdup(key);
log_level = LOG_INFO;
foo = "Cancelling";
/* its running : cancel it */
mon = custom_action(
rsc, local_key, CRMD_ACTION_CANCEL, node,
FALSE, TRUE, data_set);
mon->task = CRMD_ACTION_CANCEL;
add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval);
add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name);
custom_action_order(
rsc, NULL, mon,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
mon = NULL;
}
do_crm_log(log_level, "%s action %s (%s vs. %s)",
foo , key, value?value:role2text(RSC_ROLE_SLAVE),
role2text(rsc->next_role));
crm_free(key);
key = NULL;
continue;
}
mon = custom_action(rsc, key, name, node,
is_optional, TRUE, data_set);
if(is_optional) {
crm_debug("%s\t %s (optional)",
crm_str(node_uname), mon->uuid);
}
if(start == NULL || start->runnable == FALSE) {
crm_debug("%s\t %s (cancelled : start un-runnable)",
crm_str(node_uname), mon->uuid);
mon->runnable = FALSE;
} else if(node == NULL
|| node->details->online == FALSE
|| node->details->unclean) {
crm_debug("%s\t %s (cancelled : no node available)",
crm_str(node_uname), mon->uuid);
mon->runnable = FALSE;
} else if(mon->optional == FALSE) {
crm_notice("%s\t %s", crm_str(node_uname),mon->uuid);
}
custom_action_order(rsc, start_key(rsc), NULL,
NULL, crm_strdup(key), mon,
pe_order_internal_restart, data_set);
if(rsc->next_role == RSC_ROLE_MASTER) {
char *running_master = crm_itoa(EXECRA_RUNNING_MASTER);
add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master);
custom_action_order(
rsc, promote_key(rsc), NULL,
rsc, NULL, mon,
pe_order_optional, data_set);
crm_free(running_master);
}
);
}
void native_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
action_t *start = NULL;
node_t *chosen = NULL;
enum rsc_role_e role = RSC_ROLE_UNKNOWN;
enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
crm_debug_2("Creating actions for %s", rsc->id);
chosen = rsc->allocated_to;
if(chosen != NULL) {
CRM_CHECK(rsc->next_role != RSC_ROLE_UNKNOWN, rsc->next_role = RSC_ROLE_STARTED);
}
unpack_instance_attributes(
rsc->xml, XML_TAG_ATTR_SETS,
chosen?chosen->details->attrs:NULL,
rsc->parameters, NULL, data_set->now);
crm_debug_2("%s: %s->%s", rsc->id,
role2text(rsc->role), role2text(rsc->next_role));
if(g_list_length(rsc->running_on) > 1) {
if(rsc->recovery_type == recovery_stop_start) {
pe_proc_err("Attempting recovery of resource %s", rsc->id);
StopRsc(rsc, NULL, data_set);
rsc->role = RSC_ROLE_STOPPED;
}
} else if(rsc->running_on != NULL) {
node_t *current = rsc->running_on->data;
NoRoleChange(rsc, current, chosen, data_set);
} else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) {
char *key = start_key(rsc);
GListPtr possible_matches = find_actions(rsc->actions, key, NULL);
slist_iter(
action, action_t, possible_matches, lpc,
action->optional = TRUE;
/* action->pseudo = TRUE; */
);
crm_debug_2("Stopping a stopped resource");
crm_free(key);
return;
}
role = rsc->role;
while(role != rsc->next_role) {
next_role = rsc_state_matrix[role][rsc->next_role];
crm_debug_2("Executing: %s->%s (%s)",
role2text(role), role2text(next_role), rsc->id);
if(rsc_action_matrix[role][next_role](
rsc, chosen, data_set) == FALSE) {
break;
}
role = next_role;
}
if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) {
start = start_action(rsc, chosen, TRUE);
Recurring(rsc, start, chosen, data_set);
}
}
void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
order_restart(rsc);
custom_action_order(rsc, demote_key(rsc), NULL,
rsc, stop_key(rsc), NULL,
pe_order_implies_left, data_set);
custom_action_order(rsc, start_key(rsc), NULL,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
custom_action_order(
rsc, stop_key(rsc), NULL, rsc, delete_key(rsc), NULL,
pe_order_optional, data_set);
custom_action_order(
rsc, delete_key(rsc), NULL, rsc, start_key(rsc), NULL,
pe_order_implies_left, data_set);
if(rsc->notify) {
char *key1 = NULL;
char *key2 = NULL;
key1 = generate_op_key(rsc->id, "confirmed-post_notify_start", 0);
key2 = generate_op_key(rsc->id, "pre_notify_promote", 0);
custom_action_order(
rsc, key1, NULL, rsc, key2, NULL,
pe_order_optional, data_set);
key1 = generate_op_key(rsc->id, "confirmed-post_notify_demote", 0);
key2 = generate_op_key(rsc->id, "pre_notify_stop", 0);
custom_action_order(
rsc, key1, NULL, rsc, key2, NULL,
pe_order_optional, data_set);
}
}
void native_rsc_colocation_lh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
if(rsc_lh == NULL) {
pe_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if(constraint->rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
}
crm_debug_2("Processing colocation constraint between %s and %s",
rsc_lh->id, rsc_rh->id);
rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint);
}
static gboolean
filter_colocation_constraint(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
if(constraint->score == 0){
return FALSE;
}
if(constraint->role_lh != RSC_ROLE_UNKNOWN
&& constraint->role_lh != rsc_lh->next_role) {
crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
role2text(constraint->role_rh));
return FALSE;
}
if(constraint->role_rh != RSC_ROLE_UNKNOWN
&& constraint->role_rh != rsc_rh->next_role) {
crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
role2text(constraint->role_rh));
return FALSE;
}
return TRUE;
}
static void
colocation_match(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
const char *tmp = NULL;
const char *value = NULL;
gboolean do_check = FALSE;
const char *attribute = "#id";
if(constraint->node_attribute != NULL) {
attribute = constraint->node_attribute;
}
if(rsc_rh->allocated_to) {
value = g_hash_table_lookup(
rsc_rh->allocated_to->details->attrs, attribute);
do_check = TRUE;
}
slist_iter(
node, node_t, rsc_lh->allowed_nodes, lpc,
tmp = g_hash_table_lookup(node->details->attrs, attribute);
if(do_check && safe_str_eq(tmp, value)) {
crm_debug_2("%s: %s.%s += %d", constraint->id, rsc_lh->id,
node->details->uname, constraint->score);
node->weight = merge_weights(
constraint->score, node->weight);
} else if(do_check == FALSE || constraint->score >= INFINITY) {
crm_debug_2("%s: %s.%s = -INFINITY (%s)", constraint->id, rsc_lh->id,
node->details->uname, do_check?"failed":"unallocated");
node->weight = -INFINITY;
}
);
}
void native_rsc_colocation_rh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
crm_debug_2("%sColocating %s with %s (%s, weight=%d)",
constraint->score >= 0?"":"Anti-",
rsc_lh->id, rsc_rh->id, constraint->id, constraint->score);
if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) {
return;
}
if(rsc_rh->provisional) {
return;
} else if(rsc_lh->provisional == FALSE) {
/* error check */
struct node_shared_s *details_lh;
struct node_shared_s *details_rh;
if((constraint->score > -INFINITY) && (constraint->score < INFINITY)) {
return;
}
details_rh = rsc_rh->allocated_to?rsc_rh->allocated_to->details:NULL;
details_lh = rsc_lh->allocated_to?rsc_lh->allocated_to->details:NULL;
if(constraint->score == INFINITY && details_lh != details_rh) {
crm_err("%s and %s are both allocated"
" but to different nodes: %s vs. %s",
rsc_lh->id, rsc_rh->id,
details_lh?details_lh->uname:"n/a",
details_rh?details_rh->uname:"n/a");
} else if(constraint->score == -INFINITY && details_lh == details_rh) {
crm_err("%s and %s are both allocated"
" but to the SAME node: %s",
rsc_lh->id, rsc_rh->id,
details_rh?details_rh->uname:"n/a");
}
return;
} else {
colocation_match(rsc_lh, rsc_rh, constraint);
}
}
void
node_list_update(GListPtr list1, GListPtr list2, int factor)
{
node_t *other_node = NULL;
slist_iter(
node, node_t, list1, lpc,
if(node == NULL) {
continue;
}
other_node = (node_t*)pe_find_node_id(
list2, node->details->id);
if(other_node != NULL) {
crm_debug_2("%s: %d + %d",
node->details->uname,
node->weight, other_node->weight);
node->weight = merge_weights(
factor*other_node->weight, node->weight);
}
);
}
void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order)
{
GListPtr lh_actions = NULL;
action_t *lh_action = order->lh_action;
crm_debug_3("Processing LH of ordering constraint %d", order->id);
if(lh_action != NULL) {
lh_actions = g_list_append(NULL, lh_action);
} else if(lh_action == NULL && lh_rsc != NULL) {
lh_actions = find_actions(
lh_rsc->actions, order->lh_action_task, NULL);
if(lh_actions == NULL) {
crm_debug_4("No LH-Side (%s/%s) found for constraint",
lh_rsc->id, order->lh_action_task);
if(lh_rsc->next_role == RSC_ROLE_STOPPED) {
resource_t *rh_rsc = order->rh_rsc;
if(order->rh_action
&& (order->type & pe_order_internal_restart)) {
crm_debug_3("No LH(%s/%s) found for RH(%s)...",
lh_rsc->id, order->lh_action_task,
order->rh_action->uuid);
order->rh_action->runnable = FALSE;
return;
} else if(rh_rsc != NULL) {
crm_debug_3("No LH(%s/%s) found for RH(%s/%s)...",
lh_rsc->id, order->lh_action_task,
rh_rsc->id, order->rh_action_task);
rh_rsc->cmds->rsc_order_rh(NULL, rh_rsc, order);
return;
}
}
return;
}
} else {
pe_warn("No LH-Side (%s) specified for constraint",
order->lh_action_task);
if(order->rh_rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL
&& order->rh_action->rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_action->rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL) {
crm_debug_4("RH-Side was: %s",
order->rh_action_task);
} else {
crm_debug_4("RH-Side was NULL");
}
return;
}
slist_iter(
lh_action_iter, action_t, lh_actions, lpc,
resource_t *rh_rsc = order->rh_rsc;
if(rh_rsc == NULL && order->rh_action) {
rh_rsc = order->rh_action->rsc;
}
if(rh_rsc) {
rh_rsc->cmds->rsc_order_rh(
lh_action_iter, rh_rsc, order);
} else if(order->rh_action) {
order_actions(lh_action_iter, order->rh_action, order->type);
}
);
pe_free_shallow_adv(lh_actions, FALSE);
}
void native_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order)
{
GListPtr rh_actions = NULL;
action_t *rh_action = NULL;
CRM_CHECK(rsc != NULL, return);
CRM_CHECK(order != NULL, return);
- CRM_CHECK(lh_action != NULL, return);
rh_action = order->rh_action;
crm_debug_3("Processing RH of ordering constraint %d", order->id);
if(rh_action != NULL) {
rh_actions = g_list_append(NULL, rh_action);
- } else if(rh_action == NULL && rsc != NULL) {
+ } else if(rsc != NULL) {
rh_actions = find_actions(
rsc->actions, order->rh_action_task, NULL);
-
- if(rh_actions == NULL) {
- crm_debug_4("No RH-Side (%s/%s) found for constraint..."
- " ignoring", rsc->id, order->rh_action_task);
+ }
+
+ if(rh_actions == NULL && lh_action != NULL) {
+ crm_debug_4("No RH-Side (%s/%s) found for constraint..."
+ " ignoring", rsc->id,order->rh_action_task);
+ if(lh_action) {
crm_debug_4("LH-Side was: %s", lh_action->uuid);
- return;
}
-
- } else if(rh_action == NULL) {
- crm_debug_4("No RH-Side (%s) specified for constraint..."
- " ignoring", order->rh_action_task);
- crm_debug_4("LH-Side was: %s", lh_action->uuid);
return;
- }
-
+ }
+
slist_iter(
rh_action_iter, action_t, rh_actions, lpc,
if(lh_action) {
- order_actions(lh_action, rh_action_iter, order->type);
+ order_actions(lh_action, rh_action_iter, order->type);
} else if(order->type & pe_order_internal_restart) {
rh_action_iter->runnable = FALSE;
}
);
pe_free_shallow_adv(rh_actions, FALSE);
}
void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
{
GListPtr or_list;
crm_debug_2("Applying %s (%s) to %s", constraint->id,
role2text(constraint->role_filter), rsc->id);
/* take "lifetime" into account */
if(constraint == NULL) {
pe_err("Constraint is NULL");
return;
} else if(rsc == NULL) {
pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id);
return;
} else if(constraint->role_filter > 0
&& constraint->role_filter != rsc->next_role) {
crm_debug("Constraint (%s) is not active (role : %s)",
constraint->id, role2text(constraint->role_filter));
return;
} else if(is_active(constraint) == FALSE) {
crm_debug_2("Constraint (%s) is not active", constraint->id);
return;
}
if(constraint->node_list_rh == NULL) {
crm_debug_2("RHS of constraint %s is NULL", constraint->id);
return;
}
or_list = node_list_or(
rsc->allowed_nodes, constraint->node_list_rh, FALSE);
pe_free_shallow(rsc->allowed_nodes);
rsc->allowed_nodes = or_list;
slist_iter(node, node_t, or_list, lpc,
crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight);
);
}
void native_expand(resource_t *rsc, pe_working_set_t *data_set)
{
slist_iter(
action, action_t, rsc->actions, lpc,
crm_debug_4("processing action %d for rsc=%s",
action->id, rsc->id);
graph_element_from_action(action, data_set);
);
}
void
native_agent_constraints(resource_t *rsc)
{
}
void
create_notifications(resource_t *rsc, pe_working_set_t *data_set)
{
if(rsc->notify == FALSE) {
return;
}
/* slist_iter( */
/* action, action_t, rsc->actions, lpc, */
/* ); */
}
static void
register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data)
{
notify_entry_t *entry = NULL;
crm_malloc0(entry, sizeof(notify_entry_t));
entry->rsc = rsc;
entry->node = node;
switch(task) {
case start_rsc:
n_data->start = g_list_append(n_data->start, entry);
break;
case stop_rsc:
n_data->stop = g_list_append(n_data->stop, entry);
break;
case action_promote:
n_data->promote = g_list_append(n_data->promote, entry);
break;
case action_demote:
n_data->demote = g_list_append(n_data->demote, entry);
break;
default:
crm_err("Unsupported notify action: %s", task2text(task));
crm_free(entry);
break;
}
}
static void
register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data)
{
notify_entry_t *entry = NULL;
crm_malloc0(entry, sizeof(notify_entry_t));
entry->rsc = rsc;
entry->node = on_node;
crm_debug_2("%s state: %s", rsc->id, role2text(rsc->next_role));
switch(rsc->next_role) {
case RSC_ROLE_STOPPED:
/* n_data->inactive = g_list_append(n_data->inactive, entry); */
crm_free(entry);
break;
case RSC_ROLE_STARTED:
n_data->active = g_list_append(n_data->active, entry);
break;
case RSC_ROLE_SLAVE:
n_data->slave = g_list_append(n_data->slave, entry);
break;
case RSC_ROLE_MASTER:
n_data->master = g_list_append(n_data->master, entry);
break;
default:
crm_err("Unsupported notify role");
crm_free(entry);
break;
}
}
void
native_create_notify_element(resource_t *rsc, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
node_t *next_node = NULL;
gboolean registered = FALSE;
char *op_key = NULL;
GListPtr possible_matches = NULL;
enum action_tasks task = text2task(op->task);
if(op->pre_notify == NULL || op->post_notify == NULL) {
/* no notifications required */
crm_debug_4("No notificaitons required for %s", op->task);
return;
}
next_node = rsc->allocated_to;
op_key = generate_op_key(rsc->id, op->task, 0);
possible_matches = find_actions(rsc->actions, op_key, NULL);
crm_debug_2("Creating notificaitons for: %s (%s->%s)",
op->uuid, role2text(rsc->role), role2text(rsc->next_role));
if(rsc->role == rsc->next_role) {
register_state(rsc, next_node, n_data);
}
slist_iter(
local_op, action_t, possible_matches, lpc,
local_op->notify_keys = n_data->keys;
if(local_op->optional == FALSE) {
registered = TRUE;
register_activity(rsc, task, local_op->node, n_data);
}
);
/* stop / demote */
if(rsc->role != RSC_ROLE_STOPPED) {
if(task == stop_rsc || task == action_demote) {
slist_iter(
current_node, node_t, rsc->running_on, lpc,
pe_pre_notify(rsc, current_node, op, n_data, data_set);
if(task == action_demote || registered == FALSE) {
pe_post_notify(rsc, current_node, op, n_data, data_set);
}
);
}
}
/* start / promote */
if(rsc->next_role != RSC_ROLE_STOPPED) {
CRM_CHECK(next_node != NULL,;);
if(next_node == NULL) {
pe_proc_err("next role: %s", role2text(rsc->next_role));
} else if(task == start_rsc || task == action_promote) {
if(task != start_rsc || registered == FALSE) {
pe_pre_notify(rsc, next_node, op, n_data, data_set);
}
pe_post_notify(rsc, next_node, op, n_data, data_set);
}
}
crm_free(op_key);
pe_free_shallow_adv(possible_matches, FALSE);
}
static void dup_attr(gpointer key, gpointer value, gpointer user_data)
{
char *meta_key = crm_concat(CRM_META, key, '_');
g_hash_table_replace(user_data, meta_key, crm_strdup(value));
}
static action_t *
pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm,
notify_data_t *n_data, pe_working_set_t *data_set)
{
char *key = NULL;
action_t *trigger = NULL;
const char *value = NULL;
const char *task = NULL;
if(op == NULL || confirm == NULL) {
crm_debug_2("Op=%p confirm=%p", op, confirm);
return NULL;
}
CRM_CHECK(node != NULL, return NULL);
if(node->details->online == FALSE) {
crm_info("Skipping notification for %s", rsc->id);
return NULL;
}
value = g_hash_table_lookup(op->meta, "notify_type");
task = g_hash_table_lookup(op->meta, "notify_operation");
crm_debug_2("Creating actions for %s: %s (%s-%s)",
op->uuid, rsc->id, value, task);
key = generate_notify_key(rsc->id, value, task);
trigger = custom_action(rsc, key, op->task, node,
op->optional, TRUE, data_set);
g_hash_table_foreach(op->meta, dup_attr, trigger->extra);
trigger->notify_keys = n_data->keys;
/* pseudo_notify before notify */
crm_debug_3("Ordering %s before %s (%d->%d)",
op->uuid, trigger->uuid, trigger->id, op->id);
order_actions(op, trigger, pe_order_implies_left);
value = g_hash_table_lookup(op->meta, "notify_confirm");
if(crm_is_true(value)) {
/* notify before pseudo_notified */
crm_debug_3("Ordering %s before %s (%d->%d)",
trigger->uuid, confirm->uuid,
confirm->id, trigger->id);
order_actions(trigger, confirm, pe_order_implies_left);
}
return trigger;
}
void
pe_pre_notify(resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
crm_debug_2("%s: %s", rsc->id, op->uuid);
pe_notify(rsc, node, op->pre_notify, op->pre_notified,
n_data, data_set);
}
void
pe_post_notify(resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
action_t *notify = NULL;
CRM_CHECK(op != NULL, return);
CRM_CHECK(rsc != NULL, return);
crm_debug_2("%s: %s", rsc->id, op->uuid);
notify = pe_notify(rsc, node, op->post_notify, op->post_notified,
n_data, data_set);
if(notify != NULL) {
/* crm_err("Upgrading priority for %s to INFINITY", notify->uuid); */
notify->priority = INFINITY;
}
notify = op->post_notified;
if(notify != NULL) {
slist_iter(
mon, action_t, rsc->actions, lpc,
const char *interval = g_hash_table_lookup(mon->meta, "interval");
if(interval == NULL || safe_str_eq(interval, "0")) {
crm_debug_3("Skipping %s: interval", mon->uuid);
continue;
} else if(safe_str_eq(mon->task, "cancel")) {
crm_debug_3("Skipping %s: cancel", mon->uuid);
continue;
}
order_actions(notify, mon, pe_order_optional);
);
}
}
void
NoRoleChange(resource_t *rsc, node_t *current, node_t *next,
pe_working_set_t *data_set)
{
action_t *start = NULL;
action_t *stop = NULL;
GListPtr possible_matches = NULL;
crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role));
if(current == NULL || next == NULL) {
return;
}
/* use StartRsc/StopRsc */
if(safe_str_neq(current->details->id, next->details->id)) {
crm_notice("Move resource %s\t(%s -> %s)", rsc->id,
current->details->uname, next->details->uname);
stop = stop_action(rsc, current, FALSE);
start = start_action(rsc, next, FALSE);
possible_matches = find_recurring_actions(rsc->actions, next);
slist_iter(match, action_t, possible_matches, lpc,
if(match->optional == FALSE) {
crm_err("Found bad recurring action: %s",
match->uuid);
match->optional = TRUE;
}
);
if(data_set->remove_after_stop) {
DeleteRsc(rsc, current, data_set);
}
} else {
if(rsc->failed) {
crm_notice("Recover resource %s\t(%s)",
rsc->id, next->details->uname);
stop = stop_action(rsc, current, FALSE);
start = start_action(rsc, next, FALSE);
/* /\* make the restart required *\/ */
/* order_stop_start(rsc, rsc, pe_order_implies_left); */
} else if(rsc->start_pending) {
start = start_action(rsc, next, TRUE);
if(start->runnable) {
/* wait for StartRsc() to be called */
rsc->role = RSC_ROLE_STOPPED;
} else {
/* wait for StopRsc() to be called */
rsc->next_role = RSC_ROLE_STOPPED;
}
} else {
stop = stop_action(rsc, current, TRUE);
start = start_action(rsc, next, TRUE);
stop->optional = start->optional;
if(start->runnable == FALSE) {
rsc->next_role = RSC_ROLE_STOPPED;
} else if(start->optional) {
crm_notice("Leave resource %s\t(%s)",
rsc->id, next->details->uname);
} else {
crm_notice("Restart resource %s\t(%s)",
rsc->id, next->details->uname);
}
}
}
}
gboolean
StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
action_t *stop = NULL;
crm_debug_2("Executing: %s", rsc->id);
slist_iter(
current, node_t, rsc->running_on, lpc,
crm_notice(" %s\tStop %s", current->details->uname, rsc->id);
stop = stop_action(rsc, current, FALSE);
if(data_set->remove_after_stop) {
DeleteRsc(rsc, current, data_set);
}
);
return TRUE;
}
gboolean
StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
action_t *start = NULL;
crm_debug_2("Executing: %s", rsc->id);
start = start_action(rsc, next, TRUE);
if(start->runnable) {
crm_notice(" %s\tStart %s", next->details->uname, rsc->id);
start->optional = FALSE;
}
return TRUE;
}
gboolean
PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
char *key = NULL;
gboolean runnable = TRUE;
GListPtr action_list = NULL;
crm_debug_2("Executing: %s", rsc->id);
CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE);
key = start_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
crm_free(key);
slist_iter(start, action_t, action_list, lpc,
if(start->runnable == FALSE) {
runnable = FALSE;
}
);
if(runnable) {
promote_action(rsc, next, FALSE);
crm_notice("%s\tPromote %s", next->details->uname, rsc->id);
return TRUE;
}
crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id);
key = promote_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
crm_free(key);
slist_iter(promote, action_t, action_list, lpc,
promote->runnable = FALSE;
);
return TRUE;
}
gboolean
DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug_2("Executing: %s", rsc->id);
/* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */
slist_iter(
current, node_t, rsc->running_on, lpc,
crm_notice("%s\tDeomote %s", current->details->uname, rsc->id);
demote_action(rsc, current, FALSE);
);
return TRUE;
}
gboolean
RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug("Executing: %s", rsc->id);
CRM_CHECK(FALSE, return FALSE);
return FALSE;
}
gboolean
NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug("Executing: %s", rsc->id);
return FALSE;
}
gboolean
DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set)
{
action_t *delete = NULL;
action_t *refresh = NULL;
if(rsc->failed) {
crm_debug_2("Resource %s not deleted from %s: failed",
rsc->id, node->details->uname);
return FALSE;
} else if(node == NULL) {
crm_debug_2("Resource %s not deleted: NULL node", rsc->id);
return FALSE;
} else if(node->details->unclean || node->details->online == FALSE) {
crm_debug_2("Resource %s not deleted from %s: unrunnable",
rsc->id, node->details->uname);
return FALSE;
}
crm_notice("Removing %s from %s",
rsc->id, node->details->uname);
delete = delete_action(rsc, node);
#if DELETE_THEN_REFRESH
refresh = custom_action(
NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH,
node, FALSE, TRUE, data_set);
add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
order_actions(delete, refresh, pe_order_optional);
#endif
return TRUE;
}
gboolean
native_create_probe(resource_t *rsc, node_t *node, action_t *complete,
gboolean force, pe_working_set_t *data_set)
{
char *key = NULL;
char *target_rc = NULL;
action_t *probe = NULL;
node_t *running = NULL;
CRM_CHECK(node != NULL, return FALSE);
if(rsc->orphan) {
crm_debug_2("Skipping orphan: %s", rsc->id);
return FALSE;
}
running = pe_find_node_id(rsc->known_on, node->details->id);
if(force == FALSE && running != NULL) {
/* we already know the status of the resource on this node */
crm_debug_3("Skipping active: %s", rsc->id);
return FALSE;
}
key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0);
probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node,
FALSE, TRUE, data_set);
probe->priority = INFINITY;
running = pe_find_node_id(rsc->running_on, node->details->id);
if(running == NULL) {
target_rc = crm_itoa(EXECRA_NOT_RUNNING);
add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc);
crm_free(target_rc);
}
crm_debug_2("%s: Created probe for %s", node->details->uname, rsc->id);
custom_action_order(rsc, NULL, probe, rsc, NULL, complete,
pe_order_implies_left, data_set);
return TRUE;
}
static void
native_start_constraints(
resource_t *rsc, action_t *stonith_op, gboolean is_stonith,
pe_working_set_t *data_set)
{
gboolean is_unprotected = FALSE;
gboolean run_unprotected = TRUE;
if(is_stonith) {
char *key = start_key(rsc);
crm_debug_2("Ordering %s action before stonith events", key);
custom_action_order(
rsc, key, NULL,
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
pe_order_optional, data_set);
} else {
slist_iter(action, action_t, rsc->actions, lpc2,
if(action->needs != rsc_req_stonith) {
crm_debug_3("%s doesnt need to wait for stonith events", action->uuid);
continue;
}
crm_debug_2("Ordering %s after stonith events", action->uuid);
if(stonith_op != NULL) {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
rsc, NULL, action,
pe_order_implies_left, data_set);
} else if(run_unprotected == FALSE) {
/* mark the start unrunnable */
action->runnable = FALSE;
} else {
is_unprotected = TRUE;
}
);
}
if(is_unprotected) {
pe_err("SHARED RESOURCE %s IS NOT PROTECTED:"
" Stonith disabled", rsc->id);
}
}
static void
native_stop_constraints(
resource_t *rsc, action_t *stonith_op, gboolean is_stonith,
pe_working_set_t *data_set)
{
char *key = NULL;
GListPtr action_list = NULL;
node_t *node = stonith_op->node;
key = stop_key(rsc);
action_list = find_actions(rsc->actions, key, node);
crm_free(key);
/* add the stonith OP as a stop pre-req and the mark the stop
* as a pseudo op - since its now redundant
*/
slist_iter(
action, action_t, action_list, lpc2,
if(node->details->online == FALSE || rsc->failed) {
resource_t *parent = NULL;
crm_warn("Stop of failed resource %s is"
" implicit after %s is fenced",
action->uuid, node->details->uname);
/* the stop would never complete and is
* now implied by the stonith operation
*/
action->pseudo = TRUE;
action->runnable = TRUE;
if(is_stonith) {
/* do nothing */
} else {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE),stonith_op,
rsc, start_key(rsc), NULL,
pe_order_implies_left, data_set);
}
/* find the top-most resource */
parent = rsc->parent;
while(parent != NULL && parent->parent != NULL) {
parent = parent->parent;
}
if(parent) {
crm_info("Re-creating actions for %s",
parent->id);
parent->cmds->create_actions(parent, data_set);
/* make sure we dont mess anything up in create_actions */
CRM_CHECK(action->pseudo, action->pseudo = TRUE);
CRM_CHECK(action->runnable, action->runnable = TRUE);
}
} else if(is_stonith == FALSE) {
crm_info("Moving healthy resource %s"
" off %s before fencing",
rsc->id, node->details->uname);
/* stop healthy resources before the
* stonith op
*/
custom_action_order(
rsc, stop_key(rsc), NULL,
NULL,crm_strdup(CRM_OP_FENCE),stonith_op,
pe_order_implies_left, data_set);
}
);
key = demote_key(rsc);
action_list = find_actions(rsc->actions, key, node);
crm_free(key);
slist_iter(
action, action_t, action_list, lpc2,
if(node->details->online == FALSE || rsc->failed) {
crm_info("Demote of failed resource %s is"
" implict after %s is fenced",
rsc->id, node->details->uname);
/* the stop would never complete and is
* now implied by the stonith operation
*/
action->pseudo = TRUE;
action->runnable = TRUE;
if(is_stonith == FALSE) {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
rsc, demote_key(rsc), NULL,
pe_order_implies_left, data_set);
}
}
);
}
void
native_stonith_ordering(
resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set)
{
gboolean is_stonith = FALSE;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
if(rsc->is_managed == FALSE) {
crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id);
return;
}
if(stonith_op != NULL && safe_str_eq(class, "stonith")) {
is_stonith = TRUE;
}
/* Start constraints */
native_start_constraints(rsc, stonith_op, is_stonith, data_set);
/* Stop constraints */
native_stop_constraints(rsc, stonith_op, is_stonith, data_set);
}
void
native_migrate_reload(resource_t *rsc, pe_working_set_t *data_set)
{
char *key = NULL;
GListPtr action_list = NULL;
const char *value = NULL;
action_t *stop = NULL;
action_t *start = NULL;
action_t *other = NULL;
action_t *action = NULL;
if(rsc->variant != pe_native) {
return;
}
if(rsc->is_managed == FALSE
|| rsc->failed
|| rsc->start_pending
|| rsc->next_role != RSC_ROLE_STARTED
|| g_list_length(rsc->running_on) != 1) {
crm_debug_3("%s: resource", rsc->id);
return;
}
key = start_key(rsc);
action_list = find_actions(rsc->actions, key, NULL);
crm_free(key);
if(action_list == NULL) {
crm_debug_3("%s: no start action", rsc->id);
return;
}
start = action_list->data;
value = g_hash_table_lookup(rsc->meta, "allow_migrate");
if(crm_is_true(value)) {
rsc->can_migrate = TRUE;
}
if(rsc->can_migrate == FALSE
&& start->allow_reload_conversion == FALSE) {
crm_debug_3("%s: no need to continue", rsc->id);
return;
}
key = stop_key(rsc);
action_list = find_actions(rsc->actions, key, NULL);
crm_free(key);
if(action_list == NULL) {
crm_debug_3("%s: no stop action", rsc->id);
return;
}
stop = action_list->data;
action = start;
if(action->pseudo
|| action->optional
|| action->node == NULL
|| action->runnable == FALSE) {
crm_debug_3("Skipping: %s", action->task);
return;
}
action = stop;
if(action->pseudo
|| action->optional
|| action->node == NULL
|| action->runnable == FALSE) {
crm_debug_3("Skipping: %s", action->task);
return;
}
slist_iter(
other_w, action_wrapper_t, start->actions_before, lpc,
other = other_w->action;
if(other->optional == FALSE
&& other->rsc != NULL
&& other->rsc != start->rsc) {
crm_debug_2("Skipping: start depends");
return;
}
);
slist_iter(
other_w, action_wrapper_t, stop->actions_after, lpc,
other = other_w->action;
if(other->optional == FALSE
&& other->rsc != NULL
&& other->rsc != stop->rsc) {
crm_debug_2("Skipping: stop depends");
return;
}
);
if(rsc->can_migrate && stop->node->details != start->node->details) {
crm_info("Migrating %s from %s to %s", rsc->id,
stop->node->details->uname,
start->node->details->uname);
crm_free(stop->uuid);
stop->task = CRMD_ACTION_MIGRATE;
stop->uuid = generate_op_key(rsc->id, stop->task, 0);
add_hash_param(stop->meta, "migrate_source",
stop->node->details->uname);
add_hash_param(stop->meta, "migrate_target",
start->node->details->uname);
crm_free(start->uuid);
start->task = CRMD_ACTION_MIGRATED;
start->uuid = generate_op_key(rsc->id, start->task, 0);
add_hash_param(start->meta, "migrate_source_uuid",
stop->node->details->id);
add_hash_param(start->meta, "migrate_source",
stop->node->details->uname);
add_hash_param(start->meta, "migrate_target",
start->node->details->uname);
} else if(start->allow_reload_conversion
&& stop->node->details == start->node->details) {
crm_info("Rewriting restart of %s on %s as a reload",
rsc->id, start->node->details->uname);
crm_free(start->uuid);
start->task = "reload";
start->uuid = generate_op_key(rsc->id, start->task, 0);
stop->pseudo = TRUE; /* easier than trying to delete it from the graph */
} else {
crm_debug_3("%s nothing to do", rsc->id);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 3:12 AM (23 m, 48 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018087
Default Alt Text
(44 KB)

Event Timeline