Blame SOURCES/bz1078078-pcmk-fence_using_all_required_devices.patch

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);