|
|
7ebc05 |
commit 1928af7d8d2fc7d225df22caeb7ea93964f48bde
|
|
|
7ebc05 |
Author: David Vossel <dvossel@redhat.com>
|
|
|
7ebc05 |
Date: Wed Apr 16 10:28:46 2014 -0500
|
|
|
7ebc05 |
|
|
|
7ebc05 |
High: fencing: Fence using all required devices
|
|
|
7ebc05 |
|
|
|
7ebc05 |
(cherry picked from commit 1f39dfe13d8cbfb5dd22f8324735319f81230fdb)
|
|
|
7ebc05 |
|
|
|
7ebc05 |
Conflicts:
|
|
|
7ebc05 |
fencing/main.c
|
|
|
7ebc05 |
|
|
|
7ebc05 |
diff --git a/fencing/commands.c b/fencing/commands.c
|
|
|
7ebc05 |
index 41690f7..8efb156 100644
|
|
|
7ebc05 |
--- a/fencing/commands.c
|
|
|
7ebc05 |
+++ b/fencing/commands.c
|
|
|
7ebc05 |
@@ -111,6 +111,20 @@ typedef struct async_command_s {
|
|
|
7ebc05 |
static xmlNode *stonith_construct_async_reply(async_command_t * cmd, const char *output,
|
|
|
7ebc05 |
xmlNode * data, int rc);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
+static gboolean
|
|
|
7ebc05 |
+is_action_required(const char *action, stonith_device_t *device)
|
|
|
7ebc05 |
+{
|
|
|
7ebc05 |
+ if (device->required_actions == NULL) {
|
|
|
7ebc05 |
+ return FALSE;
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ if (strstr(device->required_actions, action)) {
|
|
|
7ebc05 |
+ return TRUE;
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ return FALSE;
|
|
|
7ebc05 |
+}
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
static int
|
|
|
7ebc05 |
get_action_timeout(stonith_device_t * device, const char *action, int default_timeout)
|
|
|
7ebc05 |
{
|
|
|
7ebc05 |
@@ -318,6 +332,7 @@ free_device(gpointer data)
|
|
|
7ebc05 |
free_xml(device->agent_metadata);
|
|
|
7ebc05 |
free(device->namespace);
|
|
|
7ebc05 |
free(device->on_target_actions);
|
|
|
7ebc05 |
+ free(device->required_actions);
|
|
|
7ebc05 |
free(device->agent);
|
|
|
7ebc05 |
free(device->id);
|
|
|
7ebc05 |
free(device);
|
|
|
7ebc05 |
@@ -525,10 +540,24 @@ is_nodeid_required(xmlNode * xml)
|
|
|
7ebc05 |
return TRUE;
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
+static char *
|
|
|
7ebc05 |
+add_action(char *actions, const char *action)
|
|
|
7ebc05 |
+{
|
|
|
7ebc05 |
+ static size_t len = 256;
|
|
|
7ebc05 |
+ if (actions == NULL) {
|
|
|
7ebc05 |
+ actions = calloc(1, len);
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+ if (strlen(actions)) {
|
|
|
7ebc05 |
+ g_strlcat(actions, " ", len);
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+ g_strlcat(actions, action, len);
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ return actions;
|
|
|
7ebc05 |
+}
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
static void
|
|
|
7ebc05 |
-get_on_target_actions(stonith_device_t *device)
|
|
|
7ebc05 |
+read_action_metadata(stonith_device_t *device)
|
|
|
7ebc05 |
{
|
|
|
7ebc05 |
- char *actions = NULL;
|
|
|
7ebc05 |
xmlXPathObjectPtr xpath = NULL;
|
|
|
7ebc05 |
int max = 0;
|
|
|
7ebc05 |
int lpc = 0;
|
|
|
7ebc05 |
@@ -545,40 +574,38 @@ get_on_target_actions(stonith_device_t *device)
|
|
|
7ebc05 |
return;
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- actions = calloc(1, 512);
|
|
|
7ebc05 |
-
|
|
|
7ebc05 |
for (lpc = 0; lpc < max; lpc++) {
|
|
|
7ebc05 |
const char *on_target = NULL;
|
|
|
7ebc05 |
const char *action = NULL;
|
|
|
7ebc05 |
+ const char *automatic = NULL;
|
|
|
7ebc05 |
+ const char *required = NULL;
|
|
|
7ebc05 |
xmlNode *match = getXpathResult(xpath, lpc);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
CRM_CHECK(match != NULL, continue);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
on_target = crm_element_value(match, "on_target");
|
|
|
7ebc05 |
action = crm_element_value(match, "name");
|
|
|
7ebc05 |
+ automatic = crm_element_value(match, "automatic");
|
|
|
7ebc05 |
+ required = crm_element_value(match, "required");
|
|
|
7ebc05 |
|
|
|
7ebc05 |
if(safe_str_eq(action, "list")) {
|
|
|
7ebc05 |
set_bit(device->flags, st_device_supports_list);
|
|
|
7ebc05 |
} else if(safe_str_eq(action, "status")) {
|
|
|
7ebc05 |
set_bit(device->flags, st_device_supports_status);
|
|
|
7ebc05 |
+ } else if(safe_str_eq(action, "on") && (crm_is_true(automatic))) {
|
|
|
7ebc05 |
+ /* this setting implies required=true for unfencing */
|
|
|
7ebc05 |
+ required = "true";
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
if (action && crm_is_true(on_target)) {
|
|
|
7ebc05 |
- if (strlen(actions)) {
|
|
|
7ebc05 |
- g_strlcat(actions, " ", 512);
|
|
|
7ebc05 |
- }
|
|
|
7ebc05 |
- g_strlcat(actions, action, 512);
|
|
|
7ebc05 |
+ device->on_target_actions = add_action(device->on_target_actions, action);
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+ if (action && crm_is_true(required)) {
|
|
|
7ebc05 |
+ device->required_actions = add_action(device->required_actions, action);
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
freeXpathObject(xpath);
|
|
|
7ebc05 |
-
|
|
|
7ebc05 |
- if (!strlen(actions)) {
|
|
|
7ebc05 |
- free(actions);
|
|
|
7ebc05 |
- actions = NULL;
|
|
|
7ebc05 |
- }
|
|
|
7ebc05 |
-
|
|
|
7ebc05 |
- device->on_target_actions = actions;
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
static stonith_device_t *
|
|
|
7ebc05 |
@@ -603,13 +630,23 @@ build_device_from_xml(xmlNode * msg)
|
|
|
7ebc05 |
device->aliases = build_port_aliases(value, &(device->targets));
|
|
|
7ebc05 |
|
|
|
7ebc05 |
device->agent_metadata = get_agent_metadata(device->agent);
|
|
|
7ebc05 |
- get_on_target_actions(device);
|
|
|
7ebc05 |
+ read_action_metadata(device);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
value = g_hash_table_lookup(device->params, "nodeid");
|
|
|
7ebc05 |
if (!value) {
|
|
|
7ebc05 |
device->include_nodeid = is_nodeid_required(device->agent_metadata);
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
+ value = crm_element_value(dev, "rsc_provides");
|
|
|
7ebc05 |
+ if (safe_str_eq(value, "unfencing")) {
|
|
|
7ebc05 |
+ /* if this agent requires unfencing, 'on' is considered a required action */
|
|
|
7ebc05 |
+ device->required_actions = add_action(device->required_actions, "on");
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ if (is_action_required("on", device)) {
|
|
|
7ebc05 |
+ crm_info("The fencing device '%s' requires unfencing", device->id);
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
if (device->on_target_actions) {
|
|
|
7ebc05 |
crm_info("The fencing device '%s' requires actions (%s) to be executed on the target node",
|
|
|
7ebc05 |
device->id, device->on_target_actions);
|
|
|
7ebc05 |
@@ -1460,6 +1497,7 @@ static void
|
|
|
7ebc05 |
st_child_done(GPid pid, int rc, const char *output, gpointer user_data)
|
|
|
7ebc05 |
{
|
|
|
7ebc05 |
stonith_device_t *device = NULL;
|
|
|
7ebc05 |
+ stonith_device_t *next_device = NULL;
|
|
|
7ebc05 |
async_command_t *cmd = user_data;
|
|
|
7ebc05 |
|
|
|
7ebc05 |
GListPtr gIter = NULL;
|
|
|
7ebc05 |
@@ -1483,21 +1521,37 @@ st_child_done(GPid pid, int rc, const char *output, gpointer user_data)
|
|
|
7ebc05 |
mainloop_set_trigger(device->work);
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- crm_trace("Operation %s on %s completed with rc=%d (%d remaining)",
|
|
|
7ebc05 |
+ crm_debug("Operation '%s' on '%s' completed with rc=%d (%d remaining)",
|
|
|
7ebc05 |
cmd->action, cmd->device, rc, g_list_length(cmd->device_next));
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- if (rc != 0 && cmd->device_next) {
|
|
|
7ebc05 |
- stonith_device_t *dev = g_hash_table_lookup(device_list, cmd->device_next->data);
|
|
|
7ebc05 |
-
|
|
|
7ebc05 |
- if (dev) {
|
|
|
7ebc05 |
- log_operation(cmd, rc, pid, dev->id, output);
|
|
|
7ebc05 |
+ if (rc == 0) {
|
|
|
7ebc05 |
+ GListPtr iter;
|
|
|
7ebc05 |
+ /* see if there are any required devices left to execute for this op */
|
|
|
7ebc05 |
+ for (iter = cmd->device_next; iter != NULL; iter = iter->next) {
|
|
|
7ebc05 |
+ next_device = g_hash_table_lookup(device_list, iter->data);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- cmd->device_next = cmd->device_next->next;
|
|
|
7ebc05 |
- schedule_stonith_command(cmd, dev);
|
|
|
7ebc05 |
- /* Prevent cmd from being freed */
|
|
|
7ebc05 |
- cmd = NULL;
|
|
|
7ebc05 |
- goto done;
|
|
|
7ebc05 |
+ if (next_device != NULL && is_action_required(cmd->action, next_device)) {
|
|
|
7ebc05 |
+ cmd->device_next = iter->next;
|
|
|
7ebc05 |
+ break;
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+ next_device = NULL;
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ } else if (rc != 0 && cmd->device_next && (is_action_required(cmd->action, device) == FALSE)) {
|
|
|
7ebc05 |
+ /* if this device didn't work out, see if there are any others we can try.
|
|
|
7ebc05 |
+ * if the failed device was 'required', we can't pick another device. */
|
|
|
7ebc05 |
+ next_device = g_hash_table_lookup(device_list, cmd->device_next->data);
|
|
|
7ebc05 |
+ cmd->device_next = cmd->device_next->next;
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ /* this operation requires more fencing, hooray! */
|
|
|
7ebc05 |
+ if (next_device) {
|
|
|
7ebc05 |
+ log_operation(cmd, rc, pid, device->id, output);
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ schedule_stonith_command(cmd, next_device);
|
|
|
7ebc05 |
+ /* Prevent cmd from being freed */
|
|
|
7ebc05 |
+ cmd = NULL;
|
|
|
7ebc05 |
+ goto done;
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
if (rc > 0) {
|
|
|
7ebc05 |
diff --git a/fencing/internal.h b/fencing/internal.h
|
|
|
7ebc05 |
index 4e0525c..971a32f 100644
|
|
|
7ebc05 |
--- a/fencing/internal.h
|
|
|
7ebc05 |
+++ b/fencing/internal.h
|
|
|
7ebc05 |
@@ -25,6 +25,7 @@ typedef struct stonith_device_s {
|
|
|
7ebc05 |
|
|
|
7ebc05 |
/*! list of actions that must execute on the target node. Used for unfencing */
|
|
|
7ebc05 |
char *on_target_actions;
|
|
|
7ebc05 |
+ char *required_actions;
|
|
|
7ebc05 |
GListPtr targets;
|
|
|
7ebc05 |
time_t targets_age;
|
|
|
7ebc05 |
gboolean has_attr_map;
|
|
|
7ebc05 |
diff --git a/fencing/main.c b/fencing/main.c
|
|
|
7ebc05 |
index e002125..16713fe 100644
|
|
|
7ebc05 |
--- a/fencing/main.c
|
|
|
7ebc05 |
+++ b/fencing/main.c
|
|
|
7ebc05 |
@@ -645,9 +645,13 @@ static void cib_device_update(resource_t *rsc, pe_working_set_t *data_set)
|
|
|
7ebc05 |
const char *name = NULL;
|
|
|
7ebc05 |
const char *agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE);
|
|
|
7ebc05 |
const char *provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
|
|
|
7ebc05 |
+ const char *rsc_provides = NULL;
|
|
|
7ebc05 |
|
|
|
7ebc05 |
crm_info("Device %s is allowed on %s: score=%d", rsc->id, stonith_our_uname, node->weight);
|
|
|
7ebc05 |
get_rsc_attributes(rsc->parameters, rsc, node, data_set);
|
|
|
7ebc05 |
+ get_meta_attributes(rsc->meta, rsc, node, data_set);
|
|
|
7ebc05 |
+
|
|
|
7ebc05 |
+ rsc_provides = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROVIDES);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
g_hash_table_iter_init(&gIter, rsc->parameters);
|
|
|
7ebc05 |
while (g_hash_table_iter_next(&gIter, (gpointer *) & name, (gpointer *) & value)) {
|
|
|
7ebc05 |
@@ -658,7 +662,7 @@ static void cib_device_update(resource_t *rsc, pe_working_set_t *data_set)
|
|
|
7ebc05 |
crm_trace(" %s=%s", name, value);
|
|
|
7ebc05 |
}
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- data = create_device_registration_xml(rsc_name(rsc), provider, agent, params);
|
|
|
7ebc05 |
+ data = create_device_registration_xml(rsc_name(rsc), provider, agent, params, rsc_provides);
|
|
|
7ebc05 |
stonith_device_register(data, NULL, TRUE);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
stonith_key_value_freeall(params, 1, 1);
|
|
|
7ebc05 |
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
|
|
|
7ebc05 |
index 4f30fed..2822e9a 100644
|
|
|
7ebc05 |
--- a/include/crm/fencing/internal.h
|
|
|
7ebc05 |
+++ b/include/crm/fencing/internal.h
|
|
|
7ebc05 |
@@ -46,7 +46,7 @@ xmlNode *create_level_registration_xml(const char *node, int level,
|
|
|
7ebc05 |
stonith_key_value_t * device_list);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
xmlNode *create_device_registration_xml(const char *id, const char *namespace, const char *agent,
|
|
|
7ebc05 |
- stonith_key_value_t * params);
|
|
|
7ebc05 |
+ stonith_key_value_t * params, const char *rsc_provides);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
# define ST_LEVEL_MAX 10
|
|
|
7ebc05 |
|
|
|
7ebc05 |
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
|
|
|
7ebc05 |
index 2be854f..06e0726 100644
|
|
|
7ebc05 |
--- a/lib/fencing/st_client.c
|
|
|
7ebc05 |
+++ b/lib/fencing/st_client.c
|
|
|
7ebc05 |
@@ -178,7 +178,7 @@ stonith_connection_destroy(gpointer user_data)
|
|
|
7ebc05 |
|
|
|
7ebc05 |
xmlNode *
|
|
|
7ebc05 |
create_device_registration_xml(const char *id, const char *namespace, const char *agent,
|
|
|
7ebc05 |
- stonith_key_value_t * params)
|
|
|
7ebc05 |
+ stonith_key_value_t * params, const char *rsc_provides)
|
|
|
7ebc05 |
{
|
|
|
7ebc05 |
xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
|
|
|
7ebc05 |
xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
|
|
|
7ebc05 |
@@ -195,6 +195,9 @@ create_device_registration_xml(const char *id, const char *namespace, const char
|
|
|
7ebc05 |
crm_xml_add(data, "origin", __FUNCTION__);
|
|
|
7ebc05 |
crm_xml_add(data, "agent", agent);
|
|
|
7ebc05 |
crm_xml_add(data, "namespace", namespace);
|
|
|
7ebc05 |
+ if (rsc_provides) {
|
|
|
7ebc05 |
+ crm_xml_add(data, "rsc_provides", rsc_provides);
|
|
|
7ebc05 |
+ }
|
|
|
7ebc05 |
|
|
|
7ebc05 |
for (; params; params = params->next) {
|
|
|
7ebc05 |
hash2field((gpointer) params->key, (gpointer) params->value, args);
|
|
|
7ebc05 |
@@ -211,7 +214,7 @@ stonith_api_register_device(stonith_t * st, int call_options,
|
|
|
7ebc05 |
int rc = 0;
|
|
|
7ebc05 |
xmlNode *data = NULL;
|
|
|
7ebc05 |
|
|
|
7ebc05 |
- data = create_device_registration_xml(id, namespace, agent, params);
|
|
|
7ebc05 |
+ data = create_device_registration_xml(id, namespace, agent, params, NULL);
|
|
|
7ebc05 |
|
|
|
7ebc05 |
rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
|
|
|
7ebc05 |
free_xml(data);
|