Blame SOURCES/002-fencing-reasons.patch

1b1151
From 95b4f87aae5fb2cf771cf9a8f8e5420b65fb213f Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 21 Sep 2021 10:47:51 -0500
1b1151
Subject: [PATCH 01/12] Refactor: fencing: use pcmk__action_result_t in
1b1151
 stonith_action_t
1b1151
1b1151
stonith_action_t previously had an rc member for a legacy return code, along
1b1151
with output and error members for action stdout/stderr. When setting rc based
1b1151
on the svc_action_t result, it used a mapping function svc_action_to_errno().
1b1151
1b1151
This replaces those with a pcmk__action_result_t member, which means we now
1b1151
track the exit status and execution status as originally set by libcrmservice,
1b1151
rather than the mapped rc. The library now calls the mapping function, now
1b1151
returning standard codes and called result2rc(), when calling the client
1b1151
callback.
1b1151
1b1151
The exit_reason member is unused as of this commit.
1b1151
1b1151
The behavior should be identical, with the small exception of
1b1151
services_action_async() failure leaving the exit status as set by the services
1b1151
library, which means callers will get the result2rc() mapping of the actual
1b1151
result instead of the former -ECONNABORTED.
1b1151
---
1b1151
 lib/fencing/st_client.c | 118 +++++++++++++++++++++++-----------------
1b1151
 1 file changed, 68 insertions(+), 50 deletions(-)
1b1151
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index 08adb51c6..6c607b010 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -29,6 +29,7 @@
1b1151
 #include <crm/msg_xml.h>
1b1151
 #include <crm/common/xml.h>
1b1151
 #include <crm/common/xml_internal.h>
1b1151
+#include <crm/services_internal.h>
1b1151
 
1b1151
 #include <crm/common/mainloop.h>
1b1151
 
1b1151
@@ -57,9 +58,7 @@ struct stonith_action_s {
1b1151
     int max_retries;
1b1151
 
1b1151
     int pid;
1b1151
-    int rc;
1b1151
-    char *output;
1b1151
-    char *error;
1b1151
+    pcmk__action_result_t result;
1b1151
 };
1b1151
 
1b1151
 typedef struct stonith_private_s {
1b1151
@@ -120,6 +119,7 @@ static void stonith_connection_destroy(gpointer user_data);
1b1151
 static void stonith_send_notification(gpointer data, gpointer user_data);
1b1151
 static int internal_stonith_action_execute(stonith_action_t * action);
1b1151
 static void log_action(stonith_action_t *action, pid_t pid);
1b1151
+static int result2rc(const pcmk__action_result_t *result);
1b1151
 
1b1151
 /*!
1b1151
  * \brief Get agent namespace by name
1b1151
@@ -196,6 +196,23 @@ stonith_get_namespace(const char *agent, const char *namespace_s)
1b1151
     return st_namespace_invalid;
1b1151
 }
1b1151
 
1b1151
+/*!
1b1151
+ * \internal
1b1151
+ * \brief Set an action's result based on services library result
1b1151
+ *
1b1151
+ * \param[in] action      Fence action to set result for
1b1151
+ * \param[in] svc_action  Service action to get result from
1b1151
+ */
1b1151
+static void
1b1151
+set_result_from_svc_action(stonith_action_t *action, svc_action_t *svc_action)
1b1151
+{
1b1151
+    pcmk__set_result(&(action->result), svc_action->rc, svc_action->status,
1b1151
+                     NULL);
1b1151
+    pcmk__set_result_output(&(action->result),
1b1151
+                            services__grab_stdout(svc_action),
1b1151
+                            services__grab_stderr(svc_action));
1b1151
+}
1b1151
+
1b1151
 gboolean
1b1151
 stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
1b1151
 {
1b1151
@@ -259,19 +276,19 @@ stonith__watchdog_fencing_enabled_for_node(const char *node)
1b1151
 static void
1b1151
 log_action(stonith_action_t *action, pid_t pid)
1b1151
 {
1b1151
-    if (action->output) {
1b1151
+    if (action->result.action_stdout != NULL) {
1b1151
         /* Logging the whole string confuses syslog when the string is xml */
1b1151
         char *prefix = crm_strdup_printf("%s[%d] stdout:", action->agent, pid);
1b1151
 
1b1151
-        crm_log_output(LOG_TRACE, prefix, action->output);
1b1151
+        crm_log_output(LOG_TRACE, prefix, action->result.action_stdout);
1b1151
         free(prefix);
1b1151
     }
1b1151
 
1b1151
-    if (action->error) {
1b1151
+    if (action->result.action_stderr != NULL) {
1b1151
         /* Logging the whole string confuses syslog when the string is xml */
1b1151
         char *prefix = crm_strdup_printf("%s[%d] stderr:", action->agent, pid);
1b1151
 
1b1151
-        crm_log_output(LOG_WARNING, prefix, action->error);
1b1151
+        crm_log_output(LOG_WARNING, prefix, action->result.action_stderr);
1b1151
         free(prefix);
1b1151
     }
1b1151
 }
1b1151
@@ -645,8 +662,7 @@ stonith__destroy_action(stonith_action_t *action)
1b1151
         if (action->svc_action) {
1b1151
             services_action_free(action->svc_action);
1b1151
         }
1b1151
-        free(action->output);
1b1151
-        free(action->error);
1b1151
+        pcmk__reset_result(&(action->result));
1b1151
         free(action);
1b1151
     }
1b1151
 }
1b1151
@@ -678,15 +694,15 @@ stonith__action_result(stonith_action_t *action, int *rc, char **output,
1b1151
     }
1b1151
     if (action != NULL) {
1b1151
         if (rc) {
1b1151
-            *rc = action->rc;
1b1151
+            *rc = pcmk_rc2legacy(result2rc(&(action->result)));
1b1151
         }
1b1151
-        if (output && action->output) {
1b1151
-            *output = action->output;
1b1151
-            action->output = NULL; // hand off memory management to caller
1b1151
+        if ((output != NULL) && (action->result.action_stdout != NULL)) {
1b1151
+            *output = action->result.action_stdout;
1b1151
+            action->result.action_stdout = NULL; // hand off ownership to caller
1b1151
         }
1b1151
-        if (error_output && action->error) {
1b1151
-            *error_output = action->error;
1b1151
-            action->error = NULL; // hand off memory management to caller
1b1151
+        if ((error_output != NULL) && (action->result.action_stderr != NULL)) {
1b1151
+            *error_output = action->result.action_stderr;
1b1151
+            action->result.action_stderr = NULL; // hand off ownership to caller
1b1151
         }
1b1151
     }
1b1151
 }
1b1151
@@ -715,6 +731,9 @@ stonith_action_create(const char *agent,
1b1151
     action->timeout = action->remaining_timeout = timeout;
1b1151
     action->max_retries = FAILURE_MAX_RETRIES;
1b1151
 
1b1151
+    pcmk__set_result(&(action->result), PCMK_OCF_UNKNOWN, PCMK_EXEC_UNKNOWN,
1b1151
+                     NULL);
1b1151
+
1b1151
     if (device_args) {
1b1151
         char buffer[512];
1b1151
         const char *value = NULL;
1b1151
@@ -739,7 +758,8 @@ update_remaining_timeout(stonith_action_t * action)
1b1151
         crm_info("Attempted to execute agent %s (%s) the maximum number of times (%d) allowed",
1b1151
                  action->agent, action->action, action->max_retries);
1b1151
         action->remaining_timeout = 0;
1b1151
-    } else if ((action->rc != -ETIME) && diff < (action->timeout * 0.7)) {
1b1151
+    } else if ((action->result.execution_status != PCMK_EXEC_TIMEOUT)
1b1151
+               && (diff < (action->timeout * 0.7))) {
1b1151
         /* only set remaining timeout period if there is 30%
1b1151
          * or greater of the original timeout period left */
1b1151
         action->remaining_timeout = action->timeout - diff;
1b1151
@@ -750,31 +770,31 @@ update_remaining_timeout(stonith_action_t * action)
1b1151
 }
1b1151
 
1b1151
 static int
1b1151
-svc_action_to_errno(svc_action_t *svc_action) {
1b1151
-    int rv = pcmk_ok;
1b1151
+result2rc(const pcmk__action_result_t *result) {
1b1151
+    int rc = pcmk_rc_ok;
1b1151
 
1b1151
-    if (svc_action->status == PCMK_EXEC_TIMEOUT) {
1b1151
-            rv = -ETIME;
1b1151
+    if (result->execution_status == PCMK_EXEC_TIMEOUT) {
1b1151
+            rc = ETIME;
1b1151
 
1b1151
-    } else if (svc_action->rc != PCMK_OCF_OK) {
1b1151
+    } else if (result->exit_status != CRM_EX_OK) {
1b1151
         /* Try to provide a useful error code based on the fence agent's
1b1151
          * error output.
1b1151
          */
1b1151
-        if (svc_action->stderr_data == NULL) {
1b1151
-            rv = -ENODATA;
1b1151
+        if (result->action_stderr == NULL) {
1b1151
+            rc = ENODATA;
1b1151
 
1b1151
-        } else if (strstr(svc_action->stderr_data, "imed out")) {
1b1151
+        } else if (strstr(result->action_stderr, "imed out")) {
1b1151
             /* Some agents have their own internal timeouts */
1b1151
-            rv = -ETIME;
1b1151
+            rc = ETIME;
1b1151
 
1b1151
-        } else if (strstr(svc_action->stderr_data, "Unrecognised action")) {
1b1151
-            rv = -EOPNOTSUPP;
1b1151
+        } else if (strstr(result->action_stderr, "Unrecognised action")) {
1b1151
+            rc = EOPNOTSUPP;
1b1151
 
1b1151
         } else {
1b1151
-            rv = -pcmk_err_generic;
1b1151
+            rc = pcmk_rc_error;
1b1151
         }
1b1151
     }
1b1151
-    return rv;
1b1151
+    return rc;
1b1151
 }
1b1151
 
1b1151
 static void
1b1151
@@ -782,11 +802,7 @@ stonith_action_async_done(svc_action_t *svc_action)
1b1151
 {
1b1151
     stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
1b1151
 
1b1151
-    action->rc = svc_action_to_errno(svc_action);
1b1151
-    action->output = svc_action->stdout_data;
1b1151
-    svc_action->stdout_data = NULL;
1b1151
-    action->error = svc_action->stderr_data;
1b1151
-    svc_action->stderr_data = NULL;
1b1151
+    set_result_from_svc_action(action, svc_action);
1b1151
 
1b1151
     svc_action->params = NULL;
1b1151
 
1b1151
@@ -795,7 +811,9 @@ stonith_action_async_done(svc_action_t *svc_action)
1b1151
 
1b1151
     log_action(action, action->pid);
1b1151
 
1b1151
-    if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
1b1151
+    if ((action->result.exit_status != CRM_EX_OK)
1b1151
+        && update_remaining_timeout(action)) {
1b1151
+
1b1151
         int rc = internal_stonith_action_execute(action);
1b1151
         if (rc == pcmk_ok) {
1b1151
             return;
1b1151
@@ -803,7 +821,8 @@ stonith_action_async_done(svc_action_t *svc_action)
1b1151
     }
1b1151
 
1b1151
     if (action->done_cb) {
1b1151
-        action->done_cb(action->pid, action->rc, action->output, action->userdata);
1b1151
+        action->done_cb(action->pid, pcmk_rc2legacy(result2rc(&(action->result))),
1b1151
+                        action->result.action_stdout, action->userdata);
1b1151
     }
1b1151
 
1b1151
     action->svc_action = NULL; // don't remove our caller
1b1151
@@ -835,9 +854,13 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
     static int stonith_sequence = 0;
1b1151
     char *buffer = NULL;
1b1151
 
1b1151
-    if ((action == NULL) || (action->action == NULL) || (action->args == NULL)
1b1151
+    CRM_CHECK(action != NULL, return -EINVAL);
1b1151
+
1b1151
+    if ((action->action == NULL) || (action->args == NULL)
1b1151
         || (action->agent == NULL)) {
1b1151
-        return -EPROTO;
1b1151
+        pcmk__set_result(&(action->result), PCMK_OCF_UNKNOWN_ERROR,
1b1151
+                         PCMK_EXEC_ERROR_FATAL, NULL);
1b1151
+        return -EINVAL;
1b1151
     }
1b1151
 
1b1151
     if (!action->tries) {
1b1151
@@ -857,6 +880,7 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
     free(buffer);
1b1151
 
1b1151
     if (svc_action->rc != PCMK_OCF_UNKNOWN) {
1b1151
+        set_result_from_svc_action(action, svc_action);
1b1151
         services_action_free(svc_action);
1b1151
         return -E2BIG;
1b1151
     }
1b1151
@@ -877,10 +901,7 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
 
1b1151
     /* keep retries from executing out of control and free previous results */
1b1151
     if (is_retry) {
1b1151
-        free(action->output);
1b1151
-        action->output = NULL;
1b1151
-        free(action->error);
1b1151
-        action->error = NULL;
1b1151
+        pcmk__reset_result(&(action->result));
1b1151
         sleep(1);
1b1151
     }
1b1151
 
1b1151
@@ -889,22 +910,19 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
         if (services_action_async_fork_notify(svc_action,
1b1151
                                               &stonith_action_async_done,
1b1151
                                               &stonith_action_async_forked)) {
1b1151
+            pcmk__set_result(&(action->result), PCMK_OCF_UNKNOWN,
1b1151
+                             PCMK_EXEC_PENDING, NULL);
1b1151
             return pcmk_ok;
1b1151
         }
1b1151
 
1b1151
     } else if (services_action_sync(svc_action)) { // sync success
1b1151
         rc = pcmk_ok;
1b1151
-        action->rc = svc_action_to_errno(svc_action);
1b1151
-        action->output = svc_action->stdout_data;
1b1151
-        svc_action->stdout_data = NULL;
1b1151
-        action->error = svc_action->stderr_data;
1b1151
-        svc_action->stderr_data = NULL;
1b1151
 
1b1151
     } else { // sync failure
1b1151
-        action->rc = -ECONNABORTED;
1b1151
-        rc = action->rc;
1b1151
+        rc = -ECONNABORTED;
1b1151
     }
1b1151
 
1b1151
+    set_result_from_svc_action(action, svc_action);
1b1151
     svc_action->params = NULL;
1b1151
     services_action_free(svc_action);
1b1151
     return rc;
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 4c8e0b0ecc53cb3883f0da0eede20b900fff48d1 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 21 Sep 2021 11:14:31 -0500
1b1151
Subject: [PATCH 02/12] Low: fencing: improve return code given back to library
1b1151
 callers
1b1151
1b1151
Expose result2rc() internally for future reuse, and expand it to handle more
1b1151
cases. In theory, this can give us better log messages and status output for
1b1151
failures.
1b1151
---
1b1151
 include/crm/fencing/internal.h |  1 +
1b1151
 lib/fencing/st_client.c        | 63 +++++++++++++++++++++-------------
1b1151
 2 files changed, 41 insertions(+), 23 deletions(-)
1b1151
1b1151
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
1b1151
index fa9059e6f..0d23967bb 100644
1b1151
--- a/include/crm/fencing/internal.h
1b1151
+++ b/include/crm/fencing/internal.h
1b1151
@@ -60,6 +60,7 @@ stonith_action_t *stonith_action_create(const char *agent,
1b1151
 void stonith__destroy_action(stonith_action_t *action);
1b1151
 void stonith__action_result(stonith_action_t *action, int *rc, char **output,
1b1151
                             char **error_output);
1b1151
+int stonith__result2rc(const pcmk__action_result_t *result);
1b1151
 
1b1151
 int
1b1151
 stonith_action_execute_async(stonith_action_t * action,
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index 6c607b010..809be1640 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -119,7 +119,6 @@ static void stonith_connection_destroy(gpointer user_data);
1b1151
 static void stonith_send_notification(gpointer data, gpointer user_data);
1b1151
 static int internal_stonith_action_execute(stonith_action_t * action);
1b1151
 static void log_action(stonith_action_t *action, pid_t pid);
1b1151
-static int result2rc(const pcmk__action_result_t *result);
1b1151
 
1b1151
 /*!
1b1151
  * \brief Get agent namespace by name
1b1151
@@ -694,7 +693,7 @@ stonith__action_result(stonith_action_t *action, int *rc, char **output,
1b1151
     }
1b1151
     if (action != NULL) {
1b1151
         if (rc) {
1b1151
-            *rc = pcmk_rc2legacy(result2rc(&(action->result)));
1b1151
+            *rc = pcmk_rc2legacy(stonith__result2rc(&(action->result)));
1b1151
         }
1b1151
         if ((output != NULL) && (action->result.action_stdout != NULL)) {
1b1151
             *output = action->result.action_stdout;
1b1151
@@ -769,32 +768,49 @@ update_remaining_timeout(stonith_action_t * action)
1b1151
     return action->remaining_timeout ? TRUE : FALSE;
1b1151
 }
1b1151
 
1b1151
-static int
1b1151
-result2rc(const pcmk__action_result_t *result) {
1b1151
-    int rc = pcmk_rc_ok;
1b1151
+/*!
1b1151
+ * \internal
1b1151
+ * \brief Map a fencing action result to a standard return code
1b1151
+ *
1b1151
+ * \param[in] result  Fencing action result to map
1b1151
+ *
1b1151
+ * \return Standard Pacemaker return code that best corresponds to \p result
1b1151
+ */
1b1151
+int
1b1151
+stonith__result2rc(const pcmk__action_result_t *result)
1b1151
+{
1b1151
+    switch (result->execution_status) {
1b1151
+        case PCMK_EXEC_CANCELLED:       return ECANCELED;
1b1151
+        case PCMK_EXEC_TIMEOUT:         return ETIME;
1b1151
+        case PCMK_EXEC_NOT_INSTALLED:   return ENOENT;
1b1151
+        case PCMK_EXEC_NOT_SUPPORTED:   return EOPNOTSUPP;
1b1151
+        case PCMK_EXEC_NOT_CONNECTED:   return ENOTCONN;
1b1151
+        case PCMK_EXEC_NO_FENCE_DEVICE: return ENODEV;
1b1151
+        case PCMK_EXEC_NO_SECRETS:      return EACCES;
1b1151
+        default:                        break;
1b1151
+    }
1b1151
 
1b1151
-    if (result->execution_status == PCMK_EXEC_TIMEOUT) {
1b1151
-            rc = ETIME;
1b1151
+    if (result->exit_status == CRM_EX_OK) {
1b1151
+        return pcmk_rc_ok;
1b1151
+    }
1b1151
 
1b1151
-    } else if (result->exit_status != CRM_EX_OK) {
1b1151
-        /* Try to provide a useful error code based on the fence agent's
1b1151
-         * error output.
1b1151
-         */
1b1151
-        if (result->action_stderr == NULL) {
1b1151
-            rc = ENODATA;
1b1151
+    // Try to provide useful error code based on result's error output
1b1151
 
1b1151
-        } else if (strstr(result->action_stderr, "imed out")) {
1b1151
-            /* Some agents have their own internal timeouts */
1b1151
-            rc = ETIME;
1b1151
+    if (result->action_stderr == NULL) {
1b1151
+        return ENODATA;
1b1151
 
1b1151
-        } else if (strstr(result->action_stderr, "Unrecognised action")) {
1b1151
-            rc = EOPNOTSUPP;
1b1151
+    } else if (strcasestr(result->action_stderr, "timed out")
1b1151
+               || strcasestr(result->action_stderr, "timeout")) {
1b1151
+        return ETIME;
1b1151
 
1b1151
-        } else {
1b1151
-            rc = pcmk_rc_error;
1b1151
-        }
1b1151
+    } else if (strcasestr(result->action_stderr, "unrecognised action")
1b1151
+               || strcasestr(result->action_stderr, "unrecognized action")
1b1151
+               || strcasestr(result->action_stderr, "unsupported action")) {
1b1151
+        return EOPNOTSUPP;
1b1151
     }
1b1151
-    return rc;
1b1151
+
1b1151
+    // Oh well, we tried
1b1151
+    return pcmk_rc_error;
1b1151
 }
1b1151
 
1b1151
 static void
1b1151
@@ -821,7 +837,8 @@ stonith_action_async_done(svc_action_t *svc_action)
1b1151
     }
1b1151
 
1b1151
     if (action->done_cb) {
1b1151
-        action->done_cb(action->pid, pcmk_rc2legacy(result2rc(&(action->result))),
1b1151
+        action->done_cb(action->pid,
1b1151
+                        pcmk_rc2legacy(stonith__result2rc(&(action->result))),
1b1151
                         action->result.action_stdout, action->userdata);
1b1151
     }
1b1151
 
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 153c9b552a5bad9dd36e8635fa478ed9cad1f240 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Thu, 7 Oct 2021 11:35:44 -0500
1b1151
Subject: [PATCH 03/12] Refactor: fencing: return full result from
1b1151
 stonith__action_result()
1b1151
1b1151
Previously, stonith__action_result() grabbed an action's legacy rc, stdout, and
1b1151
stderr separately. Now, directly return a pointer to the action's result
1b1151
object, and map that to a legacy rc in the callers when needed.
1b1151
---
1b1151
 include/crm/fencing/internal.h |  3 +--
1b1151
 lib/fencing/st_client.c        | 36 ++++---------------------
1b1151
 lib/fencing/st_rhcs.c          | 48 ++++++++++++++++++++++++----------
1b1151
 3 files changed, 40 insertions(+), 47 deletions(-)
1b1151
1b1151
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
1b1151
index 0d23967bb..4e9f50fe8 100644
1b1151
--- a/include/crm/fencing/internal.h
1b1151
+++ b/include/crm/fencing/internal.h
1b1151
@@ -58,8 +58,7 @@ stonith_action_t *stonith_action_create(const char *agent,
1b1151
                                         GHashTable * port_map,
1b1151
                                         const char * host_arg);
1b1151
 void stonith__destroy_action(stonith_action_t *action);
1b1151
-void stonith__action_result(stonith_action_t *action, int *rc, char **output,
1b1151
-                            char **error_output);
1b1151
+pcmk__action_result_t *stonith__action_result(stonith_action_t *action);
1b1151
 int stonith__result2rc(const pcmk__action_result_t *result);
1b1151
 
1b1151
 int
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index 809be1640..b9df18465 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -670,40 +670,14 @@ stonith__destroy_action(stonith_action_t *action)
1b1151
  * \internal
1b1151
  * \brief Get the result of an executed stonith action
1b1151
  *
1b1151
- * \param[in,out] action        Executed action
1b1151
- * \param[out]    rc            Where to store result code (or NULL)
1b1151
- * \param[out]    output        Where to store standard output (or NULL)
1b1151
- * \param[out]    error_output  Where to store standard error output (or NULL)
1b1151
+ * \param[in] action  Executed action
1b1151
  *
1b1151
- * \note If output or error_output is not NULL, the caller is responsible for
1b1151
- *       freeing the memory.
1b1151
+ * \return Pointer to action's result (or NULL if \p action is NULL)
1b1151
  */
1b1151
-void
1b1151
-stonith__action_result(stonith_action_t *action, int *rc, char **output,
1b1151
-                       char **error_output)
1b1151
+pcmk__action_result_t *
1b1151
+stonith__action_result(stonith_action_t *action)
1b1151
 {
1b1151
-    if (rc) {
1b1151
-        *rc = pcmk_ok;
1b1151
-    }
1b1151
-    if (output) {
1b1151
-        *output = NULL;
1b1151
-    }
1b1151
-    if (error_output) {
1b1151
-        *error_output = NULL;
1b1151
-    }
1b1151
-    if (action != NULL) {
1b1151
-        if (rc) {
1b1151
-            *rc = pcmk_rc2legacy(stonith__result2rc(&(action->result)));
1b1151
-        }
1b1151
-        if ((output != NULL) && (action->result.action_stdout != NULL)) {
1b1151
-            *output = action->result.action_stdout;
1b1151
-            action->result.action_stdout = NULL; // hand off ownership to caller
1b1151
-        }
1b1151
-        if ((error_output != NULL) && (action->result.action_stderr != NULL)) {
1b1151
-            *error_output = action->result.action_stderr;
1b1151
-            action->result.action_stderr = NULL; // hand off ownership to caller
1b1151
-        }
1b1151
-    }
1b1151
+    return (action == NULL)? NULL : &(action->result);
1b1151
 }
1b1151
 
1b1151
 #define FAILURE_MAX_RETRIES 2
1b1151
diff --git a/lib/fencing/st_rhcs.c b/lib/fencing/st_rhcs.c
1b1151
index 89a2625bd..23e694975 100644
1b1151
--- a/lib/fencing/st_rhcs.c
1b1151
+++ b/lib/fencing/st_rhcs.c
1b1151
@@ -1,5 +1,5 @@
1b1151
 /*
1b1151
- * Copyright 2004-2020 the Pacemaker project contributors
1b1151
+ * Copyright 2004-2021 the Pacemaker project contributors
1b1151
  *
1b1151
  * The version control history for this file may have further details.
1b1151
  *
1b1151
@@ -123,10 +123,10 @@ stonith_rhcs_parameter_not_required(xmlNode *metadata, const char *parameter)
1b1151
 static int
1b1151
 stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
1b1151
 {
1b1151
-    char *buffer = NULL;
1b1151
     xmlNode *xml = NULL;
1b1151
     xmlNode *actions = NULL;
1b1151
     xmlXPathObject *xpathObj = NULL;
1b1151
+    pcmk__action_result_t *result = NULL;
1b1151
     stonith_action_t *action = stonith_action_create(agent, "metadata", NULL, 0,
1b1151
                                                      5, NULL, NULL, NULL);
1b1151
     int rc = stonith__execute(action);
1b1151
@@ -138,23 +138,31 @@ stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
1b1151
         return rc;
1b1151
     }
1b1151
 
1b1151
-    stonith__action_result(action, &rc, &buffer, NULL);
1b1151
-    stonith__destroy_action(action);
1b1151
-    if (rc < 0) {
1b1151
-        crm_warn("Metadata action for %s failed: %s " CRM_XS "rc=%d",
1b1151
-                 agent, pcmk_strerror(rc), rc);
1b1151
-        free(buffer);
1b1151
-        return rc;
1b1151
+    result = stonith__action_result(action);
1b1151
+
1b1151
+    if (result->execution_status != PCMK_EXEC_DONE) {
1b1151
+        crm_warn("Could not execute metadata action for %s: %s",
1b1151
+                 agent, pcmk_exec_status_str(result->execution_status));
1b1151
+        stonith__destroy_action(action);
1b1151
+        return pcmk_rc2legacy(stonith__result2rc(result));
1b1151
     }
1b1151
 
1b1151
-    if (buffer == NULL) {
1b1151
+    if (result->exit_status != CRM_EX_OK) {
1b1151
+        crm_warn("Metadata action for %s returned error code %d",
1b1151
+                 agent, result->exit_status);
1b1151
+        stonith__destroy_action(action);
1b1151
+        return pcmk_rc2legacy(stonith__result2rc(result));
1b1151
+    }
1b1151
+
1b1151
+    if (result->action_stdout == NULL) {
1b1151
         crm_warn("Metadata action for %s returned no data", agent);
1b1151
+        stonith__destroy_action(action);
1b1151
         return -ENODATA;
1b1151
     }
1b1151
 
1b1151
-    xml = string2xml(buffer);
1b1151
-    free(buffer);
1b1151
-    buffer = NULL;
1b1151
+    xml = string2xml(result->action_stdout);
1b1151
+    stonith__destroy_action(action);
1b1151
+
1b1151
     if (xml == NULL) {
1b1151
         crm_warn("Metadata for %s is invalid", agent);
1b1151
         return -pcmk_err_schema_validation;
1b1151
@@ -289,7 +297,19 @@ stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
1b1151
 
1b1151
     rc = stonith__execute(action);
1b1151
     if (rc == pcmk_ok) {
1b1151
-        stonith__action_result(action, &rc, output, error_output);
1b1151
+        pcmk__action_result_t *result = stonith__action_result(action);
1b1151
+
1b1151
+        rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
+
1b1151
+        // Take ownership of output so stonith__destroy_action() doesn't free it
1b1151
+        if (output != NULL) {
1b1151
+            *output = result->action_stdout;
1b1151
+            result->action_stdout = NULL;
1b1151
+        }
1b1151
+        if (error_output != NULL) {
1b1151
+            *error_output = result->action_stderr;
1b1151
+            result->action_stderr = NULL;
1b1151
+        }
1b1151
     }
1b1151
     stonith__destroy_action(action);
1b1151
     return rc;
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 7f7067014357cccb229a0bef091e234eb3765f7a Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 21 Sep 2021 13:05:54 -0500
1b1151
Subject: [PATCH 04/12] Refactor: fencing: pass full result to async action
1b1151
 callback
1b1151
1b1151
When executing an asynchronous fence agent command, the fencing library gets
1b1151
the full result (exit status, execution status, and exit reason) from the
1b1151
services library, then maps that to a legacy return code.
1b1151
1b1151
Now, pass the full result object to the fencing async callback, rather than
1b1151
separate arguments for legacy code and stdout. The mapping to a legacy code now
1b1151
happens in the fencer rather than the fencing library.
1b1151
1b1151
The goal of this and following commits is to push the full result object
1b1151
further down the code path, so that ultimately the full result is always
1b1151
available internally, and the legacy code mapping is only done for backward
1b1151
compatibility when sending the result back to a client.
1b1151
1b1151
This commit focuses on the async callback (done_cb() in both the fencer's
1b1151
async_command_t and the fencing library's stonith_action_t). Later commits will
1b1151
follow the chain:
1b1151
1b1151
	st_child_done() and stonith_fence_get_devices_cb()
1b1151
	-> stonith_send_async_reply()
1b1151
	-> stonith_construct_async_reply() and log_async_result()
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 78 +++++++++++++++++++++-----------
1b1151
 include/crm/fencing/internal.h   |  3 +-
1b1151
 lib/fencing/st_client.c          | 10 ++--
1b1151
 3 files changed, 58 insertions(+), 33 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index b5ae28d90..d5d04ae69 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -62,7 +62,8 @@ struct device_search_s {
1b1151
 };
1b1151
 
1b1151
 static gboolean stonith_device_dispatch(gpointer user_data);
1b1151
-static void st_child_done(int pid, int rc, const char *output, void *user_data);
1b1151
+static void st_child_done(int pid, const pcmk__action_result_t *result,
1b1151
+                          void *user_data);
1b1151
 static void stonith_send_reply(xmlNode * reply, int call_options, const char *remote_peer,
1b1151
                                const char *client_id);
1b1151
 
1b1151
@@ -99,7 +100,8 @@ typedef struct async_command_s {
1b1151
     GList *device_next;
1b1151
 
1b1151
     void *internal_user_data;
1b1151
-    void (*done_cb) (int pid, int rc, const char *output, void *user_data);
1b1151
+    void (*done_cb) (int pid, const pcmk__action_result_t *result,
1b1151
+                     void *user_data);
1b1151
     guint timer_sigterm;
1b1151
     guint timer_sigkill;
1b1151
     /*! If the operation timed out, this is the last signal
1b1151
@@ -377,13 +379,25 @@ get_agent_metadata_cb(gpointer data) {
1b1151
  * \internal
1b1151
  * \brief Call a command's action callback for an internal (not library) result
1b1151
  *
1b1151
- * \param[in] cmd     Command to report result for
1b1151
- * \param[in] rc      Legacy return code to pass to callback
1b1151
+ * \param[in] cmd               Command to report result for
1b1151
+ * \param[in] execution_status  Execution status to use for result
1b1151
+ * \param[in] exit_status       Exit status to use for result
1b1151
+ * \param[in] exit_reason       Exit reason to use for result
1b1151
  */
1b1151
 static void
1b1151
-report_internal_result(async_command_t *cmd, int rc)
1b1151
+report_internal_result(async_command_t *cmd, int exit_status,
1b1151
+                       int execution_status, const char *exit_reason)
1b1151
 {
1b1151
-    cmd->done_cb(0, rc, NULL, cmd);
1b1151
+    pcmk__action_result_t result = {
1b1151
+        // Ensure we don't pass garbage to free()
1b1151
+        .exit_reason = NULL,
1b1151
+        .action_stdout = NULL,
1b1151
+        .action_stderr = NULL
1b1151
+    };
1b1151
+
1b1151
+    pcmk__set_result(&result, exit_status, execution_status, exit_reason);
1b1151
+    cmd->done_cb(0, &result, cmd);
1b1151
+    pcmk__reset_result(&result);
1b1151
 }
1b1151
 
1b1151
 static gboolean
1b1151
@@ -446,7 +460,7 @@ stonith_device_execute(stonith_device_t * device)
1b1151
             }
1b1151
         } else {
1b1151
             crm_info("Faking success for %s watchdog operation", cmd->action);
1b1151
-            report_internal_result(cmd, pcmk_ok);
1b1151
+            report_internal_result(cmd, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
1b1151
             goto done;
1b1151
         }
1b1151
     }
1b1151
@@ -462,7 +476,8 @@ stonith_device_execute(stonith_device_t * device)
1b1151
             crm_err("Considering %s unconfigured "
1b1151
                     "because unable to load CIB secrets: %s",
1b1151
                      device->id, pcmk_rc_str(exec_rc));
1b1151
-            report_internal_result(cmd, -EACCES);
1b1151
+            report_internal_result(cmd, CRM_EX_ERROR, PCMK_EXEC_NO_SECRETS,
1b1151
+                                   NULL);
1b1151
             goto done;
1b1151
         }
1b1151
     }
1b1151
@@ -501,7 +516,7 @@ stonith_device_execute(stonith_device_t * device)
1b1151
                                            cmd->done_cb, fork_cb);
1b1151
     if (exec_rc < 0) {
1b1151
         cmd->activating_on = NULL;
1b1151
-        report_internal_result(cmd, exec_rc);
1b1151
+        cmd->done_cb(0, stonith__action_result(action), cmd);
1b1151
         stonith__destroy_action(action);
1b1151
     }
1b1151
 
1b1151
@@ -625,7 +640,8 @@ free_device(gpointer data)
1b1151
         async_command_t *cmd = gIter->data;
1b1151
 
1b1151
         crm_warn("Removal of device '%s' purged operation '%s'", device->id, cmd->action);
1b1151
-        report_internal_result(cmd, -ENODEV);
1b1151
+        report_internal_result(cmd, CRM_EX_ERROR, PCMK_EXEC_NO_FENCE_DEVICE,
1b1151
+                               NULL);
1b1151
     }
1b1151
     g_list_free(device->pending_ops);
1b1151
 
1b1151
@@ -1079,7 +1095,8 @@ schedule_internal_command(const char *origin,
1b1151
                           const char *victim,
1b1151
                           int timeout,
1b1151
                           void *internal_user_data,
1b1151
-                          void (*done_cb) (int pid, int rc, const char *output,
1b1151
+                          void (*done_cb) (int pid,
1b1151
+                                           const pcmk__action_result_t *result,
1b1151
                                            void *user_data))
1b1151
 {
1b1151
     async_command_t *cmd = NULL;
1b1151
@@ -1111,7 +1128,7 @@ enum fence_status_code {
1b1151
 };
1b1151
 
1b1151
 static void
1b1151
-status_search_cb(int pid, int rc, const char *output, void *user_data)
1b1151
+status_search_cb(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
 {
1b1151
     async_command_t *cmd = user_data;
1b1151
     struct device_search_s *search = cmd->internal_user_data;
1b1151
@@ -1127,7 +1144,7 @@ status_search_cb(int pid, int rc, const char *output, void *user_data)
1b1151
 
1b1151
     mainloop_set_trigger(dev->work);
1b1151
 
1b1151
-    switch (rc) {
1b1151
+    switch (result->exit_status) {
1b1151
         case fence_status_unknown:
1b1151
             crm_trace("%s reported it cannot fence %s", dev->id, search->host);
1b1151
             break;
1b1151
@@ -1141,14 +1158,15 @@ status_search_cb(int pid, int rc, const char *output, void *user_data)
1b1151
         default:
1b1151
             crm_warn("Assuming %s cannot fence %s "
1b1151
                      "(status returned unknown code %d)",
1b1151
-                     dev->id, search->host, rc);
1b1151
+                     dev->id, search->host, result->exit_status);
1b1151
             break;
1b1151
     }
1b1151
     search_devices_record_result(search, dev->id, can);
1b1151
 }
1b1151
 
1b1151
 static void
1b1151
-dynamic_list_search_cb(int pid, int rc, const char *output, void *user_data)
1b1151
+dynamic_list_search_cb(int pid, const pcmk__action_result_t *result,
1b1151
+                       void *user_data)
1b1151
 {
1b1151
     async_command_t *cmd = user_data;
1b1151
     struct device_search_s *search = cmd->internal_user_data;
1b1151
@@ -1169,21 +1187,21 @@ dynamic_list_search_cb(int pid, int rc, const char *output, void *user_data)
1b1151
 
1b1151
     mainloop_set_trigger(dev->work);
1b1151
 
1b1151
-    if (rc == CRM_EX_OK) {
1b1151
+    if (result->exit_status == CRM_EX_OK) {
1b1151
         crm_info("Refreshing target list for %s", dev->id);
1b1151
         g_list_free_full(dev->targets, free);
1b1151
-        dev->targets = stonith__parse_targets(output);
1b1151
+        dev->targets = stonith__parse_targets(result->action_stdout);
1b1151
         dev->targets_age = time(NULL);
1b1151
 
1b1151
     } else if (dev->targets != NULL) {
1b1151
         crm_info("Reusing most recent target list for %s "
1b1151
                  "because list returned error code %d",
1b1151
-                 dev->id, rc);
1b1151
+                 dev->id, result->exit_status);
1b1151
 
1b1151
     } else { // We have never successfully executed list
1b1151
         crm_warn("Assuming %s cannot fence %s "
1b1151
                  "because list returned error code %d",
1b1151
-                 dev->id, search->host, rc);
1b1151
+                 dev->id, search->host, result->exit_status);
1b1151
 
1b1151
         /* Fall back to pcmk_host_check="status" if the user didn't explicitly
1b1151
          * specify "dynamic-list".
1b1151
@@ -2407,7 +2425,7 @@ cancel_stonith_command(async_command_t * cmd)
1b1151
 }
1b1151
 
1b1151
 static void
1b1151
-st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
+st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
 {
1b1151
     stonith_device_t *device = NULL;
1b1151
     stonith_device_t *next_device = NULL;
1b1151
@@ -2423,7 +2441,7 @@ st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
     /* The device is ready to do something else now */
1b1151
     device = g_hash_table_lookup(device_list, cmd->device);
1b1151
     if (device) {
1b1151
-        if (!device->verified && (rc == pcmk_ok) &&
1b1151
+        if (!device->verified && (result->exit_status == CRM_EX_OK) &&
1b1151
             (pcmk__strcase_any_of(cmd->action, "list", "monitor", "status", NULL))) {
1b1151
 
1b1151
             device->verified = TRUE;
1b1151
@@ -2432,7 +2450,7 @@ st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
         mainloop_set_trigger(device->work);
1b1151
     }
1b1151
 
1b1151
-    if (rc == 0) {
1b1151
+    if (result->exit_status == CRM_EX_OK) {
1b1151
         GList *iter;
1b1151
         /* see if there are any required devices left to execute for this op */
1b1151
         for (iter = cmd->device_next; iter != NULL; iter = iter->next) {
1b1151
@@ -2445,7 +2463,8 @@ st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
             next_device = NULL;
1b1151
         }
1b1151
 
1b1151
-    } else if (rc != 0 && cmd->device_next && (is_action_required(cmd->action, device) == FALSE)) {
1b1151
+    } else if ((cmd->device_next != NULL)
1b1151
+               && !is_action_required(cmd->action, device)) {
1b1151
         /* if this device didn't work out, see if there are any others we can try.
1b1151
          * if the failed device was 'required', we can't pick another device. */
1b1151
         next_device = g_hash_table_lookup(device_list, cmd->device_next->data);
1b1151
@@ -2454,16 +2473,19 @@ st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
 
1b1151
     /* this operation requires more fencing, hooray! */
1b1151
     if (next_device) {
1b1151
-        log_async_result(cmd, rc, pid, next_device->id, output, FALSE);
1b1151
+        log_async_result(cmd, pcmk_rc2legacy(stonith__result2rc(result)), pid,
1b1151
+                         next_device->id, result->action_stdout, FALSE);
1b1151
         schedule_stonith_command(cmd, next_device);
1b1151
         /* Prevent cmd from being freed */
1b1151
         cmd = NULL;
1b1151
         goto done;
1b1151
     }
1b1151
 
1b1151
-    stonith_send_async_reply(cmd, output, rc, pid, false);
1b1151
+    stonith_send_async_reply(cmd, result->action_stdout,
1b1151
+                             pcmk_rc2legacy(stonith__result2rc(result)), pid,
1b1151
+                             false);
1b1151
 
1b1151
-    if (rc != 0) {
1b1151
+    if (result->exit_status != CRM_EX_OK) {
1b1151
         goto done;
1b1151
     }
1b1151
 
1b1151
@@ -2509,7 +2531,9 @@ st_child_done(int pid, int rc, const char *output, void *user_data)
1b1151
 
1b1151
         cmd_list = g_list_remove_link(cmd_list, gIter);
1b1151
 
1b1151
-        stonith_send_async_reply(cmd_other, output, rc, pid, true);
1b1151
+        stonith_send_async_reply(cmd_other, result->action_stdout,
1b1151
+                                 pcmk_rc2legacy(stonith__result2rc(result)),
1b1151
+                                 pid, true);
1b1151
         cancel_stonith_command(cmd_other);
1b1151
 
1b1151
         free_async_command(cmd_other);
1b1151
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
1b1151
index 4e9f50fe8..6a7e4232c 100644
1b1151
--- a/include/crm/fencing/internal.h
1b1151
+++ b/include/crm/fencing/internal.h
1b1151
@@ -64,7 +64,8 @@ int stonith__result2rc(const pcmk__action_result_t *result);
1b1151
 int
1b1151
 stonith_action_execute_async(stonith_action_t * action,
1b1151
                              void *userdata,
1b1151
-                             void (*done) (int pid, int rc, const char *output,
1b1151
+                             void (*done) (int pid,
1b1151
+                                           const pcmk__action_result_t *result,
1b1151
                                            void *user_data),
1b1151
                              void (*fork_cb) (int pid, void *user_data));
1b1151
 
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index b9df18465..59dcab9a3 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -46,7 +46,8 @@ struct stonith_action_s {
1b1151
     int timeout;
1b1151
     int async;
1b1151
     void *userdata;
1b1151
-    void (*done_cb) (int pid, int status, const char *output, void *user_data);
1b1151
+    void (*done_cb) (int pid, const pcmk__action_result_t *result,
1b1151
+                     void *user_data);
1b1151
     void (*fork_cb) (int pid, void *user_data);
1b1151
 
1b1151
     svc_action_t *svc_action;
1b1151
@@ -811,9 +812,7 @@ stonith_action_async_done(svc_action_t *svc_action)
1b1151
     }
1b1151
 
1b1151
     if (action->done_cb) {
1b1151
-        action->done_cb(action->pid,
1b1151
-                        pcmk_rc2legacy(stonith__result2rc(&(action->result))),
1b1151
-                        action->result.action_stdout, action->userdata);
1b1151
+        action->done_cb(action->pid, &(action->result), action->userdata);
1b1151
     }
1b1151
 
1b1151
     action->svc_action = NULL; // don't remove our caller
1b1151
@@ -933,7 +932,8 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
 int
1b1151
 stonith_action_execute_async(stonith_action_t * action,
1b1151
                              void *userdata,
1b1151
-                             void (*done) (int pid, int rc, const char *output,
1b1151
+                             void (*done) (int pid,
1b1151
+                                           const pcmk__action_result_t *result,
1b1151
                                            void *user_data),
1b1151
                              void (*fork_cb) (int pid, void *user_data))
1b1151
 {
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From bbd022306df7a873c0ecb2be2d33c56fbf327b8c Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 21 Sep 2021 11:51:28 -0500
1b1151
Subject: [PATCH 05/12] Feature: fencing: set exit reason for internal
1b1151
 execution errors
1b1151
1b1151
... most importantly, copying any exit reason set by the services library.
1b1151
This ensures that the stonith_action_t exit reason is set when appropriate.
1b1151
However, nothing uses it as of this commit.
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 4 ++--
1b1151
 lib/fencing/st_client.c          | 6 +++---
1b1151
 2 files changed, 5 insertions(+), 5 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index d5d04ae69..f55a32649 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -477,7 +477,7 @@ stonith_device_execute(stonith_device_t * device)
1b1151
                     "because unable to load CIB secrets: %s",
1b1151
                      device->id, pcmk_rc_str(exec_rc));
1b1151
             report_internal_result(cmd, CRM_EX_ERROR, PCMK_EXEC_NO_SECRETS,
1b1151
-                                   NULL);
1b1151
+                                   "Failed to get CIB secrets");
1b1151
             goto done;
1b1151
         }
1b1151
     }
1b1151
@@ -641,7 +641,7 @@ free_device(gpointer data)
1b1151
 
1b1151
         crm_warn("Removal of device '%s' purged operation '%s'", device->id, cmd->action);
1b1151
         report_internal_result(cmd, CRM_EX_ERROR, PCMK_EXEC_NO_FENCE_DEVICE,
1b1151
-                               NULL);
1b1151
+                               "Device was removed before action could be executed");
1b1151
     }
1b1151
     g_list_free(device->pending_ops);
1b1151
 
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index 59dcab9a3..3d4127eff 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -207,7 +207,7 @@ static void
1b1151
 set_result_from_svc_action(stonith_action_t *action, svc_action_t *svc_action)
1b1151
 {
1b1151
     pcmk__set_result(&(action->result), svc_action->rc, svc_action->status,
1b1151
-                     NULL);
1b1151
+                     services__exit_reason(svc_action));
1b1151
     pcmk__set_result_output(&(action->result),
1b1151
                             services__grab_stdout(svc_action),
1b1151
                             services__grab_stderr(svc_action));
1b1151
@@ -706,7 +706,7 @@ stonith_action_create(const char *agent,
1b1151
     action->max_retries = FAILURE_MAX_RETRIES;
1b1151
 
1b1151
     pcmk__set_result(&(action->result), PCMK_OCF_UNKNOWN, PCMK_EXEC_UNKNOWN,
1b1151
-                     NULL);
1b1151
+                     "Initialization bug in fencing library");
1b1151
 
1b1151
     if (device_args) {
1b1151
         char buffer[512];
1b1151
@@ -849,7 +849,7 @@ internal_stonith_action_execute(stonith_action_t * action)
1b1151
     if ((action->action == NULL) || (action->args == NULL)
1b1151
         || (action->agent == NULL)) {
1b1151
         pcmk__set_result(&(action->result), PCMK_OCF_UNKNOWN_ERROR,
1b1151
-                         PCMK_EXEC_ERROR_FATAL, NULL);
1b1151
+                         PCMK_EXEC_ERROR_FATAL, "Bug in fencing library");
1b1151
         return -EINVAL;
1b1151
     }
1b1151
 
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From ed08f600688af1d25412d2427502ba5d4a55c0d6 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Thu, 7 Oct 2021 12:06:10 -0500
1b1151
Subject: [PATCH 06/12] Fix: fencer: handle dynamic target query failures
1b1151
 better
1b1151
1b1151
Previously, the callbacks for list and status queries checked only the result's
1b1151
exit status. However, the services library will use PCMK_OCF_UNKNOWN_ERROR (1)
1b1151
as the exit status for internal failures, and that value signifies a recognized
1b1151
node (not an error) for fence list actions.
1b1151
1b1151
Now, the callbacks check the execution status as well.
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 46 +++++++++++++++++++++++++++-----
1b1151
 1 file changed, 39 insertions(+), 7 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index f55a32649..7b3fb25a1 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -1144,6 +1144,18 @@ status_search_cb(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
 
1b1151
     mainloop_set_trigger(dev->work);
1b1151
 
1b1151
+    if (result->execution_status != PCMK_EXEC_DONE) {
1b1151
+        crm_warn("Assuming %s cannot fence %s "
1b1151
+                 "because status could not be executed: %s%s%s%s",
1b1151
+                 dev->id, search->host,
1b1151
+                 pcmk_exec_status_str(result->execution_status),
1b1151
+                 ((result->exit_reason == NULL)? "" : " ("),
1b1151
+                 ((result->exit_reason == NULL)? "" : result->exit_reason),
1b1151
+                 ((result->exit_reason == NULL)? "" : ")"));
1b1151
+        search_devices_record_result(search, dev->id, FALSE);
1b1151
+        return;
1b1151
+    }
1b1151
+
1b1151
     switch (result->exit_status) {
1b1151
         case fence_status_unknown:
1b1151
             crm_trace("%s reported it cannot fence %s", dev->id, search->host);
1b1151
@@ -1187,21 +1199,41 @@ dynamic_list_search_cb(int pid, const pcmk__action_result_t *result,
1b1151
 
1b1151
     mainloop_set_trigger(dev->work);
1b1151
 
1b1151
-    if (result->exit_status == CRM_EX_OK) {
1b1151
+    if ((result->execution_status == PCMK_EXEC_DONE)
1b1151
+        && (result->exit_status == CRM_EX_OK)) {
1b1151
         crm_info("Refreshing target list for %s", dev->id);
1b1151
         g_list_free_full(dev->targets, free);
1b1151
         dev->targets = stonith__parse_targets(result->action_stdout);
1b1151
         dev->targets_age = time(NULL);
1b1151
 
1b1151
     } else if (dev->targets != NULL) {
1b1151
-        crm_info("Reusing most recent target list for %s "
1b1151
-                 "because list returned error code %d",
1b1151
-                 dev->id, result->exit_status);
1b1151
+        if (result->execution_status == PCMK_EXEC_DONE) {
1b1151
+            crm_info("Reusing most recent target list for %s "
1b1151
+                     "because list returned error code %d",
1b1151
+                     dev->id, result->exit_status);
1b1151
+        } else {
1b1151
+            crm_info("Reusing most recent target list for %s "
1b1151
+                     "because list could not be executed: %s%s%s%s",
1b1151
+                     dev->id, pcmk_exec_status_str(result->execution_status),
1b1151
+                     ((result->exit_reason == NULL)? "" : " ("),
1b1151
+                     ((result->exit_reason == NULL)? "" : result->exit_reason),
1b1151
+                     ((result->exit_reason == NULL)? "" : ")"));
1b1151
+        }
1b1151
 
1b1151
     } else { // We have never successfully executed list
1b1151
-        crm_warn("Assuming %s cannot fence %s "
1b1151
-                 "because list returned error code %d",
1b1151
-                 dev->id, search->host, result->exit_status);
1b1151
+        if (result->execution_status == PCMK_EXEC_DONE) {
1b1151
+            crm_warn("Assuming %s cannot fence %s "
1b1151
+                     "because list returned error code %d",
1b1151
+                     dev->id, search->host, result->exit_status);
1b1151
+        } else {
1b1151
+            crm_warn("Assuming %s cannot fence %s "
1b1151
+                     "because list could not be executed: %s%s%s%s",
1b1151
+                     dev->id, search->host,
1b1151
+                     pcmk_exec_status_str(result->execution_status),
1b1151
+                     ((result->exit_reason == NULL)? "" : " ("),
1b1151
+                     ((result->exit_reason == NULL)? "" : result->exit_reason),
1b1151
+                     ((result->exit_reason == NULL)? "" : ")"));
1b1151
+        }
1b1151
 
1b1151
         /* Fall back to pcmk_host_check="status" if the user didn't explicitly
1b1151
          * specify "dynamic-list".
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 5a30238a3b8691a5fc20f53906c0efcc50193306 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 21 Sep 2021 15:57:50 -0500
1b1151
Subject: [PATCH 07/12] Refactor: fencer: pass result object when sending an
1b1151
 async reply
1b1151
1b1151
... via stonith_send_async_reply(), instead of sending the mapped legacy code
1b1151
and action stdout separately. Also, drop the "stonith_" prefix since the
1b1151
function is static.
1b1151
1b1151
This moves the mapping from the stonith_send_async_reply() callers to the
1b1151
function itself, so we use the result object and standard codes as long as
1b1151
possible, and map to a legacy code only where needed.
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 62 +++++++++++++++++++-------------
1b1151
 daemons/fenced/fenced_remote.c   |  2 +-
1b1151
 2 files changed, 39 insertions(+), 25 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index 7b3fb25a1..e5f8162ce 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -2376,12 +2376,28 @@ log_async_result(async_command_t *cmd, int rc, int pid, const char *next,
1b1151
     }
1b1151
 }
1b1151
 
1b1151
+/*!
1b1151
+ * \internal
1b1151
+ * \brief Reply to requester after asynchronous command completion
1b1151
+ *
1b1151
+ * \param[in] cmd      Command that completed
1b1151
+ * \param[in] result   Result of command
1b1151
+ * \param[in] pid      Process ID of command, if available
1b1151
+ * \param[in] merged   If true, command was merged with another, not executed
1b1151
+ */
1b1151
 static void
1b1151
-stonith_send_async_reply(async_command_t *cmd, const char *output, int rc,
1b1151
-                         int pid, bool merged)
1b1151
+send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
+                 int pid, bool merged)
1b1151
 {
1b1151
     xmlNode *reply = NULL;
1b1151
     gboolean bcast = FALSE;
1b1151
+    const char *output = NULL;
1b1151
+    int rc = pcmk_ok;
1b1151
+
1b1151
+    CRM_CHECK((cmd != NULL) && (result != NULL), return);
1b1151
+
1b1151
+    output = result->action_stdout;
1b1151
+    rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
 
1b1151
     reply = stonith_construct_async_reply(cmd, output, NULL, rc);
1b1151
 
1b1151
@@ -2513,9 +2529,7 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
         goto done;
1b1151
     }
1b1151
 
1b1151
-    stonith_send_async_reply(cmd, result->action_stdout,
1b1151
-                             pcmk_rc2legacy(stonith__result2rc(result)), pid,
1b1151
-                             false);
1b1151
+    send_async_reply(cmd, result, pid, false);
1b1151
 
1b1151
     if (result->exit_status != CRM_EX_OK) {
1b1151
         goto done;
1b1151
@@ -2563,9 +2577,7 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
 
1b1151
         cmd_list = g_list_remove_link(cmd_list, gIter);
1b1151
 
1b1151
-        stonith_send_async_reply(cmd_other, result->action_stdout,
1b1151
-                                 pcmk_rc2legacy(stonith__result2rc(result)),
1b1151
-                                 pid, true);
1b1151
+        send_async_reply(cmd_other, result, pid, true);
1b1151
         cancel_stonith_command(cmd_other);
1b1151
 
1b1151
         free_async_command(cmd_other);
1b1151
@@ -2604,26 +2616,28 @@ stonith_fence_get_devices_cb(GList * devices, void *user_data)
1b1151
         /* Order based on priority */
1b1151
         devices = g_list_sort(devices, sort_device_priority);
1b1151
         device = g_hash_table_lookup(device_list, devices->data);
1b1151
-
1b1151
-        if (device) {
1b1151
-            cmd->device_list = devices;
1b1151
-            cmd->device_next = devices->next;
1b1151
-            devices = NULL;     /* list owned by cmd now */
1b1151
-        }
1b1151
     }
1b1151
 
1b1151
-    /* we have a device, schedule it for fencing. */
1b1151
-    if (device) {
1b1151
-        schedule_stonith_command(cmd, device);
1b1151
-        /* in progress */
1b1151
-        return;
1b1151
-    }
1b1151
+    if (device == NULL) { // No device found
1b1151
+        pcmk__action_result_t result = {
1b1151
+            // Ensure we don't pass garbage to free()
1b1151
+            .exit_reason = NULL,
1b1151
+            .action_stdout = NULL,
1b1151
+            .action_stderr = NULL
1b1151
+        };
1b1151
 
1b1151
-    /* no device found! */
1b1151
-    stonith_send_async_reply(cmd, NULL, -ENODEV, 0, false);
1b1151
+        pcmk__set_result(&result, CRM_EX_ERROR, PCMK_EXEC_NO_FENCE_DEVICE,
1b1151
+                         "No fence device configured for target");
1b1151
+        send_async_reply(cmd, &result, 0, false);
1b1151
+        pcmk__reset_result(&result);
1b1151
+        free_async_command(cmd);
1b1151
+        g_list_free_full(devices, free);
1b1151
 
1b1151
-    free_async_command(cmd);
1b1151
-    g_list_free_full(devices, free);
1b1151
+    } else { // Device found, schedule it for fencing
1b1151
+        cmd->device_list = devices;
1b1151
+        cmd->device_next = devices->next;
1b1151
+        schedule_stonith_command(cmd, device);
1b1151
+    }
1b1151
 }
1b1151
 
1b1151
 static int
1b1151
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
1b1151
index ffaf60018..b09d2865e 100644
1b1151
--- a/daemons/fenced/fenced_remote.c
1b1151
+++ b/daemons/fenced/fenced_remote.c
1b1151
@@ -996,7 +996,7 @@ stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op)
1b1151
 
1b1151
     remote_op_done(op, msg, pcmk_ok, FALSE);
1b1151
 
1b1151
-    /* Replies are sent via done_cb->stonith_send_async_reply()->do_local_reply() */
1b1151
+    // Replies are sent via done_cb -> send_async_reply() -> do_local_reply()
1b1151
     return -EINPROGRESS;
1b1151
 }
1b1151
 
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From c67b6bfbe0baa1253058417ddfb9bc4cf0844e27 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Thu, 7 Oct 2021 17:25:38 -0500
1b1151
Subject: [PATCH 08/12] Refactor: fencer: pass result object when building
1b1151
 async reply
1b1151
1b1151
... via stonith_construct_async_reply(), instead of passing a mapped legacy rc
1b1151
and action output separately, which will be helpful when we add the exit reason
1b1151
to the reply. Also, drop the "stonith_" prefix since the function is static, and
1b1151
drop an unused argument.
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 33 +++++++++++++++-----------------
1b1151
 1 file changed, 15 insertions(+), 18 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index e5f8162ce..6bc12e6c4 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -112,8 +112,8 @@ typedef struct async_command_s {
1b1151
     stonith_device_t *activating_on;
1b1151
 } async_command_t;
1b1151
 
1b1151
-static xmlNode *stonith_construct_async_reply(async_command_t * cmd, const char *output,
1b1151
-                                              xmlNode * data, int rc);
1b1151
+static xmlNode *construct_async_reply(async_command_t *cmd,
1b1151
+                                      const pcmk__action_result_t *result);
1b1151
 
1b1151
 static gboolean
1b1151
 is_action_required(const char *action, stonith_device_t *device)
1b1151
@@ -2399,7 +2399,7 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
     output = result->action_stdout;
1b1151
     rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
 
1b1151
-    reply = stonith_construct_async_reply(cmd, output, NULL, rc);
1b1151
+    reply = construct_async_reply(cmd, result);
1b1151
 
1b1151
     // Only replies for certain actions are broadcast
1b1151
     if (pcmk__str_any_of(cmd->action, "metadata", "monitor", "list", "status",
1b1151
@@ -2732,17 +2732,20 @@ stonith_construct_reply(xmlNode * request, const char *output, xmlNode * data, i
1b1151
     return reply;
1b1151
 }
1b1151
 
1b1151
+/*!
1b1151
+ * \internal
1b1151
+ * \brief Build an XML reply to an asynchronous fencing command
1b1151
+ *
1b1151
+ * \param[in] cmd     Fencing command that reply is for
1b1151
+ * \param[in] result  Command result
1b1151
+ */
1b1151
 static xmlNode *
1b1151
-stonith_construct_async_reply(async_command_t * cmd, const char *output, xmlNode * data, int rc)
1b1151
+construct_async_reply(async_command_t *cmd, const pcmk__action_result_t *result)
1b1151
 {
1b1151
-    xmlNode *reply = NULL;
1b1151
-
1b1151
-    crm_trace("Creating a basic reply");
1b1151
-    reply = create_xml_node(NULL, T_STONITH_REPLY);
1b1151
+    xmlNode *reply = create_xml_node(NULL, T_STONITH_REPLY);
1b1151
 
1b1151
     crm_xml_add(reply, "st_origin", __func__);
1b1151
     crm_xml_add(reply, F_TYPE, T_STONITH_NG);
1b1151
-
1b1151
     crm_xml_add(reply, F_STONITH_OPERATION, cmd->op);
1b1151
     crm_xml_add(reply, F_STONITH_DEVICE, cmd->device);
1b1151
     crm_xml_add(reply, F_STONITH_REMOTE_OP_ID, cmd->remote_op_id);
1b1151
@@ -2753,15 +2756,9 @@ stonith_construct_async_reply(async_command_t * cmd, const char *output, xmlNode
1b1151
     crm_xml_add(reply, F_STONITH_ORIGIN, cmd->origin);
1b1151
     crm_xml_add_int(reply, F_STONITH_CALLID, cmd->id);
1b1151
     crm_xml_add_int(reply, F_STONITH_CALLOPTS, cmd->options);
1b1151
-
1b1151
-    crm_xml_add_int(reply, F_STONITH_RC, rc);
1b1151
-
1b1151
-    crm_xml_add(reply, "st_output", output);
1b1151
-
1b1151
-    if (data != NULL) {
1b1151
-        crm_info("Attaching reply output");
1b1151
-        add_message_xml(reply, F_STONITH_CALLDATA, data);
1b1151
-    }
1b1151
+    crm_xml_add_int(reply, F_STONITH_RC,
1b1151
+                    pcmk_rc2legacy(stonith__result2rc(result)));
1b1151
+    crm_xml_add(reply, "st_output", result->action_stdout);
1b1151
     return reply;
1b1151
 }
1b1151
 
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 2686caeb3b74f687ddd86a4e483250ca8096ba7c Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Tue, 19 Oct 2021 18:27:31 -0500
1b1151
Subject: [PATCH 09/12] Log: fencer: improve messages for asynchronous results
1b1151
1b1151
Now that we have the full result object, pass it to log_async_result().
1b1151
Instead of logging a mapped legacy rc, log the execution status or exit status
1b1151
as appropriate, along with the exit reason.
1b1151
---
1b1151
 daemons/fenced/fenced_commands.c | 43 +++++++++++++++++---------------
1b1151
 1 file changed, 23 insertions(+), 20 deletions(-)
1b1151
1b1151
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
1b1151
index 6bc12e6c4..9d06c68dc 100644
1b1151
--- a/daemons/fenced/fenced_commands.c
1b1151
+++ b/daemons/fenced/fenced_commands.c
1b1151
@@ -2305,15 +2305,14 @@ stonith_query(xmlNode * msg, const char *remote_peer, const char *client_id, int
1b1151
  * \brief Log the result of an asynchronous command
1b1151
  *
1b1151
  * \param[in] cmd        Command the result is for
1b1151
- * \param[in] rc         Legacy return code corresponding to result
1b1151
+ * \param[in] result     Result of command
1b1151
  * \param[in] pid        Process ID of command, if available
1b1151
  * \param[in] next       Alternate device that will be tried if command failed
1b1151
- * \param[in] output     Command output, if any
1b1151
  * \param[in] op_merged  Whether this command was merged with an earlier one
1b1151
  */
1b1151
 static void
1b1151
-log_async_result(async_command_t *cmd, int rc, int pid, const char *next,
1b1151
-                 const char *output, gboolean op_merged)
1b1151
+log_async_result(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
+                 int pid, const char *next, bool op_merged)
1b1151
 {
1b1151
     int log_level = LOG_ERR;
1b1151
     int output_log_level = LOG_NEVER;
1b1151
@@ -2321,17 +2320,18 @@ log_async_result(async_command_t *cmd, int rc, int pid, const char *next,
1b1151
 
1b1151
     GString *msg = g_string_sized_new(80); // Reasonable starting size
1b1151
 
1b1151
-    // Choose log levels appropriately
1b1151
-    if (rc == 0) { // Success
1b1151
+    // Choose log levels appropriately if we have a result
1b1151
+    if ((result->execution_status == PCMK_EXEC_DONE)
1b1151
+        && (result->exit_status == CRM_EX_OK))  { // Success
1b1151
         log_level = (cmd->victim == NULL)? LOG_DEBUG : LOG_NOTICE;
1b1151
-        if ((output != NULL)
1b1151
+        if ((result->action_stdout != NULL)
1b1151
             && !pcmk__str_eq(cmd->action, "metadata", pcmk__str_casei)) {
1b1151
             output_log_level = LOG_DEBUG;
1b1151
         }
1b1151
         next = NULL;
1b1151
     } else { // Failure
1b1151
         log_level = (cmd->victim == NULL)? LOG_NOTICE : LOG_ERR;
1b1151
-        if ((output != NULL)
1b1151
+        if ((result->action_stdout != NULL)
1b1151
             && !pcmk__str_eq(cmd->action, "metadata", pcmk__str_casei)) {
1b1151
             output_log_level = LOG_WARNING;
1b1151
         }
1b1151
@@ -2347,10 +2347,18 @@ log_async_result(async_command_t *cmd, int rc, int pid, const char *next,
1b1151
     }
1b1151
     g_string_append_printf(msg, "using %s ", cmd->device);
1b1151
 
1b1151
-    // Add result
1b1151
-    g_string_append_printf(msg, "returned %d (%s)", rc, pcmk_strerror(rc));
1b1151
+    // Add exit status or execution status as appropriate
1b1151
+    if (result->execution_status == PCMK_EXEC_DONE) {
1b1151
+        g_string_append_printf(msg, "returned %d", result->exit_status);
1b1151
+    } else {
1b1151
+        g_string_append_printf(msg, "could not be executed: %s",
1b1151
+                               pcmk_exec_status_str(result->execution_status));
1b1151
+    }
1b1151
 
1b1151
-    // Add next device if appropriate
1b1151
+    // Add exit reason and next device if appropriate
1b1151
+    if (result->exit_reason != NULL) {
1b1151
+        g_string_append_printf(msg, " (%s)", result->exit_reason);
1b1151
+    }
1b1151
     if (next != NULL) {
1b1151
         g_string_append_printf(msg, ", retrying with %s", next);
1b1151
     }
1b1151
@@ -2371,7 +2379,7 @@ log_async_result(async_command_t *cmd, int rc, int pid, const char *next,
1b1151
     if (output_log_level != LOG_NEVER) {
1b1151
         char *prefix = crm_strdup_printf("%s[%d]", cmd->device, pid);
1b1151
 
1b1151
-        crm_log_output(output_log_level, prefix, output);
1b1151
+        crm_log_output(output_log_level, prefix, result->action_stdout);
1b1151
         free(prefix);
1b1151
     }
1b1151
 }
1b1151
@@ -2391,14 +2399,9 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
 {
1b1151
     xmlNode *reply = NULL;
1b1151
     gboolean bcast = FALSE;
1b1151
-    const char *output = NULL;
1b1151
-    int rc = pcmk_ok;
1b1151
 
1b1151
     CRM_CHECK((cmd != NULL) && (result != NULL), return);
1b1151
 
1b1151
-    output = result->action_stdout;
1b1151
-    rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
-
1b1151
     reply = construct_async_reply(cmd, result);
1b1151
 
1b1151
     // Only replies for certain actions are broadcast
1b1151
@@ -2412,7 +2415,7 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
         bcast = TRUE;
1b1151
     }
1b1151
 
1b1151
-    log_async_result(cmd, rc, pid, NULL, output, merged);
1b1151
+    log_async_result(cmd, result, pid, NULL, merged);
1b1151
     crm_log_xml_trace(reply, "Reply");
1b1151
 
1b1151
     if (merged) {
1b1151
@@ -2436,6 +2439,7 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
1b1151
     if (stand_alone) {
1b1151
         /* Do notification with a clean data object */
1b1151
         xmlNode *notify_data = create_xml_node(NULL, T_STONITH_NOTIFY_FENCE);
1b1151
+        int rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
 
1b1151
         crm_xml_add_int(notify_data, F_STONITH_RC, rc);
1b1151
         crm_xml_add(notify_data, F_STONITH_TARGET, cmd->victim);
1b1151
@@ -2521,8 +2525,7 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
1b1151
 
1b1151
     /* this operation requires more fencing, hooray! */
1b1151
     if (next_device) {
1b1151
-        log_async_result(cmd, pcmk_rc2legacy(stonith__result2rc(result)), pid,
1b1151
-                         next_device->id, result->action_stdout, FALSE);
1b1151
+        log_async_result(cmd, result, pid, next_device->id, false);
1b1151
         schedule_stonith_command(cmd, next_device);
1b1151
         /* Prevent cmd from being freed */
1b1151
         cmd = NULL;
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 9f9dea518da50f629589d505ea0f330a47111d76 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Thu, 28 Oct 2021 13:29:31 -0500
1b1151
Subject: [PATCH 10/12] Test: cts-fencing: update expected log messages
1b1151
1b1151
... which now log the original exit status rather than a mapped legacy rc
1b1151
---
1b1151
 cts/cts-fencing.in | 28 ++++++++++++++--------------
1b1151
 1 file changed, 14 insertions(+), 14 deletions(-)
1b1151
1b1151
diff --git a/cts/cts-fencing.in b/cts/cts-fencing.in
1b1151
index babfb6351..5cd9f7b8f 100644
1b1151
--- a/cts/cts-fencing.in
1b1151
+++ b/cts/cts-fencing.in
1b1151
@@ -886,7 +886,7 @@ class Tests(object):
1b1151
             test.add_cmd("stonith_admin", "--output-as=xml -F node3 -t 20")
1b1151
 
1b1151
             test.add_stonith_log_pattern("Total timeout set to 40")
1b1151
-            test.add_stonith_log_pattern("targeting node3 using false returned -201")
1b1151
+            test.add_stonith_log_pattern("targeting node3 using false returned 1")
1b1151
             test.add_stonith_log_pattern("targeting node3 using true returned 0")
1b1151
 
1b1151
         # test what happens when the first fencing level fails.
1b1151
@@ -920,8 +920,8 @@ class Tests(object):
1b1151
             test.add_cmd("stonith_admin", "--output-as=xml -F node3 -t 3")
1b1151
 
1b1151
             test.add_stonith_log_pattern("Total timeout set to 18")
1b1151
-            test.add_stonith_log_pattern("targeting node3 using false1 returned -201")
1b1151
-            test.add_stonith_log_pattern("targeting node3 using false2 returned -201")
1b1151
+            test.add_stonith_log_pattern("targeting node3 using false1 returned 1")
1b1151
+            test.add_stonith_log_pattern("targeting node3 using false2 returned 1")
1b1151
             test.add_stonith_log_pattern("targeting node3 using true3 returned 0")
1b1151
             test.add_stonith_log_pattern("targeting node3 using true4 returned 0")
1b1151
 
1b1151
@@ -987,7 +987,7 @@ class Tests(object):
1b1151
             test.add_cmd("stonith_admin", "--output-as=xml -F node3 -t 20")
1b1151
 
1b1151
             test.add_stonith_log_pattern("Total timeout set to 8")
1b1151
-            test.add_stonith_log_pattern("targeting node3 using false1 returned -201")
1b1151
+            test.add_stonith_log_pattern("targeting node3 using false1 returned 1")
1b1151
             test.add_stonith_neg_log_pattern("targeting node3 using false2 returned ")
1b1151
             test.add_stonith_log_pattern("targeting node3 using true3 returned 0")
1b1151
             test.add_stonith_log_pattern("targeting node3 using true4 returned 0")
1b1151
@@ -1147,7 +1147,7 @@ class Tests(object):
1b1151
                          "--output-as=xml -R true1 -a fence_dummy_no_reboot -o \"mode=pass\" -o \"pcmk_host_list=node1 node2 node3\"")
1b1151
             test.add_cmd("stonith_admin", "--output-as=xml -B node1 -t 5 -V")
1b1151
             test.add_stonith_log_pattern("does not support reboot")
1b1151
-            test.add_stonith_log_pattern("using true1 returned 0 (OK)")
1b1151
+            test.add_stonith_log_pattern("using true1 returned 0")
1b1151
 
1b1151
         # make sure reboot is used when reboot action is advertised
1b1151
         for test_type in test_types:
1b1151
@@ -1158,7 +1158,7 @@ class Tests(object):
1b1151
                          "--output-as=xml -R true1 -a fence_dummy -o \"mode=pass\" -o \"pcmk_host_list=node1 node2 node3\"")
1b1151
             test.add_cmd("stonith_admin", "--output-as=xml -B node1 -t 5 -V")
1b1151
             test.add_stonith_neg_log_pattern("does not advertise support for 'reboot', performing 'off'")
1b1151
-            test.add_stonith_log_pattern("using true1 returned 0 (OK)")
1b1151
+            test.add_stonith_log_pattern("using true1 returned 0")
1b1151
 
1b1151
         # make sure requested fencing delay is applied only for the first device in the first level
1b1151
         # make sure static delay from pcmk_delay_base is added
1b1151
@@ -1240,8 +1240,8 @@ class Tests(object):
1b1151
                      '--output-as=xml -R true2 -a fence_dummy_auto_unfence -o "mode=pass" -o "pcmk_host_list=%s"' % (our_uname))
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -U %s -t 3" % (our_uname))
1b1151
         # both devices should be executed
1b1151
-        test.add_stonith_log_pattern("using true1 returned 0 (OK)")
1b1151
-        test.add_stonith_log_pattern("using true2 returned 0 (OK)")
1b1151
+        test.add_stonith_log_pattern("using true1 returned 0")
1b1151
+        test.add_stonith_log_pattern("using true2 returned 0")
1b1151
 
1b1151
         ### verify unfencing using automatic unfencing fails if any of the required agents fail
1b1151
         test = self.new_test("cpg_unfence_required_2",
1b1151
@@ -1264,8 +1264,8 @@ class Tests(object):
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -r %s -i 1 -v true1" % (our_uname))
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -r %s -i 2 -v true2" % (our_uname))
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -U %s -t 3" % (our_uname))
1b1151
-        test.add_stonith_log_pattern("using true1 returned 0 (OK)")
1b1151
-        test.add_stonith_log_pattern("using true2 returned 0 (OK)")
1b1151
+        test.add_stonith_log_pattern("using true1 returned 0")
1b1151
+        test.add_stonith_log_pattern("using true2 returned 0")
1b1151
 
1b1151
         ### verify unfencing using automatic devices with topology
1b1151
         test = self.new_test("cpg_unfence_required_4",
1b1151
@@ -1296,10 +1296,10 @@ class Tests(object):
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -r %s -i 3 -v false4" % (our_uname))
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -r %s -i 4 -v true4" % (our_uname))
1b1151
         test.add_cmd("stonith_admin", "--output-as=xml -U %s -t 3" % (our_uname))
1b1151
-        test.add_stonith_log_pattern("using true1 returned 0 (OK)")
1b1151
-        test.add_stonith_log_pattern("using true2 returned 0 (OK)")
1b1151
-        test.add_stonith_log_pattern("using true3 returned 0 (OK)")
1b1151
-        test.add_stonith_log_pattern("using true4 returned 0 (OK)")
1b1151
+        test.add_stonith_log_pattern("using true1 returned 0")
1b1151
+        test.add_stonith_log_pattern("using true2 returned 0")
1b1151
+        test.add_stonith_log_pattern("using true3 returned 0")
1b1151
+        test.add_stonith_log_pattern("using true4 returned 0")
1b1151
 
1b1151
     def build_unfence_on_target_tests(self):
1b1151
         """ Register tests that verify unfencing that runs on the target """
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From be72166ed9ccb53c218529783660503df95da719 Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Thu, 16 Sep 2021 16:50:23 -0500
1b1151
Subject: [PATCH 11/12] Log: libcrmservice: downgrade failed action messages
1b1151
1b1151
Previously, we would often get duplicate log messages for failed actions,
1b1151
from the service library and again from its callers.
1b1151
1b1151
Now that the service library tracks and provides exit reasons, callers can log
1b1151
sufficient detail with better context, so downgrade the library's messages to
1b1151
info level or lower. Similarly, avoid duplicate logs of process output.
1b1151
1b1151
Certain messages (such as out-of-memory) remain at higher severity.
1b1151
---
1b1151
 daemons/controld/controld_execd.c | 15 +++---
1b1151
 lib/fencing/st_client.c           | 11 ++---
1b1151
 lib/services/services.c           | 14 +++---
1b1151
 lib/services/services_linux.c     | 80 ++++++++++++++++---------------
1b1151
 lib/services/systemd.c            | 20 ++++----
1b1151
 lib/services/upstart.c            | 19 ++++----
1b1151
 6 files changed, 80 insertions(+), 79 deletions(-)
1b1151
1b1151
diff --git a/daemons/controld/controld_execd.c b/daemons/controld/controld_execd.c
1b1151
index bded6e6b6..3ddff6e13 100644
1b1151
--- a/daemons/controld/controld_execd.c
1b1151
+++ b/daemons/controld/controld_execd.c
1b1151
@@ -2684,16 +2684,15 @@ log_executor_event(lrmd_event_data_t *op, const char *op_key,
1b1151
     do_crm_log(log_level, "%s", str->str);
1b1151
     g_string_free(str, TRUE);
1b1151
 
1b1151
-    if (op->output != NULL) {
1b1151
-        char *prefix = crm_strdup_printf("%s-" PCMK__OP_FMT ":%d", node_name,
1b1151
+    /* The services library has already logged the output at info or debug
1b1151
+     * level, so just raise to notice if it looks like a failure.
1b1151
+     */
1b1151
+    if ((op->output != NULL) && (op->rc != PCMK_OCF_OK)) {
1b1151
+        char *prefix = crm_strdup_printf(PCMK__OP_FMT "@%s output",
1b1151
                                          op->rsc_id, op->op_type,
1b1151
-                                         op->interval_ms, op->call_id);
1b1151
+                                         op->interval_ms, node_name);
1b1151
 
1b1151
-        if (op->rc) {
1b1151
-            crm_log_output(LOG_NOTICE, prefix, op->output);
1b1151
-        } else {
1b1151
-            crm_log_output(LOG_DEBUG, prefix, op->output);
1b1151
-        }
1b1151
+        crm_log_output(LOG_NOTICE, prefix, op->output);
1b1151
         free(prefix);
1b1151
     }
1b1151
 }
1b1151
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
1b1151
index 3d4127eff..2fbff7f24 100644
1b1151
--- a/lib/fencing/st_client.c
1b1151
+++ b/lib/fencing/st_client.c
1b1151
@@ -276,14 +276,9 @@ stonith__watchdog_fencing_enabled_for_node(const char *node)
1b1151
 static void
1b1151
 log_action(stonith_action_t *action, pid_t pid)
1b1151
 {
1b1151
-    if (action->result.action_stdout != NULL) {
1b1151
-        /* Logging the whole string confuses syslog when the string is xml */
1b1151
-        char *prefix = crm_strdup_printf("%s[%d] stdout:", action->agent, pid);
1b1151
-
1b1151
-        crm_log_output(LOG_TRACE, prefix, action->result.action_stdout);
1b1151
-        free(prefix);
1b1151
-    }
1b1151
-
1b1151
+    /* The services library has already logged the output at info or debug
1b1151
+     * level, so just raise to warning for stderr.
1b1151
+     */
1b1151
     if (action->result.action_stderr != NULL) {
1b1151
         /* Logging the whole string confuses syslog when the string is xml */
1b1151
         char *prefix = crm_strdup_printf("%s[%d] stderr:", action->agent, pid);
1b1151
diff --git a/lib/services/services.c b/lib/services/services.c
1b1151
index 86a0a213c..cf8bbc70e 100644
1b1151
--- a/lib/services/services.c
1b1151
+++ b/lib/services/services.c
1b1151
@@ -319,13 +319,13 @@ services__create_resource_action(const char *name, const char *standard,
1b1151
         rc = services__nagios_prepare(op);
1b1151
 #endif
1b1151
     } else {
1b1151
-        crm_err("Unknown resource standard: %s", op->standard);
1b1151
+        crm_info("Unknown resource standard: %s", op->standard);
1b1151
         rc = ENOENT;
1b1151
     }
1b1151
 
1b1151
     if (rc != pcmk_rc_ok) {
1b1151
-        crm_err("Cannot prepare %s operation for %s: %s",
1b1151
-                action, name, strerror(rc));
1b1151
+        crm_info("Cannot prepare %s operation for %s: %s",
1b1151
+                 action, name, strerror(rc));
1b1151
         services__handle_exec_error(op, rc);
1b1151
     }
1b1151
     return op;
1b1151
@@ -967,14 +967,14 @@ execute_metadata_action(svc_action_t *op)
1b1151
     const char *class = op->standard;
1b1151
 
1b1151
     if (op->agent == NULL) {
1b1151
-        crm_err("meta-data requested without specifying agent");
1b1151
+        crm_info("Meta-data requested without specifying agent");
1b1151
         services__set_result(op, services__generic_error(op),
1b1151
                              PCMK_EXEC_ERROR_FATAL, "Agent not specified");
1b1151
         return EINVAL;
1b1151
     }
1b1151
 
1b1151
     if (class == NULL) {
1b1151
-        crm_err("meta-data requested for agent %s without specifying class",
1b1151
+        crm_info("Meta-data requested for agent %s without specifying class",
1b1151
                 op->agent);
1b1151
         services__set_result(op, services__generic_error(op),
1b1151
                              PCMK_EXEC_ERROR_FATAL,
1b1151
@@ -986,8 +986,8 @@ execute_metadata_action(svc_action_t *op)
1b1151
         class = resources_find_service_class(op->agent);
1b1151
     }
1b1151
     if (class == NULL) {
1b1151
-        crm_err("meta-data requested for %s, but could not determine class",
1b1151
-                op->agent);
1b1151
+        crm_info("Meta-data requested for %s, but could not determine class",
1b1151
+                 op->agent);
1b1151
         services__set_result(op, services__generic_error(op),
1b1151
                              PCMK_EXEC_ERROR_HARD,
1b1151
                              "Agent standard could not be determined");
1b1151
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
1b1151
index b2ff27a0d..9a4c6cf80 100644
1b1151
--- a/lib/services/services_linux.c
1b1151
+++ b/lib/services/services_linux.c
1b1151
@@ -64,8 +64,8 @@ sigchld_setup(struct sigchld_data_s *data)
1b1151
 
1b1151
     // Block SIGCHLD (saving previous set of blocked signals to restore later)
1b1151
     if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=sigprocmask", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=sigprocmask", pcmk_strerror(errno));
1b1151
         return false;
1b1151
     }
1b1151
     return true;
1b1151
@@ -81,8 +81,8 @@ sigchld_open(struct sigchld_data_s *data)
1b1151
 
1b1151
     fd = signalfd(-1, &(data->mask), SFD_NONBLOCK);
1b1151
     if (fd < 0) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=signalfd", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=signalfd", pcmk_strerror(errno));
1b1151
     }
1b1151
     return fd;
1b1151
 }
1b1151
@@ -108,8 +108,8 @@ sigchld_received(int fd)
1b1151
     }
1b1151
     s = read(fd, &fdsi, sizeof(struct signalfd_siginfo));
1b1151
     if (s != sizeof(struct signalfd_siginfo)) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=read", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=read", pcmk_strerror(errno));
1b1151
 
1b1151
     } else if (fdsi.ssi_signo == SIGCHLD) {
1b1151
         return true;
1b1151
@@ -149,8 +149,8 @@ sigchld_handler()
1b1151
     if ((last_sigchld_data != NULL)
1b1151
         && (last_sigchld_data->pipe_fd[1] >= 0)
1b1151
         && (write(last_sigchld_data->pipe_fd[1], "", 1) == -1)) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=write", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=write", pcmk_strerror(errno));
1b1151
     }
1b1151
 }
1b1151
 
1b1151
@@ -162,19 +162,19 @@ sigchld_setup(struct sigchld_data_s *data)
1b1151
     data->pipe_fd[0] = data->pipe_fd[1] = -1;
1b1151
 
1b1151
     if (pipe(data->pipe_fd) == -1) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=pipe", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=pipe", pcmk_strerror(errno));
1b1151
         return false;
1b1151
     }
1b1151
 
1b1151
     rc = pcmk__set_nonblocking(data->pipe_fd[0]);
1b1151
     if (rc != pcmk_rc_ok) {
1b1151
-        crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
1b1151
+        crm_info("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
1b1151
                  pcmk_rc_str(rc), rc);
1b1151
     }
1b1151
     rc = pcmk__set_nonblocking(data->pipe_fd[1]);
1b1151
     if (rc != pcmk_rc_ok) {
1b1151
-        crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
1b1151
+        crm_info("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
1b1151
                  pcmk_rc_str(rc), rc);
1b1151
     }
1b1151
 
1b1151
@@ -183,8 +183,8 @@ sigchld_setup(struct sigchld_data_s *data)
1b1151
     data->sa.sa_flags = 0;
1b1151
     sigemptyset(&(data->sa.sa_mask));
1b1151
     if (sigaction(SIGCHLD, &(data->sa), &(data->old_sa)) < 0) {
1b1151
-        crm_err("Wait for child process completion failed: %s "
1b1151
-                CRM_XS " source=sigaction", pcmk_strerror(errno));
1b1151
+        crm_info("Wait for child process completion failed: %s "
1b1151
+                 CRM_XS " source=sigaction", pcmk_strerror(errno));
1b1151
     }
1b1151
 
1b1151
     // Remember data for use in signal handler
1b1151
@@ -585,7 +585,11 @@ log_op_output(svc_action_t *op)
1b1151
 {
1b1151
     char *prefix = crm_strdup_printf("%s[%d] error output", op->id, op->pid);
1b1151
 
1b1151
-    crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
1b1151
+    /* The library caller has better context to know how important the output
1b1151
+     * is, so log it at info and debug severity here. They can log it again at
1b1151
+     * higher severity if appropriate.
1b1151
+     */
1b1151
+    crm_log_output(LOG_INFO, prefix, op->stderr_data);
1b1151
     strcpy(prefix + strlen(prefix) - strlen("error output"), "output");
1b1151
     crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
1b1151
     free(prefix);
1b1151
@@ -673,7 +677,7 @@ async_action_complete(mainloop_child_t *p, pid_t pid, int core, int signo,
1b1151
         parse_exit_reason_from_stderr(op);
1b1151
 
1b1151
     } else if (mainloop_child_timeout(p)) {
1b1151
-        crm_warn("%s[%d] timed out after %dms", op->id, op->pid, op->timeout);
1b1151
+        crm_info("%s[%d] timed out after %dms", op->id, op->pid, op->timeout);
1b1151
         services__set_result(op, services__generic_error(op), PCMK_EXEC_TIMEOUT,
1b1151
                              "Process did not exit within specified timeout");
1b1151
 
1b1151
@@ -686,7 +690,7 @@ async_action_complete(mainloop_child_t *p, pid_t pid, int core, int signo,
1b1151
         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_CANCELLED, NULL);
1b1151
 
1b1151
     } else {
1b1151
-        crm_warn("%s[%d] terminated with signal %d (%s)",
1b1151
+        crm_info("%s[%d] terminated with signal %d (%s)",
1b1151
                  op->id, op->pid, signo, strsignal(signo));
1b1151
         services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1b1151
                              "Process interrupted by signal");
1b1151
@@ -908,12 +912,12 @@ action_launch_child(svc_action_t *op)
1b1151
         sp.sched_priority = 0;
1b1151
 
1b1151
         if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
1b1151
-            crm_warn("Could not reset scheduling policy for %s", op->id);
1b1151
+            crm_info("Could not reset scheduling policy for %s", op->id);
1b1151
         }
1b1151
     }
1b1151
 #endif
1b1151
     if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1b1151
-        crm_warn("Could not reset process priority for %s", op->id);
1b1151
+        crm_info("Could not reset process priority for %s", op->id);
1b1151
     }
1b1151
 
1b1151
     /* Man: The call setpgrp() is equivalent to setpgid(0,0)
1b1151
@@ -941,7 +945,7 @@ action_launch_child(svc_action_t *op)
1b1151
         } else {
1b1151
             crm_err("Considering %s unconfigured "
1b1151
                     "because unable to load CIB secrets: %s",
1b1151
-                     op->rsc, pcmk_rc_str(rc));
1b1151
+                    op->rsc, pcmk_rc_str(rc));
1b1151
             exit_child(op, services__configuration_error(op, false),
1b1151
                        "Unable to load CIB secrets");
1b1151
         }
1b1151
@@ -1043,7 +1047,7 @@ wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data)
1b1151
 
1b1151
                 } else if (wait_rc < 0) {
1b1151
                     wait_reason = pcmk_rc_str(errno);
1b1151
-                    crm_warn("Wait for completion of %s[%d] failed: %s "
1b1151
+                    crm_info("Wait for completion of %s[%d] failed: %s "
1b1151
                              CRM_XS " source=waitpid",
1b1151
                              op->id, op->pid, wait_reason);
1b1151
                     wait_rc = 0; // Act as if process is still running
1b1151
@@ -1057,8 +1061,8 @@ wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data)
1b1151
 
1b1151
         } else if ((poll_rc < 0) && (errno != EINTR)) {
1b1151
             wait_reason = pcmk_rc_str(errno);
1b1151
-            crm_err("Wait for completion of %s[%d] failed: %s "
1b1151
-                    CRM_XS " source=poll", op->id, op->pid, wait_reason);
1b1151
+            crm_info("Wait for completion of %s[%d] failed: %s "
1b1151
+                     CRM_XS " source=poll", op->id, op->pid, wait_reason);
1b1151
             break;
1b1151
         }
1b1151
 
1b1151
@@ -1078,7 +1082,7 @@ wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data)
1b1151
             services__set_result(op, services__generic_error(op),
1b1151
                                  PCMK_EXEC_TIMEOUT,
1b1151
                                  "Process did not exit within specified timeout");
1b1151
-            crm_warn("%s[%d] timed out after %dms",
1b1151
+            crm_info("%s[%d] timed out after %dms",
1b1151
                      op->id, op->pid, op->timeout);
1b1151
 
1b1151
         } else {
1b1151
@@ -1110,8 +1114,8 @@ wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data)
1b1151
 
1b1151
         services__set_result(op, services__generic_error(op), PCMK_EXEC_ERROR,
1b1151
                              "Process interrupted by signal");
1b1151
-        crm_err("%s[%d] terminated with signal %d (%s)",
1b1151
-                op->id, op->pid, signo, strsignal(signo));
1b1151
+        crm_info("%s[%d] terminated with signal %d (%s)",
1b1151
+                 op->id, op->pid, signo, strsignal(signo));
1b1151
 
1b1151
 #ifdef WCOREDUMP
1b1151
         if (WCOREDUMP(status)) {
1b1151
@@ -1155,7 +1159,7 @@ services__execute_file(svc_action_t *op)
1b1151
     // Catch common failure conditions early
1b1151
     if (stat(op->opaque->exec, &st) != 0) {
1b1151
         rc = errno;
1b1151
-        crm_warn("Cannot execute '%s': %s " CRM_XS " stat rc=%d",
1b1151
+        crm_info("Cannot execute '%s': %s " CRM_XS " stat rc=%d",
1b1151
                  op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
         services__handle_exec_error(op, rc);
1b1151
         goto done;
1b1151
@@ -1163,8 +1167,8 @@ services__execute_file(svc_action_t *op)
1b1151
 
1b1151
     if (pipe(stdout_fd) < 0) {
1b1151
         rc = errno;
1b1151
-        crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
1b1151
-                op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
+        crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
1b1151
+                 op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
         services__handle_exec_error(op, rc);
1b1151
         goto done;
1b1151
     }
1b1151
@@ -1174,8 +1178,8 @@ services__execute_file(svc_action_t *op)
1b1151
 
1b1151
         close_pipe(stdout_fd);
1b1151
 
1b1151
-        crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
1b1151
-                op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
+        crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
1b1151
+                 op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
         services__handle_exec_error(op, rc);
1b1151
         goto done;
1b1151
     }
1b1151
@@ -1187,8 +1191,8 @@ services__execute_file(svc_action_t *op)
1b1151
             close_pipe(stdout_fd);
1b1151
             close_pipe(stderr_fd);
1b1151
 
1b1151
-            crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
1b1151
-                    op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
+            crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
1b1151
+                     op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
             services__handle_exec_error(op, rc);
1b1151
             goto done;
1b1151
         }
1b1151
@@ -1212,8 +1216,8 @@ services__execute_file(svc_action_t *op)
1b1151
             close_pipe(stdout_fd);
1b1151
             close_pipe(stderr_fd);
1b1151
 
1b1151
-            crm_err("Cannot execute '%s': %s " CRM_XS " fork rc=%d",
1b1151
-                    op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
+            crm_info("Cannot execute '%s': %s " CRM_XS " fork rc=%d",
1b1151
+                     op->opaque->exec, pcmk_strerror(rc), rc);
1b1151
             services__handle_exec_error(op, rc);
1b1151
             if (op->synchronous) {
1b1151
                 sigchld_cleanup(&data);
1b1151
@@ -1271,7 +1275,7 @@ services__execute_file(svc_action_t *op)
1b1151
     op->opaque->stdout_fd = stdout_fd[0];
1b1151
     rc = pcmk__set_nonblocking(op->opaque->stdout_fd);
1b1151
     if (rc != pcmk_rc_ok) {
1b1151
-        crm_warn("Could not set '%s' output non-blocking: %s "
1b1151
+        crm_info("Could not set '%s' output non-blocking: %s "
1b1151
                  CRM_XS " rc=%d",
1b1151
                  op->opaque->exec, pcmk_rc_str(rc), rc);
1b1151
     }
1b1151
@@ -1279,7 +1283,7 @@ services__execute_file(svc_action_t *op)
1b1151
     op->opaque->stderr_fd = stderr_fd[0];
1b1151
     rc = pcmk__set_nonblocking(op->opaque->stderr_fd);
1b1151
     if (rc != pcmk_rc_ok) {
1b1151
-        crm_warn("Could not set '%s' error output non-blocking: %s "
1b1151
+        crm_info("Could not set '%s' error output non-blocking: %s "
1b1151
                  CRM_XS " rc=%d",
1b1151
                  op->opaque->exec, pcmk_rc_str(rc), rc);
1b1151
     }
1b1151
@@ -1290,7 +1294,7 @@ services__execute_file(svc_action_t *op)
1b1151
         // as long as no other standard uses stdin_fd assume stonith
1b1151
         rc = pcmk__set_nonblocking(op->opaque->stdin_fd);
1b1151
         if (rc != pcmk_rc_ok) {
1b1151
-            crm_warn("Could not set '%s' input non-blocking: %s "
1b1151
+            crm_info("Could not set '%s' input non-blocking: %s "
1b1151
                     CRM_XS " fd=%d,rc=%d", op->opaque->exec,
1b1151
                     pcmk_rc_str(rc), op->opaque->stdin_fd, rc);
1b1151
         }
1b1151
diff --git a/lib/services/systemd.c b/lib/services/systemd.c
1b1151
index 6f5bef960..8e9fff484 100644
1b1151
--- a/lib/services/systemd.c
1b1151
+++ b/lib/services/systemd.c
1b1151
@@ -232,7 +232,8 @@ systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
1b1151
     }
1b1151
 
1b1151
     if (pcmk_dbus_find_error(pending, reply, &error)) {
1b1151
-        crm_err("Could not issue systemd reload %d: %s", reload_count, error.message);
1b1151
+        crm_warn("Could not issue systemd reload %d: %s",
1b1151
+                 reload_count, error.message);
1b1151
         dbus_error_free(&error);
1b1151
 
1b1151
     } else {
1b1151
@@ -291,8 +292,8 @@ set_result_from_method_error(svc_action_t *op, const DBusError *error)
1b1151
                              PCMK_EXEC_NOT_INSTALLED, "systemd unit not found");
1b1151
     }
1b1151
 
1b1151
-    crm_err("DBus request for %s of systemd unit %s for resource %s failed: %s",
1b1151
-            op->action, op->agent, crm_str(op->rsc), error->message);
1b1151
+    crm_info("DBus request for %s of systemd unit %s for resource %s failed: %s",
1b1151
+             op->action, op->agent, crm_str(op->rsc), error->message);
1b1151
 }
1b1151
 
1b1151
 /*!
1b1151
@@ -325,11 +326,11 @@ execute_after_loadunit(DBusMessage *reply, svc_action_t *op)
1b1151
         if (op != NULL) {
1b1151
             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1b1151
                                  "systemd DBus method had unexpected reply");
1b1151
-            crm_err("Could not load systemd unit %s for %s: "
1b1151
-                    "DBus reply has unexpected type", op->agent, op->id);
1b1151
+            crm_info("Could not load systemd unit %s for %s: "
1b1151
+                     "DBus reply has unexpected type", op->agent, op->id);
1b1151
         } else {
1b1151
-            crm_err("Could not load systemd unit: "
1b1151
-                    "DBus reply has unexpected type");
1b1151
+            crm_info("Could not load systemd unit: "
1b1151
+                     "DBus reply has unexpected type");
1b1151
         }
1b1151
 
1b1151
     } else {
1b1151
@@ -688,7 +689,7 @@ process_unit_method_reply(DBusMessage *reply, svc_action_t *op)
1b1151
 
1b1151
     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
1b1151
                                      __func__, __LINE__)) {
1b1151
-        crm_warn("DBus request for %s of %s succeeded but "
1b1151
+        crm_info("DBus request for %s of %s succeeded but "
1b1151
                  "return type was unexpected", op->action, crm_str(op->rsc));
1b1151
         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE,
1b1151
                              "systemd DBus method had unexpected reply");
1b1151
@@ -981,7 +982,8 @@ systemd_timeout_callback(gpointer p)
1b1151
     svc_action_t * op = p;
1b1151
 
1b1151
     op->opaque->timerid = 0;
1b1151
-    crm_warn("%s operation on systemd unit %s named '%s' timed out", op->action, op->agent, op->rsc);
1b1151
+    crm_info("%s action for systemd unit %s named '%s' timed out",
1b1151
+             op->action, op->agent, op->rsc);
1b1151
     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_TIMEOUT,
1b1151
                          "Systemd action did not complete within specified timeout");
1b1151
     services__finalize_async_op(op);
1b1151
diff --git a/lib/services/upstart.c b/lib/services/upstart.c
1b1151
index 2fdc229ad..2ece803e1 100644
1b1151
--- a/lib/services/upstart.c
1b1151
+++ b/lib/services/upstart.c
1b1151
@@ -308,21 +308,21 @@ get_first_instance(const gchar * job, int timeout)
1b1151
     dbus_message_unref(msg);
1b1151
 
1b1151
     if (dbus_error_is_set(&error)) {
1b1151
-        crm_err("Call to %s failed: %s", method, error.message);
1b1151
+        crm_info("Call to %s failed: %s", method, error.message);
1b1151
         dbus_error_free(&error);
1b1151
         goto done;
1b1151
 
1b1151
     } else if(reply == NULL) {
1b1151
-        crm_err("Call to %s failed: no reply", method);
1b1151
+        crm_info("Call to %s failed: no reply", method);
1b1151
         goto done;
1b1151
 
1b1151
     } else if (!dbus_message_iter_init(reply, &args)) {
1b1151
-        crm_err("Call to %s failed: Message has no arguments", method);
1b1151
+        crm_info("Call to %s failed: Message has no arguments", method);
1b1151
         goto done;
1b1151
     }
1b1151
 
1b1151
     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __func__, __LINE__)) {
1b1151
-        crm_err("Call to %s failed: Message has invalid arguments", method);
1b1151
+        crm_info("Call to %s failed: Message has invalid arguments", method);
1b1151
         goto done;
1b1151
     }
1b1151
 
1b1151
@@ -432,8 +432,8 @@ set_result_from_method_error(svc_action_t *op, const DBusError *error)
1b1151
         return;
1b1151
     }
1b1151
 
1b1151
-    crm_err("DBus request for %s of Upstart job %s for resource %s failed: %s",
1b1151
-            op->action, op->agent, crm_str(op->rsc), error->message);
1b1151
+    crm_info("DBus request for %s of Upstart job %s for resource %s failed: %s",
1b1151
+             op->action, op->agent, crm_str(op->rsc), error->message);
1b1151
 }
1b1151
 
1b1151
 /*!
1b1151
@@ -468,7 +468,7 @@ job_method_complete(DBusPendingCall *pending, void *user_data)
1b1151
 
1b1151
     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
1b1151
                                      __func__, __LINE__)) {
1b1151
-        crm_warn("DBus request for %s of %s succeeded but "
1b1151
+        crm_info("DBus request for %s of %s succeeded but "
1b1151
                  "return type was unexpected", op->action, crm_str(op->rsc));
1b1151
         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1b1151
 
1b1151
@@ -667,7 +667,8 @@ services__execute_upstart(svc_action_t *op)
1b1151
 
1b1151
     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
1b1151
                                      __func__, __LINE__)) {
1b1151
-        crm_warn("Call to %s passed but return type was unexpected", op->action);
1b1151
+        crm_info("Call to %s passed but return type was unexpected",
1b1151
+                 op->action);
1b1151
         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1b1151
 
1b1151
     } else {
1b1151
@@ -675,7 +676,7 @@ services__execute_upstart(svc_action_t *op)
1b1151
 
1b1151
         dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1b1151
                               DBUS_TYPE_INVALID);
1b1151
-        crm_info("Call to %s passed: %s", op->action, path);
1b1151
+        crm_debug("Call to %s passed: %s", op->action, path);
1b1151
         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1b1151
     }
1b1151
 
1b1151
-- 
1b1151
2.27.0
1b1151
1b1151
1b1151
From 39f6861c72eb9dd76d2cf3da287fe7485615631b Mon Sep 17 00:00:00 2001
1b1151
From: Ken Gaillot <kgaillot@redhat.com>
1b1151
Date: Mon, 8 Nov 2021 09:43:38 -0600
1b1151
Subject: [PATCH 12/12] Low: fencing: avoid use-after-free with new result
1b1151
 object
1b1151
1b1151
itnroduced by 153c9b552 (not released)
1b1151
---
1b1151
 lib/fencing/st_rhcs.c | 6 ++++--
1b1151
 1 file changed, 4 insertions(+), 2 deletions(-)
1b1151
1b1151
diff --git a/lib/fencing/st_rhcs.c b/lib/fencing/st_rhcs.c
1b1151
index 23e694975..6c8cbedc7 100644
1b1151
--- a/lib/fencing/st_rhcs.c
1b1151
+++ b/lib/fencing/st_rhcs.c
1b1151
@@ -143,15 +143,17 @@ stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
1b1151
     if (result->execution_status != PCMK_EXEC_DONE) {
1b1151
         crm_warn("Could not execute metadata action for %s: %s",
1b1151
                  agent, pcmk_exec_status_str(result->execution_status));
1b1151
+        rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
         stonith__destroy_action(action);
1b1151
-        return pcmk_rc2legacy(stonith__result2rc(result));
1b1151
+        return rc;
1b1151
     }
1b1151
 
1b1151
     if (result->exit_status != CRM_EX_OK) {
1b1151
         crm_warn("Metadata action for %s returned error code %d",
1b1151
                  agent, result->exit_status);
1b1151
+        rc = pcmk_rc2legacy(stonith__result2rc(result));
1b1151
         stonith__destroy_action(action);
1b1151
-        return pcmk_rc2legacy(stonith__result2rc(result));
1b1151
+        return rc;
1b1151
     }
1b1151
 
1b1151
     if (result->action_stdout == NULL) {
1b1151
-- 
1b1151
2.27.0
1b1151