Blame SOURCES/011-fencing-reasons.patch

d4e586
From 6db8e3adef0441953ec18dd0339c0a67c5c26bdf Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Tue, 14 Dec 2021 16:25:21 -0600
d4e586
Subject: [PATCH 01/17] Doc: Pacemaker Development: update for recent function
d4e586
 renames
d4e586
d4e586
---
d4e586
 doc/sphinx/Pacemaker_Development/components.rst | 16 ++++++++--------
d4e586
 1 file changed, 8 insertions(+), 8 deletions(-)
d4e586
d4e586
diff --git a/doc/sphinx/Pacemaker_Development/components.rst b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
index a51220cac9..68158484ce 100644
d4e586
--- a/doc/sphinx/Pacemaker_Development/components.rst
d4e586
+++ b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
@@ -106,7 +106,7 @@ or messaging layer callback, which calls:
d4e586
       the number of active peers), and if this is the last expected reply,
d4e586
       calls
d4e586
 
d4e586
-      * ``call_remote_stonith()``, which calculates the timeout and sends
d4e586
+      * ``request_peer_fencing()``, which calculates the timeout and sends
d4e586
         ``STONITH_OP_FENCE`` request(s) to carry out the fencing. If the target
d4e586
 	node has a fencing "topology" (which allows specifications such as
d4e586
 	"this node can be fenced either with device A, or devices B and C in
d4e586
@@ -156,7 +156,7 @@ returns, and calls
d4e586
   * done callback (``st_child_done()``), which calls ``schedule_stonith_command()``
d4e586
     for a new device if there are further required actions to execute or if the
d4e586
     original action failed, then builds and sends an XML reply to the original
d4e586
-    fencer (via ``stonith_send_async_reply()``), then checks whether any
d4e586
+    fencer (via ``send_async_reply()``), then checks whether any
d4e586
     pending actions are the same as the one just executed and merges them if so.
d4e586
 
d4e586
 Fencing replies
d4e586
@@ -169,18 +169,18 @@ messaging layer callback, which calls:
d4e586
 
d4e586
   * ``handle_reply()``, which calls
d4e586
 
d4e586
-    * ``process_remote_stonith_exec()``, which calls either
d4e586
-      ``call_remote_stonith()`` (to retry a failed operation, or try the next
d4e586
-       device in a topology is appropriate, which issues a new
d4e586
+    * ``fenced_process_fencing_reply()``, which calls either
d4e586
+      ``request_peer_fencing()`` (to retry a failed operation, or try the next
d4e586
+      device in a topology is appropriate, which issues a new
d4e586
       ``STONITH_OP_FENCE`` request, proceeding as before) or
d4e586
-      ``remote_op_done()`` (if the operation is definitively failed or
d4e586
+      ``finalize_op()`` (if the operation is definitively failed or
d4e586
       successful).
d4e586
 
d4e586
-      * remote_op_done() broadcasts the result to all peers.
d4e586
+      * ``finalize_op()`` broadcasts the result to all peers.
d4e586
 
d4e586
 Finally, all peers receive the broadcast result and call
d4e586
 
d4e586
-* ``remote_op_done()``, which sends the result to all local clients.
d4e586
+* ``finalize_op()``, which sends the result to all local clients.
d4e586
 
d4e586
 
d4e586
 .. index::
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 47db9e5fb410b1e911710727d646eb7180a70c90 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Fri, 12 Nov 2021 09:58:16 -0600
d4e586
Subject: [PATCH 02/17] Refactor: fencing: add full result to fence action
d4e586
 callback data
d4e586
d4e586
stonith_callback_data_t previously only contained the legacy return code for
d4e586
the action. Use its new opaque member to store the full result, along with
d4e586
accessors (available only internally for now).
d4e586
---
d4e586
 include/crm/fencing/internal.h |  3 ++
d4e586
 lib/fencing/st_client.c        | 99 ++++++++++++++++++++++++++--------
d4e586
 2 files changed, 81 insertions(+), 21 deletions(-)
d4e586
d4e586
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
d4e586
index f0d294a0b3..eff689e59b 100644
d4e586
--- a/include/crm/fencing/internal.h
d4e586
+++ b/include/crm/fencing/internal.h
d4e586
@@ -187,6 +187,9 @@ bool stonith__event_state_eq(stonith_history_t *history, void *user_data);
d4e586
 bool stonith__event_state_neq(stonith_history_t *history, void *user_data);
d4e586
 
d4e586
 int stonith__legacy2status(int rc);
d4e586
+int stonith__exit_status(stonith_callback_data_t *data);
d4e586
+int stonith__execution_status(stonith_callback_data_t *data);
d4e586
+const char *stonith__exit_reason(stonith_callback_data_t *data);
d4e586
 
d4e586
 /*!
d4e586
  * \internal
d4e586
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
d4e586
index 2ca094566b..9d93ffd481 100644
d4e586
--- a/lib/fencing/st_client.c
d4e586
+++ b/lib/fencing/st_client.c
d4e586
@@ -854,20 +854,23 @@ stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
d4e586
  * \param[in] st        Fencer API connection
d4e586
  * \param[in] call_id   If positive, call ID of completed fence action, otherwise
d4e586
  *                      legacy return code for early action failure
d4e586
- * \param[in] rc        Legacy return code for action result
d4e586
+ * \param[in] result    Full result for action
d4e586
  * \param[in] userdata  User data to pass to callback
d4e586
  * \param[in] callback  Fence action callback to invoke
d4e586
  */
d4e586
 static void
d4e586
-invoke_fence_action_callback(stonith_t *st, int call_id, int rc, void *userdata,
d4e586
+invoke_fence_action_callback(stonith_t *st, int call_id,
d4e586
+                             pcmk__action_result_t *result,
d4e586
+                             void *userdata,
d4e586
                              void (*callback) (stonith_t *st,
d4e586
                                                stonith_callback_data_t *data))
d4e586
 {
d4e586
     stonith_callback_data_t data = { 0, };
d4e586
 
d4e586
     data.call_id = call_id;
d4e586
-    data.rc = rc;
d4e586
+    data.rc = pcmk_rc2legacy(stonith__result2rc(result));
d4e586
     data.userdata = userdata;
d4e586
+    data.opaque = (void *) result;
d4e586
 
d4e586
     callback(st, &data);
d4e586
 }
d4e586
@@ -888,7 +891,7 @@ invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
d4e586
 {
d4e586
     stonith_private_t *private = NULL;
d4e586
     stonith_callback_client_t *cb_info = NULL;
d4e586
-    int rc = pcmk_ok;
d4e586
+    pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
d4e586
 
d4e586
     CRM_CHECK(stonith != NULL, return);
d4e586
     CRM_CHECK(stonith->st_private != NULL, return);
d4e586
@@ -897,20 +900,17 @@ invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
d4e586
 
d4e586
     if (msg == NULL) {
d4e586
         // Fencer didn't reply in time
d4e586
-        rc = -ETIME;
d4e586
+        pcmk__set_result(&result, CRM_EX_ERROR, PCMK_EXEC_TIMEOUT,
d4e586
+                         "Timeout waiting for reply from fencer");
d4e586
         CRM_LOG_ASSERT(call_id > 0);
d4e586
 
d4e586
     } else {
d4e586
         // We have the fencer reply
d4e586
-
d4e586
-        if (crm_element_value_int(msg, F_STONITH_RC, &rc) != 0) {
d4e586
-            rc = -pcmk_err_generic;
d4e586
-        }
d4e586
-
d4e586
         if ((crm_element_value_int(msg, F_STONITH_CALLID, &call_id) != 0)
d4e586
             || (call_id <= 0)) {
d4e586
             crm_log_xml_warn(msg, "Bad fencer reply");
d4e586
         }
d4e586
+        stonith__xe_get_result(msg, &result);
d4e586
     }
d4e586
 
d4e586
     if (call_id > 0) {
d4e586
@@ -919,27 +919,29 @@ invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
d4e586
     }
d4e586
 
d4e586
     if ((cb_info != NULL) && (cb_info->callback != NULL)
d4e586
-        && (rc == pcmk_ok || !(cb_info->only_success))) {
d4e586
+        && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
d4e586
         crm_trace("Invoking callback %s for call %d",
d4e586
                   crm_str(cb_info->id), call_id);
d4e586
-        invoke_fence_action_callback(stonith, call_id, rc, cb_info->user_data,
d4e586
-                                     cb_info->callback);
d4e586
+        invoke_fence_action_callback(stonith, call_id, &result,
d4e586
+                                     cb_info->user_data, cb_info->callback);
d4e586
 
d4e586
-    } else if ((private->op_callback == NULL) && (rc != pcmk_ok)) {
d4e586
-        crm_warn("Fencing action without registered callback failed: %s",
d4e586
-                 pcmk_strerror(rc));
d4e586
+    } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
d4e586
+        crm_warn("Fencing action without registered callback failed: %d (%s)",
d4e586
+                 result.exit_status,
d4e586
+                 pcmk_exec_status_str(result.execution_status));
d4e586
         crm_log_xml_debug(msg, "Failed fence update");
d4e586
     }
d4e586
 
d4e586
     if (private->op_callback != NULL) {
d4e586
         crm_trace("Invoking global callback for call %d", call_id);
d4e586
-        invoke_fence_action_callback(stonith, call_id, rc, NULL,
d4e586
+        invoke_fence_action_callback(stonith, call_id, &result, NULL,
d4e586
                                      private->op_callback);
d4e586
     }
d4e586
 
d4e586
     if (cb_info != NULL) {
d4e586
         stonith_api_del_callback(stonith, call_id, FALSE);
d4e586
     }
d4e586
+    pcmk__reset_result(&result);
d4e586
 }
d4e586
 
d4e586
 static gboolean
d4e586
@@ -1252,14 +1254,18 @@ stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int opti
d4e586
     CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
d4e586
     private = stonith->st_private;
d4e586
 
d4e586
-    if (call_id == 0) {
d4e586
+    if (call_id == 0) { // Add global callback
d4e586
         private->op_callback = callback;
d4e586
 
d4e586
-    } else if (call_id < 0) {
d4e586
+    } else if (call_id < 0) { // Call failed immediately, so call callback now
d4e586
         if (!(options & st_opt_report_only_success)) {
d4e586
+            pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
d4e586
+
d4e586
             crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
d4e586
-            invoke_fence_action_callback(stonith, call_id, call_id, user_data,
d4e586
-                                         callback);
d4e586
+            pcmk__set_result(&result, CRM_EX_ERROR,
d4e586
+                             stonith__legacy2status(call_id), NULL);
d4e586
+            invoke_fence_action_callback(stonith, call_id, &result,
d4e586
+                                         user_data, callback);
d4e586
         } else {
d4e586
             crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
d4e586
         }
d4e586
@@ -2293,6 +2299,57 @@ stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
d4e586
     freeXpathObject(xpath);
d4e586
 }
d4e586
 
d4e586
+/*!
d4e586
+ * \internal
d4e586
+ * \brief Return the exit status from an async action callback
d4e586
+ *
d4e586
+ * \param[in] data  Callback data
d4e586
+ *
d4e586
+ * \return Exit status from callback data
d4e586
+ */
d4e586
+int
d4e586
+stonith__exit_status(stonith_callback_data_t *data)
d4e586
+{
d4e586
+    if ((data == NULL) || (data->opaque == NULL)) {
d4e586
+        return CRM_EX_ERROR;
d4e586
+    }
d4e586
+    return ((pcmk__action_result_t *) data->opaque)->exit_status;
d4e586
+}
d4e586
+
d4e586
+/*!
d4e586
+ * \internal
d4e586
+ * \brief Return the execution status from an async action callback
d4e586
+ *
d4e586
+ * \param[in] data  Callback data
d4e586
+ *
d4e586
+ * \return Execution status from callback data
d4e586
+ */
d4e586
+int
d4e586
+stonith__execution_status(stonith_callback_data_t *data)
d4e586
+{
d4e586
+    if ((data == NULL) || (data->opaque == NULL)) {
d4e586
+        return PCMK_EXEC_UNKNOWN;
d4e586
+    }
d4e586
+    return ((pcmk__action_result_t *) data->opaque)->execution_status;
d4e586
+}
d4e586
+
d4e586
+/*!
d4e586
+ * \internal
d4e586
+ * \brief Return the exit reason from an async action callback
d4e586
+ *
d4e586
+ * \param[in] data  Callback data
d4e586
+ *
d4e586
+ * \return Exit reason from callback data
d4e586
+ */
d4e586
+const char *
d4e586
+stonith__exit_reason(stonith_callback_data_t *data)
d4e586
+{
d4e586
+    if ((data == NULL) || (data->opaque == NULL)) {
d4e586
+        return NULL;
d4e586
+    }
d4e586
+    return ((pcmk__action_result_t *) data->opaque)->exit_reason;
d4e586
+}
d4e586
+
d4e586
 // Deprecated functions kept only for backward API compatibility
d4e586
 // LCOV_EXCL_START
d4e586
 
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 1e076370ef4ac7993b5ff21ed1cdfb3c4a494cf0 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Tue, 9 Nov 2021 16:16:03 -0600
d4e586
Subject: [PATCH 03/17] Log: controller: improve fencing result messages
d4e586
d4e586
Now that fence callbacks get the full result, we can log a better message.
d4e586
Also check for error conditions better, improve message wording, and ensure
d4e586
only a single message is logged per result.
d4e586
---
d4e586
 daemons/controld/controld_fencing.c | 83 +++++++++++++++++++----------
d4e586
 1 file changed, 56 insertions(+), 27 deletions(-)
d4e586
d4e586
diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c
d4e586
index f5a252c813..f8d2fc13f4 100644
d4e586
--- a/daemons/controld/controld_fencing.c
d4e586
+++ b/daemons/controld/controld_fencing.c
d4e586
@@ -714,45 +714,64 @@ tengine_stonith_callback(stonith_t *stonith, stonith_callback_data_t *data)
d4e586
     int stonith_id = -1;
d4e586
     int transition_id = -1;
d4e586
     crm_action_t *action = NULL;
d4e586
-    int call_id = data->call_id;
d4e586
-    int rc = data->rc;
d4e586
-    char *userdata = data->userdata;
d4e586
-
d4e586
-    CRM_CHECK(userdata != NULL, return);
d4e586
-    crm_notice("Stonith operation %d/%s: %s (%d)", call_id, (char *)userdata,
d4e586
-               pcmk_strerror(rc), rc);
d4e586
+    const char *target = NULL;
d4e586
 
d4e586
-    if (AM_I_DC == FALSE) {
d4e586
+    if ((data == NULL) || (data->userdata == NULL)) {
d4e586
+        crm_err("Ignoring fence operation %d result: "
d4e586
+                "No transition key given (bug?)",
d4e586
+                ((data == NULL)? -1 : data->call_id));
d4e586
         return;
d4e586
     }
d4e586
 
d4e586
-    /* crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s", */
d4e586
-    /*       op->call_id, op->optype, op->node_name, op->op_result, */
d4e586
-    /*       (char *)op->node_list, op->private_data); */
d4e586
+    if (!AM_I_DC) {
d4e586
+        const char *reason = stonith__exit_reason(data);
d4e586
+
d4e586
+        if (reason == NULL) {
d4e586
+           reason = pcmk_exec_status_str(stonith__execution_status(data));
d4e586
+        }
d4e586
+        crm_notice("Result of fence operation %d: %d (%s) " CRM_XS " key=%s",
d4e586
+                   data->call_id, stonith__exit_status(data), reason,
d4e586
+                   (const char *) data->userdata);
d4e586
+        return;
d4e586
+    }
d4e586
 
d4e586
-    /* filter out old STONITH actions */
d4e586
-    CRM_CHECK(decode_transition_key(userdata, &uuid, &transition_id, &stonith_id, NULL),
d4e586
+    CRM_CHECK(decode_transition_key(data->userdata, &uuid, &transition_id,
d4e586
+                                    &stonith_id, NULL),
d4e586
               goto bail);
d4e586
 
d4e586
-    if (transition_graph->complete || stonith_id < 0 || !pcmk__str_eq(uuid, te_uuid, pcmk__str_casei)
d4e586
-        || transition_graph->id != transition_id) {
d4e586
-        crm_info("Ignoring STONITH action initiated outside of the current transition");
d4e586
+    if (transition_graph->complete || (stonith_id < 0)
d4e586
+        || !pcmk__str_eq(uuid, te_uuid, pcmk__str_none)
d4e586
+        || (transition_graph->id != transition_id)) {
d4e586
+        crm_info("Ignoring fence operation %d result: "
d4e586
+                 "Not from current transition " CRM_XS
d4e586
+                 " complete=%s action=%d uuid=%s (vs %s) transition=%d (vs %d)",
d4e586
+                 data->call_id, pcmk__btoa(transition_graph->complete),
d4e586
+                 stonith_id, uuid, te_uuid, transition_id, transition_graph->id);
d4e586
         goto bail;
d4e586
     }
d4e586
 
d4e586
     action = controld_get_action(stonith_id);
d4e586
     if (action == NULL) {
d4e586
-        crm_err("Stonith action not matched");
d4e586
+        crm_err("Ignoring fence operation %d result: "
d4e586
+                "Action %d not found in transition graph (bug?) "
d4e586
+                CRM_XS " uuid=%s transition=%d",
d4e586
+                data->call_id, stonith_id, uuid, transition_id);
d4e586
+        goto bail;
d4e586
+    }
d4e586
+
d4e586
+    target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
d4e586
+    if (target == NULL) {
d4e586
+        crm_err("Ignoring fence operation %d result: No target given (bug?)",
d4e586
+                data->call_id);
d4e586
         goto bail;
d4e586
     }
d4e586
 
d4e586
     stop_te_timer(action->timer);
d4e586
-    if (rc == pcmk_ok) {
d4e586
-        const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
d4e586
+    if (stonith__exit_status(data) == CRM_EX_OK) {
d4e586
         const char *uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
d4e586
         const char *op = crm_meta_value(action->params, "stonith_action");
d4e586
 
d4e586
-        crm_info("Stonith operation %d for %s passed", call_id, target);
d4e586
+        crm_notice("Fence operation %d for %s passed", data->call_id, target);
d4e586
         if (!(pcmk_is_set(action->flags, pcmk__graph_action_confirmed))) {
d4e586
             te_action_confirmed(action, NULL);
d4e586
             if (pcmk__str_eq("on", op, pcmk__str_casei)) {
d4e586
@@ -791,20 +810,30 @@ tengine_stonith_callback(stonith_t *stonith, stonith_callback_data_t *data)
d4e586
         st_fail_count_reset(target);
d4e586
 
d4e586
     } else {
d4e586
-        const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
d4e586
         enum transition_action abort_action = tg_restart;
d4e586
+        int status = stonith__execution_status(data);
d4e586
+        const char *reason = stonith__exit_reason(data);
d4e586
 
d4e586
+        if (reason == NULL) {
d4e586
+            if (status == PCMK_EXEC_DONE) {
d4e586
+                reason = "Agent returned error";
d4e586
+            } else {
d4e586
+                reason = pcmk_exec_status_str(status);
d4e586
+            }
d4e586
+        }
d4e586
         crm__set_graph_action_flags(action, pcmk__graph_action_failed);
d4e586
-        crm_notice("Stonith operation %d for %s failed (%s): aborting transition.",
d4e586
-                   call_id, target, pcmk_strerror(rc));
d4e586
 
d4e586
         /* If no fence devices were available, there's no use in immediately
d4e586
          * checking again, so don't start a new transition in that case.
d4e586
          */
d4e586
-        if (rc == -ENODEV) {
d4e586
-            crm_warn("No devices found in cluster to fence %s, giving up",
d4e586
-                     target);
d4e586
+        if (status == PCMK_EXEC_NO_FENCE_DEVICE) {
d4e586
+            crm_warn("Fence operation %d for %s failed: %s "
d4e586
+                     "(aborting transition and giving up for now)",
d4e586
+                     data->call_id, target, reason);
d4e586
             abort_action = tg_stop;
d4e586
+        } else {
d4e586
+            crm_notice("Fence operation %d for %s failed: %s "
d4e586
+                       "(aborting transition)", data->call_id, target, reason);
d4e586
         }
d4e586
 
d4e586
         /* Increment the fail count now, so abort_for_stonith_failure() can
d4e586
@@ -818,7 +847,7 @@ tengine_stonith_callback(stonith_t *stonith, stonith_callback_data_t *data)
d4e586
     trigger_graph();
d4e586
 
d4e586
   bail:
d4e586
-    free(userdata);
d4e586
+    free(data->userdata);
d4e586
     free(uuid);
d4e586
     return;
d4e586
 }
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 25547e3b7e6eb23efad1c359388d6e8d0df62363 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 22 Nov 2021 12:37:16 -0600
d4e586
Subject: [PATCH 04/17] Refactor: executor: drop action_get_uniform_rc()
d4e586
 function
d4e586
d4e586
action_get_uniform_rc() called stonith2uniform_rc() or services_result2ocf() as
d4e586
appropriate to the action standard. However, it was called only from a place
d4e586
that did not process stonith actions, so that place can just call
d4e586
services_result2ocf() directly.
d4e586
d4e586
This will simplify planned changes.
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 24 ++++++------------------
d4e586
 1 file changed, 6 insertions(+), 18 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 5bb2aab692..5e123e322e 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -780,23 +780,6 @@ stonith2uniform_rc(const char *action, int rc)
d4e586
     return rc;
d4e586
 }
d4e586
 
d4e586
-static int
d4e586
-action_get_uniform_rc(svc_action_t *action)
d4e586
-{
d4e586
-    lrmd_cmd_t *cmd = action->cb_data;
d4e586
-
d4e586
-    if (pcmk__str_eq(action->standard, PCMK_RESOURCE_CLASS_STONITH,
d4e586
-                            pcmk__str_casei)) {
d4e586
-        return stonith2uniform_rc(cmd->action, action->rc);
d4e586
-    } else {
d4e586
-        enum ocf_exitcode code = services_result2ocf(action->standard,
d4e586
-                                                     cmd->action, action->rc);
d4e586
-
d4e586
-        // Cast variable instead of function return to keep compilers happy
d4e586
-        return (int) code;
d4e586
-    }
d4e586
-}
d4e586
-
d4e586
 struct notify_new_client_data {
d4e586
     xmlNode *notify;
d4e586
     pcmk__client_t *new_client;
d4e586
@@ -848,6 +831,7 @@ action_complete(svc_action_t * action)
d4e586
 {
d4e586
     lrmd_rsc_t *rsc;
d4e586
     lrmd_cmd_t *cmd = action->cb_data;
d4e586
+    enum ocf_exitcode code;
d4e586
 
d4e586
 #ifdef PCMK__TIME_USE_CGT
d4e586
     const char *rclass = NULL;
d4e586
@@ -867,8 +851,12 @@ action_complete(svc_action_t * action)
d4e586
 #endif
d4e586
 
d4e586
     cmd->last_pid = action->pid;
d4e586
-    pcmk__set_result(&(cmd->result), action_get_uniform_rc(action),
d4e586
+
d4e586
+    // Cast variable instead of function return to keep compilers happy
d4e586
+    code = services_result2ocf(action->standard, cmd->action, action->rc);
d4e586
+    pcmk__set_result(&(cmd->result), (int) code,
d4e586
                      action->status, services__exit_reason(action));
d4e586
+
d4e586
     rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
d4e586
 
d4e586
 #ifdef PCMK__TIME_USE_CGT
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From b5e31ba2539da4e94c124c3f0c8c72f7039f9a7a Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 22 Nov 2021 12:39:30 -0600
d4e586
Subject: [PATCH 05/17] Feature: executor: use full result from fencer for
d4e586
 fence actions
d4e586
d4e586
Now that fence callbacks get the full result, we can improve the executor
d4e586
command result for fence actions. stonith_action_complete() now takes a
d4e586
full result, allowing the executor to use that directly rather than map a
d4e586
legacy return code.
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 140 +++++++++++++++++++--------------
d4e586
 1 file changed, 80 insertions(+), 60 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 5e123e322e..e722994012 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -8,6 +8,7 @@
d4e586
  */
d4e586
 
d4e586
 #include <crm_internal.h>
d4e586
+#include <crm/fencing/internal.h>
d4e586
 
d4e586
 #include <glib.h>
d4e586
 
d4e586
@@ -748,38 +749,6 @@ cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc)
d4e586
     }
d4e586
 }
d4e586
 
d4e586
-static int
d4e586
-stonith2uniform_rc(const char *action, int rc)
d4e586
-{
d4e586
-    switch (rc) {
d4e586
-        case pcmk_ok:
d4e586
-            rc = PCMK_OCF_OK;
d4e586
-            break;
d4e586
-
d4e586
-        case -ENODEV:
d4e586
-            /* This should be possible only for probes in practice, but
d4e586
-             * interpret for all actions to be safe.
d4e586
-             */
d4e586
-            if (pcmk__str_eq(action, "monitor", pcmk__str_casei)) {
d4e586
-                rc = PCMK_OCF_NOT_RUNNING;
d4e586
-            } else if (pcmk__str_eq(action, "stop", pcmk__str_casei)) {
d4e586
-                rc = PCMK_OCF_OK;
d4e586
-            } else {
d4e586
-                rc = PCMK_OCF_NOT_INSTALLED;
d4e586
-            }
d4e586
-            break;
d4e586
-
d4e586
-        case -EOPNOTSUPP:
d4e586
-            rc = PCMK_OCF_UNIMPLEMENT_FEATURE;
d4e586
-            break;
d4e586
-
d4e586
-        default:
d4e586
-            rc = PCMK_OCF_UNKNOWN_ERROR;
d4e586
-            break;
d4e586
-    }
d4e586
-    return rc;
d4e586
-}
d4e586
-
d4e586
 struct notify_new_client_data {
d4e586
     xmlNode *notify;
d4e586
     pcmk__client_t *new_client;
d4e586
@@ -988,46 +957,84 @@ action_complete(svc_action_t * action)
d4e586
     cmd_finalize(cmd, rsc);
d4e586
 }
d4e586
 
d4e586
+/*!
d4e586
+ * \internal
d4e586
+ * \brief Process the result of a fence device action (start, stop, or monitor)
d4e586
+ *
d4e586
+ * \param[in] cmd               Fence device action that completed
d4e586
+ * \param[in] exit_status       Fencer API exit status for action
d4e586
+ * \param[in] execution_status  Fencer API execution status for action
d4e586
+ * \param[in] exit_reason       Human-friendly detail, if action failed
d4e586
+ */
d4e586
 static void
d4e586
-stonith_action_complete(lrmd_cmd_t * cmd, int rc)
d4e586
+stonith_action_complete(lrmd_cmd_t *cmd, int exit_status,
d4e586
+                        enum pcmk_exec_status execution_status,
d4e586
+                        const char *exit_reason)
d4e586
 {
d4e586
     // This can be NULL if resource was removed before command completed
d4e586
     lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
d4e586
 
d4e586
-    cmd->result.exit_status = stonith2uniform_rc(cmd->action, rc);
d4e586
+    // Simplify fencer exit status to uniform exit status
d4e586
+    if (exit_status != CRM_EX_OK) {
d4e586
+        exit_status = PCMK_OCF_UNKNOWN_ERROR;
d4e586
+    }
d4e586
 
d4e586
-    /* This function may be called with status already set to cancelled, if a
d4e586
-     * pending action was aborted. Otherwise, we need to determine status from
d4e586
-     * the fencer return code.
d4e586
-     */
d4e586
-    if (cmd->result.execution_status != PCMK_EXEC_CANCELLED) {
d4e586
-        cmd->result.execution_status = stonith__legacy2status(rc);
d4e586
+    if (cmd->result.execution_status == PCMK_EXEC_CANCELLED) {
d4e586
+        /* An in-flight fence action was cancelled. The execution status is
d4e586
+         * already correct, so don't overwrite it.
d4e586
+         */
d4e586
+        execution_status = PCMK_EXEC_CANCELLED;
d4e586
 
d4e586
-        // Simplify status codes from fencer
d4e586
-        switch (cmd->result.execution_status) {
d4e586
+    } else {
d4e586
+        /* Some execution status codes have specific meanings for the fencer
d4e586
+         * that executor clients may not expect, so map them to a simple error
d4e586
+         * status.
d4e586
+         */
d4e586
+        switch (execution_status) {
d4e586
             case PCMK_EXEC_NOT_CONNECTED:
d4e586
             case PCMK_EXEC_INVALID:
d4e586
-            case PCMK_EXEC_NO_FENCE_DEVICE:
d4e586
             case PCMK_EXEC_NO_SECRETS:
d4e586
-                cmd->result.execution_status = PCMK_EXEC_ERROR;
d4e586
+                execution_status = PCMK_EXEC_ERROR;
d4e586
                 break;
d4e586
-            default:
d4e586
+
d4e586
+            case PCMK_EXEC_NO_FENCE_DEVICE:
d4e586
+                /* This should be possible only for probes in practice, but
d4e586
+                 * interpret for all actions to be safe.
d4e586
+                 */
d4e586
+                if (pcmk__str_eq(cmd->action, CRMD_ACTION_STATUS,
d4e586
+                                 pcmk__str_none)) {
d4e586
+                    exit_status = PCMK_OCF_NOT_RUNNING;
d4e586
+
d4e586
+                } else if (pcmk__str_eq(cmd->action, CRMD_ACTION_STOP,
d4e586
+                                        pcmk__str_none)) {
d4e586
+                    exit_status = PCMK_OCF_OK;
d4e586
+
d4e586
+                } else {
d4e586
+                    exit_status = PCMK_OCF_NOT_INSTALLED;
d4e586
+                }
d4e586
+                execution_status = PCMK_EXEC_ERROR;
d4e586
                 break;
d4e586
-        }
d4e586
 
d4e586
-        // Certain successful actions change the known state of the resource
d4e586
-        if ((rsc != NULL) && pcmk__result_ok(&(cmd->result))) {
d4e586
-            if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
-                rsc->st_probe_rc = pcmk_ok; // maps to PCMK_OCF_OK
d4e586
-            } else if (pcmk__str_eq(cmd->action, "stop", pcmk__str_casei)) {
d4e586
-                rsc->st_probe_rc = -ENODEV; // maps to PCMK_OCF_NOT_RUNNING
d4e586
-            }
d4e586
+            case PCMK_EXEC_NOT_SUPPORTED:
d4e586
+                exit_status = PCMK_OCF_UNIMPLEMENT_FEATURE;
d4e586
+                break;
d4e586
+
d4e586
+            default:
d4e586
+                break;
d4e586
         }
d4e586
     }
d4e586
 
d4e586
-    // Give the user more detail than an OCF code
d4e586
-    if (rc != -pcmk_err_generic) {
d4e586
-        cmd->result.exit_reason = strdup(pcmk_strerror(rc));
d4e586
+    pcmk__set_result(&cmd->result, exit_status, execution_status, exit_reason);
d4e586
+
d4e586
+    // Certain successful actions change the known state of the resource
d4e586
+    if ((rsc != NULL) && pcmk__result_ok(&(cmd->result))) {
d4e586
+
d4e586
+        if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
+            rsc->st_probe_rc = pcmk_ok; // maps to PCMK_OCF_OK
d4e586
+
d4e586
+        } else if (pcmk__str_eq(cmd->action, "stop", pcmk__str_casei)) {
d4e586
+            rsc->st_probe_rc = -ENODEV; // maps to PCMK_OCF_NOT_RUNNING
d4e586
+        }
d4e586
     }
d4e586
 
d4e586
     /* The recurring timer should not be running at this point in any case, but
d4e586
@@ -1050,7 +1057,15 @@ stonith_action_complete(lrmd_cmd_t * cmd, int rc)
d4e586
 static void
d4e586
 lrmd_stonith_callback(stonith_t * stonith, stonith_callback_data_t * data)
d4e586
 {
d4e586
-    stonith_action_complete(data->userdata, data->rc);
d4e586
+    if ((data == NULL) || (data->userdata == NULL)) {
d4e586
+        crm_err("Ignoring fence action result: "
d4e586
+                "Invalid callback arguments (bug?)");
d4e586
+    } else {
d4e586
+        stonith_action_complete((lrmd_cmd_t *) data->userdata,
d4e586
+                                stonith__exit_status(data),
d4e586
+                                stonith__execution_status(data),
d4e586
+                                stonith__exit_reason(data));
d4e586
+    }
d4e586
 }
d4e586
 
d4e586
 void
d4e586
@@ -1097,7 +1112,9 @@ stonith_connection_failed(void)
d4e586
     crm_err("Connection to fencer failed, finalizing %d pending operations",
d4e586
             g_list_length(cmd_list));
d4e586
     for (cmd_iter = cmd_list; cmd_iter; cmd_iter = cmd_iter->next) {
d4e586
-        stonith_action_complete(cmd_iter->data, -ENOTCONN);
d4e586
+        stonith_action_complete((lrmd_cmd_t *) cmd_iter->data,
d4e586
+                                CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED,
d4e586
+                                "Lost connection to fencer");
d4e586
     }
d4e586
     g_list_free(cmd_list);
d4e586
 }
d4e586
@@ -1210,7 +1227,7 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
 
d4e586
     } else if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
         rc = execd_stonith_start(stonith_api, rsc, cmd);
d4e586
-        if (rc == 0) {
d4e586
+        if (rc == pcmk_ok) {
d4e586
             do_monitor = TRUE;
d4e586
         }
d4e586
 
d4e586
@@ -1233,7 +1250,10 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
         }
d4e586
     }
d4e586
 
d4e586
-    stonith_action_complete(cmd, rc);
d4e586
+    stonith_action_complete(cmd,
d4e586
+                            ((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR),
d4e586
+                            stonith__legacy2status(rc),
d4e586
+                            rc == -pcmk_err_generic? NULL : pcmk_strerror(rc));
d4e586
 }
d4e586
 
d4e586
 static int
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 0cdc8506c2383cf05c2f62ab1ac9438958daf210 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 22 Nov 2021 16:15:05 -0600
d4e586
Subject: [PATCH 06/17] Fix: executor,scheduler: treat "no secrets" fence
d4e586
 results as a hard error
d4e586
d4e586
Previously, the executor mapped the fencer's PCMK_EXEC_NO_SECRETS status to
d4e586
PCMK_EXEC_ERROR to keep handling of that situation the same as before the new
d4e586
code was added.
d4e586
d4e586
However, the earlier handling was less than ideal -- a resource action that
d4e586
failed due to missing secrets would be retried on the same node, and almost
d4e586
certainly fail again for the same reason. Now, the executor passes along
d4e586
PCMK_EXEC_NO_SECRETS to clients; the controller will record the result in the
d4e586
CIB status, and the scheduler will treat it as a hard error (i.e. not retrying
d4e586
on the same node).
d4e586
d4e586
Backward compatibility isn't a problem because the scheduler treats unknown
d4e586
status codes the same as PCMK_EXEC_ERROR, so an older DC will continue to
d4e586
handle it as before. The CRM feature set has been bumped so the handling can't
d4e586
flip back and forth in a mixed-version cluster.
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 1 -
d4e586
 include/crm/crm.h              | 4 ++--
d4e586
 lib/pengine/unpack.c           | 3 ---
d4e586
 3 files changed, 2 insertions(+), 6 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index e722994012..4ced6d1d5c 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -993,7 +993,6 @@ stonith_action_complete(lrmd_cmd_t *cmd, int exit_status,
d4e586
         switch (execution_status) {
d4e586
             case PCMK_EXEC_NOT_CONNECTED:
d4e586
             case PCMK_EXEC_INVALID:
d4e586
-            case PCMK_EXEC_NO_SECRETS:
d4e586
                 execution_status = PCMK_EXEC_ERROR;
d4e586
                 break;
d4e586
 
d4e586
diff --git a/include/crm/crm.h b/include/crm/crm.h
d4e586
index 16b35e9c55..56b07cb12a 100644
d4e586
--- a/include/crm/crm.h
d4e586
+++ b/include/crm/crm.h
d4e586
@@ -1,5 +1,5 @@
d4e586
 /*
d4e586
- * Copyright 2004-2021 the Pacemaker project contributors
d4e586
+ * Copyright 2004-2022 the Pacemaker project contributors
d4e586
  *
d4e586
  * The version control history for this file may have further details.
d4e586
  *
d4e586
@@ -66,7 +66,7 @@ extern "C" {
d4e586
  * >=3.0.13: Fail counts include operation name and interval
d4e586
  * >=3.2.0:  DC supports PCMK_EXEC_INVALID and PCMK_EXEC_NOT_CONNECTED
d4e586
  */
d4e586
-#  define CRM_FEATURE_SET		"3.12.0"
d4e586
+#  define CRM_FEATURE_SET		"3.13.0"
d4e586
 
d4e586
 /* Pacemaker's CPG protocols use fixed-width binary fields for the sender and
d4e586
  * recipient of a CPG message. This imposes an arbitrary limit on cluster node
d4e586
diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
d4e586
index 3e0384cd2a..8a2d2a6d6d 100644
d4e586
--- a/lib/pengine/unpack.c
d4e586
+++ b/lib/pengine/unpack.c
d4e586
@@ -3879,9 +3879,6 @@ unpack_rsc_op(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op,
d4e586
         case PCMK_EXEC_INVALID:
d4e586
             break; // Not done, do error handling
d4e586
 
d4e586
-        /* These should only be possible in fence action results, not operation
d4e586
-         * history, but have some handling in place as a fail-safe.
d4e586
-         */
d4e586
         case PCMK_EXEC_NO_FENCE_DEVICE:
d4e586
         case PCMK_EXEC_NO_SECRETS:
d4e586
             status = PCMK_EXEC_ERROR_HARD;
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 75c1bdcf3ffc406e6fa286fd5fcff83e1e65591a Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 12:05:20 -0600
d4e586
Subject: [PATCH 07/17] Low: executor: improve result for fence device probes
d4e586
d4e586
Now that lrmd_rsc_execute_stonith() sets a full result instead of just a legacy
d4e586
return code, refactor lrmd_rsc_t's st_probe_rc as an execution status (and
d4e586
rename to fence_probe_result). Set an appropriate exit reason when available.
d4e586
---
d4e586
 daemons/execd/execd_commands.c  | 57 ++++++++++++++++++++++++++-------
d4e586
 daemons/execd/pacemaker-execd.h |  9 +++++-
d4e586
 2 files changed, 54 insertions(+), 12 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 4ced6d1d5c..6e5505e973 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -285,7 +285,9 @@ build_rsc_from_xml(xmlNode * msg)
d4e586
     rsc->provider = crm_element_value_copy(rsc_xml, F_LRMD_PROVIDER);
d4e586
     rsc->type = crm_element_value_copy(rsc_xml, F_LRMD_TYPE);
d4e586
     rsc->work = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_rsc_dispatch, rsc);
d4e586
-    rsc->st_probe_rc = -ENODEV; // if stonith, initialize to "not running"
d4e586
+
d4e586
+    // Initialize fence device probes (to return "not running")
d4e586
+    rsc->fence_probe_result = PCMK_EXEC_NO_FENCE_DEVICE;
d4e586
     return rsc;
d4e586
 }
d4e586
 
d4e586
@@ -1029,10 +1031,10 @@ stonith_action_complete(lrmd_cmd_t *cmd, int exit_status,
d4e586
     if ((rsc != NULL) && pcmk__result_ok(&(cmd->result))) {
d4e586
 
d4e586
         if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
-            rsc->st_probe_rc = pcmk_ok; // maps to PCMK_OCF_OK
d4e586
+            rsc->fence_probe_result = PCMK_EXEC_DONE; // "running"
d4e586
 
d4e586
         } else if (pcmk__str_eq(cmd->action, "stop", pcmk__str_casei)) {
d4e586
-            rsc->st_probe_rc = -ENODEV; // maps to PCMK_OCF_NOT_RUNNING
d4e586
+            rsc->fence_probe_result = PCMK_EXEC_NO_FENCE_DEVICE; // "not running"
d4e586
         }
d4e586
     }
d4e586
 
d4e586
@@ -1081,14 +1083,13 @@ stonith_connection_failed(void)
d4e586
         if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
d4e586
             /* If we registered this fence device, we don't know whether the
d4e586
              * fencer still has the registration or not. Cause future probes to
d4e586
-             * return PCMK_OCF_UNKNOWN_ERROR until the resource is stopped or
d4e586
-             * started successfully. This is especially important if the
d4e586
-             * controller also went away (possibly due to a cluster layer
d4e586
-             * restart) and won't receive our client notification of any
d4e586
-             * monitors finalized below.
d4e586
+             * return an error until the resource is stopped or started
d4e586
+             * successfully. This is especially important if the controller also
d4e586
+             * went away (possibly due to a cluster layer restart) and won't
d4e586
+             * receive our client notification of any monitors finalized below.
d4e586
              */
d4e586
-            if (rsc->st_probe_rc == pcmk_ok) {
d4e586
-                rsc->st_probe_rc = pcmk_err_generic;
d4e586
+            if (rsc->fence_probe_result == PCMK_EXEC_DONE) {
d4e586
+                rsc->fence_probe_result = PCMK_EXEC_NOT_CONNECTED;
d4e586
             }
d4e586
 
d4e586
             if (rsc->active) {
d4e586
@@ -1213,6 +1214,39 @@ execd_stonith_monitor(stonith_t *stonith_api, lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
d4e586
     return rc;
d4e586
 }
d4e586
 
d4e586
+/*!
d4e586
+ * \internal
d4e586
+ * \brief  Finalize the result of a fence device probe
d4e586
+ *
d4e586
+ * \param[in] cmd           Probe action
d4e586
+ * \param[in] probe_result  Probe result
d4e586
+ */
d4e586
+static void
d4e586
+finalize_fence_device_probe(lrmd_cmd_t *cmd, enum pcmk_exec_status probe_result)
d4e586
+{
d4e586
+    int exit_status = CRM_EX_ERROR;
d4e586
+    const char *reason = NULL;
d4e586
+
d4e586
+    switch (probe_result) {
d4e586
+        case PCMK_EXEC_DONE: // Device is "running"
d4e586
+            exit_status = CRM_EX_OK;
d4e586
+            break;
d4e586
+
d4e586
+        case PCMK_EXEC_NO_FENCE_DEVICE: // Device is "not running"
d4e586
+            break;
d4e586
+
d4e586
+        case PCMK_EXEC_NOT_CONNECTED: // stonith_connection_failed()
d4e586
+            reason = "Lost connection to fencer";
d4e586
+            break;
d4e586
+
d4e586
+        default: // Shouldn't be possible
d4e586
+            probe_result = PCMK_EXEC_ERROR;
d4e586
+            reason = "Invalid fence device probe result (bug?)";
d4e586
+            break;
d4e586
+    }
d4e586
+    stonith_action_complete(cmd, exit_status, probe_result, reason);
d4e586
+}
d4e586
+
d4e586
 static void
d4e586
 lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
 {
d4e586
@@ -1237,7 +1271,8 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
         if (cmd->interval_ms > 0) {
d4e586
             do_monitor = TRUE;
d4e586
         } else {
d4e586
-            rc = rsc->st_probe_rc;
d4e586
+            finalize_fence_device_probe(cmd, rsc->fence_probe_result);
d4e586
+            return;
d4e586
         }
d4e586
     }
d4e586
 
d4e586
diff --git a/daemons/execd/pacemaker-execd.h b/daemons/execd/pacemaker-execd.h
d4e586
index 51ef8d22e6..057d889584 100644
d4e586
--- a/daemons/execd/pacemaker-execd.h
d4e586
+++ b/daemons/execd/pacemaker-execd.h
d4e586
@@ -41,7 +41,14 @@ typedef struct lrmd_rsc_s {
d4e586
      * that have been handed off from the pending ops list. */
d4e586
     GList *recurring_ops;
d4e586
 
d4e586
-    int st_probe_rc; // What value should be returned for a probe if stonith
d4e586
+    /* If this resource is a fence device, probes are handled internally by the
d4e586
+     * executor, and this value indicates the result that should currently be
d4e586
+     * returned for probes. It should be one of:
d4e586
+     * PCMK_EXEC_DONE (to indicate "running"),
d4e586
+     * PCMK_EXEC_NO_FENCE_DEVICE ("not running"), or
d4e586
+     * PCMK_EXEC_NOT_CONNECTED ("unknown because fencer connection was lost").
d4e586
+     */
d4e586
+    enum pcmk_exec_status fence_probe_result;
d4e586
 
d4e586
     crm_trigger_t *work;
d4e586
 } lrmd_rsc_t;
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 1ab799d945171ab8d91bd0aada64e70a71193e5c Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 12:14:48 -0600
d4e586
Subject: [PATCH 08/17] Low: executor: don't require a fencer connection for
d4e586
 probes
d4e586
d4e586
For fence devices, probe results are based on earlier state determinations,
d4e586
so handle them before requiring an active fencer connection. The effect may be
d4e586
negligible, but it would allow probes to proceed while waiting for a
d4e586
reconnection.
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 15 ++++++++-------
d4e586
 1 file changed, 8 insertions(+), 7 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 6e5505e973..5999ba19c9 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -1255,7 +1255,13 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
 
d4e586
     stonith_t *stonith_api = get_stonith_connection();
d4e586
 
d4e586
-    if (!stonith_api) {
d4e586
+    if (pcmk__str_eq(cmd->action, "monitor", pcmk__str_casei)
d4e586
+        && (cmd->interval_ms == 0)) {
d4e586
+        // Probes don't require a fencer connection
d4e586
+        finalize_fence_device_probe(cmd, rsc->fence_probe_result);
d4e586
+        return;
d4e586
+
d4e586
+    } else if (stonith_api == NULL) {
d4e586
         rc = -ENOTCONN;
d4e586
 
d4e586
     } else if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
@@ -1268,12 +1274,7 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
         rc = execd_stonith_stop(stonith_api, rsc);
d4e586
 
d4e586
     } else if (pcmk__str_eq(cmd->action, "monitor", pcmk__str_casei)) {
d4e586
-        if (cmd->interval_ms > 0) {
d4e586
-            do_monitor = TRUE;
d4e586
-        } else {
d4e586
-            finalize_fence_device_probe(cmd, rsc->fence_probe_result);
d4e586
-            return;
d4e586
-        }
d4e586
+        do_monitor = TRUE;
d4e586
     }
d4e586
 
d4e586
     if (do_monitor) {
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From adf41fb1637bcc9a6e057be52d61a0b26e4535cc Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 12:20:34 -0600
d4e586
Subject: [PATCH 09/17] Low: executor: return an error for unsupported fence
d4e586
 device actions
d4e586
d4e586
... and set an exit reason. Previously, it would return success for unsupported
d4e586
actions. It shouldn't be possible, but it would be nice to have an indication
d4e586
of what is wrong if a bug is introduced.
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 6 ++++++
d4e586
 1 file changed, 6 insertions(+)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 5999ba19c9..772d6446dc 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -1275,6 +1275,12 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
 
d4e586
     } else if (pcmk__str_eq(cmd->action, "monitor", pcmk__str_casei)) {
d4e586
         do_monitor = TRUE;
d4e586
+
d4e586
+    } else {
d4e586
+        stonith_action_complete(cmd, PCMK_OCF_UNIMPLEMENT_FEATURE,
d4e586
+                                PCMK_EXEC_ERROR,
d4e586
+                                "Invalid fence device action (bug?)");
d4e586
+        return;
d4e586
     }
d4e586
 
d4e586
     if (do_monitor) {
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From af59dfe85bc83f5609d0a3b3b7939271549cb76f Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 12:24:07 -0600
d4e586
Subject: [PATCH 10/17] Low: executor: set exit reason if no fencer connection
d4e586
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 5 ++++-
d4e586
 1 file changed, 4 insertions(+), 1 deletion(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 772d6446dc..7ae309d94c 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -1262,7 +1262,10 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
         return;
d4e586
 
d4e586
     } else if (stonith_api == NULL) {
d4e586
-        rc = -ENOTCONN;
d4e586
+        stonith_action_complete(cmd, PCMK_OCF_UNKNOWN_ERROR,
d4e586
+                                PCMK_EXEC_NOT_CONNECTED,
d4e586
+                                "No connection to fencer");
d4e586
+        return;
d4e586
 
d4e586
     } else if (pcmk__str_eq(cmd->action, "start", pcmk__str_casei)) {
d4e586
         rc = execd_stonith_start(stonith_api, rsc, cmd);
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From ad0930b75d5617490c3a0dc3c6b83411b3c4536d Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 14:42:26 -0600
d4e586
Subject: [PATCH 11/17] Test: cts-fence-helper: log full result in fence
d4e586
 callback
d4e586
d4e586
---
d4e586
 daemons/fenced/cts-fence-helper.c | 7 +++++--
d4e586
 1 file changed, 5 insertions(+), 2 deletions(-)
d4e586
d4e586
diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c
d4e586
index 2adb032f24..c2b55d73b9 100644
d4e586
--- a/daemons/fenced/cts-fence-helper.c
d4e586
+++ b/daemons/fenced/cts-fence-helper.c
d4e586
@@ -1,5 +1,5 @@
d4e586
 /*
d4e586
- * Copyright 2009-2020 the Pacemaker project contributors
d4e586
+ * Copyright 2009-2021 the Pacemaker project contributors
d4e586
  *
d4e586
  * This source code is licensed under the GNU General Public License version 2
d4e586
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
d4e586
@@ -132,7 +132,10 @@ st_callback(stonith_t * st, stonith_event_t * e)
d4e586
 static void
d4e586
 st_global_callback(stonith_t * stonith, stonith_callback_data_t * data)
d4e586
 {
d4e586
-    crm_notice("Call id %d completed with rc %d", data->call_id, data->rc);
d4e586
+    crm_notice("Call %d exited %d: %s (%s)",
d4e586
+               data->call_id, stonith__exit_status(data),
d4e586
+               stonith__execution_status(data),
d4e586
+               crm_str(stonith__exit_reason(data)));
d4e586
 }
d4e586
 
d4e586
 static void
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 1b50ff4d83b7a96cd70389891b7b6568812f66f6 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Wed, 10 Nov 2021 15:10:14 -0600
d4e586
Subject: [PATCH 12/17] Test: cts-fence-helper: track full result instead of
d4e586
 legacy return code
d4e586
d4e586
---
d4e586
 daemons/fenced/cts-fence-helper.c | 77 +++++++++++++++----------------
d4e586
 1 file changed, 37 insertions(+), 40 deletions(-)
d4e586
d4e586
diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c
d4e586
index c2b55d73b9..2739f57804 100644
d4e586
--- a/daemons/fenced/cts-fence-helper.c
d4e586
+++ b/daemons/fenced/cts-fence-helper.c
d4e586
@@ -34,23 +34,12 @@
d4e586
 static GMainLoop *mainloop = NULL;
d4e586
 static crm_trigger_t *trig = NULL;
d4e586
 static int mainloop_iter = 0;
d4e586
-static int callback_rc = 0;
d4e586
+static pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
d4e586
+
d4e586
 typedef void (*mainloop_test_iteration_cb) (int check_event);
d4e586
 
d4e586
 #define MAINLOOP_DEFAULT_TIMEOUT 2
d4e586
 
d4e586
-#define mainloop_test_done(pass) \
d4e586
-    if (pass) { \
d4e586
-        crm_info("SUCCESS - %s", __func__); \
d4e586
-        mainloop_iter++;   \
d4e586
-        mainloop_set_trigger(trig);  \
d4e586
-    } else { \
d4e586
-        crm_err("FAILURE = %s async_callback %d", __func__, callback_rc); \
d4e586
-        crm_exit(CRM_EX_ERROR); \
d4e586
-    } \
d4e586
-    callback_rc = 0; \
d4e586
-
d4e586
-
d4e586
 enum test_modes {
d4e586
     test_standard = 0,  // test using a specific developer environment
d4e586
     test_passive,       // watch notifications only
d4e586
@@ -93,6 +82,23 @@ static const int st_opts = st_opt_sync_call;
d4e586
 static int expected_notifications = 0;
d4e586
 static int verbose = 0;
d4e586
 
d4e586
+static void
d4e586
+mainloop_test_done(const char *origin, bool pass)
d4e586
+{
d4e586
+    if (pass) {
d4e586
+        crm_info("SUCCESS - %s", origin);
d4e586
+        mainloop_iter++;
d4e586
+        mainloop_set_trigger(trig);
d4e586
+        result.execution_status = PCMK_EXEC_UNKNOWN;
d4e586
+        result.exit_status = CRM_EX_OK;
d4e586
+    } else {
d4e586
+        crm_err("FAILURE - %s (%d: %s)", origin, result.exit_status,
d4e586
+                pcmk_exec_status_str(result.execution_status));
d4e586
+        crm_exit(CRM_EX_ERROR);
d4e586
+    }
d4e586
+}
d4e586
+
d4e586
+
d4e586
 static void
d4e586
 dispatch_helper(int timeout)
d4e586
 {
d4e586
@@ -385,7 +391,9 @@ static void
d4e586
 static void
d4e586
 mainloop_callback(stonith_t * stonith, stonith_callback_data_t * data)
d4e586
 {
d4e586
-    callback_rc = data->rc;
d4e586
+    pcmk__set_result(&result, stonith__exit_status(data),
d4e586
+                     stonith__execution_status(data),
d4e586
+                     stonith__exit_reason(data));
d4e586
     iterate_mainloop_tests(TRUE);
d4e586
 }
d4e586
 
d4e586
@@ -404,18 +412,14 @@ test_async_fence_pass(int check_event)
d4e586
     int rc = 0;
d4e586
 
d4e586
     if (check_event) {
d4e586
-        if (callback_rc != 0) {
d4e586
-            mainloop_test_done(FALSE);
d4e586
-        } else {
d4e586
-            mainloop_test_done(TRUE);
d4e586
-        }
d4e586
+        mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
d4e586
         return;
d4e586
     }
d4e586
 
d4e586
     rc = st->cmds->fence(st, 0, "true_1_node1", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
d4e586
     if (rc < 0) {
d4e586
         crm_err("fence failed with rc %d", rc);
d4e586
-        mainloop_test_done(FALSE);
d4e586
+        mainloop_test_done(__func__, false);
d4e586
     }
d4e586
     register_callback_helper(rc);
d4e586
     /* wait for event */
d4e586
@@ -431,15 +435,15 @@ test_async_fence_custom_timeout(int check_event)
d4e586
     if (check_event) {
d4e586
         uint32_t diff = (time(NULL) - begin);
d4e586
 
d4e586
-        if (callback_rc != -ETIME) {
d4e586
-            mainloop_test_done(FALSE);
d4e586
+        if (result.execution_status != PCMK_EXEC_TIMEOUT) {
d4e586
+            mainloop_test_done(__func__, false);
d4e586
         } else if (diff < CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT) {
d4e586
             crm_err
d4e586
                 ("Custom timeout test failed, callback expiration should be updated to %d, actual timeout was %d",
d4e586
                  CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT, diff);
d4e586
-            mainloop_test_done(FALSE);
d4e586
+            mainloop_test_done(__func__, false);
d4e586
         } else {
d4e586
-            mainloop_test_done(TRUE);
d4e586
+            mainloop_test_done(__func__, true);
d4e586
         }
d4e586
         return;
d4e586
     }
d4e586
@@ -448,7 +452,7 @@ test_async_fence_custom_timeout(int check_event)
d4e586
     rc = st->cmds->fence(st, 0, "custom_timeout_node1", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
d4e586
     if (rc < 0) {
d4e586
         crm_err("fence failed with rc %d", rc);
d4e586
-        mainloop_test_done(FALSE);
d4e586
+        mainloop_test_done(__func__, false);
d4e586
     }
d4e586
     register_callback_helper(rc);
d4e586
     /* wait for event */
d4e586
@@ -460,18 +464,15 @@ test_async_fence_timeout(int check_event)
d4e586
     int rc = 0;
d4e586
 
d4e586
     if (check_event) {
d4e586
-        if (callback_rc != -ENODEV) {
d4e586
-            mainloop_test_done(FALSE);
d4e586
-        } else {
d4e586
-            mainloop_test_done(TRUE);
d4e586
-        }
d4e586
+        mainloop_test_done(__func__,
d4e586
+                           (result.execution_status == PCMK_EXEC_NO_FENCE_DEVICE));
d4e586
         return;
d4e586
     }
d4e586
 
d4e586
     rc = st->cmds->fence(st, 0, "false_1_node2", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
d4e586
     if (rc < 0) {
d4e586
         crm_err("fence failed with rc %d", rc);
d4e586
-        mainloop_test_done(FALSE);
d4e586
+        mainloop_test_done(__func__, false);
d4e586
     }
d4e586
     register_callback_helper(rc);
d4e586
     /* wait for event */
d4e586
@@ -483,18 +484,14 @@ test_async_monitor(int check_event)
d4e586
     int rc = 0;
d4e586
 
d4e586
     if (check_event) {
d4e586
-        if (callback_rc) {
d4e586
-            mainloop_test_done(FALSE);
d4e586
-        } else {
d4e586
-            mainloop_test_done(TRUE);
d4e586
-        }
d4e586
+        mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
d4e586
         return;
d4e586
     }
d4e586
 
d4e586
     rc = st->cmds->monitor(st, 0, "false_1", MAINLOOP_DEFAULT_TIMEOUT);
d4e586
     if (rc < 0) {
d4e586
         crm_err("monitor failed with rc %d", rc);
d4e586
-        mainloop_test_done(FALSE);
d4e586
+        mainloop_test_done(__func__, false);
d4e586
     }
d4e586
 
d4e586
     register_callback_helper(rc);
d4e586
@@ -531,7 +528,7 @@ test_register_async_devices(int check_event)
d4e586
                               params);
d4e586
     stonith_key_value_freeall(params, 1, 1);
d4e586
 
d4e586
-    mainloop_test_done(TRUE);
d4e586
+    mainloop_test_done(__func__, true);
d4e586
 }
d4e586
 
d4e586
 static void
d4e586
@@ -540,11 +537,11 @@ try_mainloop_connect(int check_event)
d4e586
     int rc = stonith_api_connect_retry(st, crm_system_name, 10);
d4e586
 
d4e586
     if (rc == pcmk_ok) {
d4e586
-        mainloop_test_done(TRUE);
d4e586
+        mainloop_test_done(__func__, true);
d4e586
         return;
d4e586
     }
d4e586
     crm_err("API CONNECTION FAILURE");
d4e586
-    mainloop_test_done(FALSE);
d4e586
+    mainloop_test_done(__func__, false);
d4e586
 }
d4e586
 
d4e586
 static void
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 8ff4b384a34828a4a9eebe896324ba8c89e5d66c Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 10 Jan 2022 10:27:45 -0600
d4e586
Subject: [PATCH 13/17] Doc: Pacemaker Development: correct typo
d4e586
d4e586
caught in review
d4e586
---
d4e586
 doc/sphinx/Pacemaker_Development/components.rst | 2 +-
d4e586
 1 file changed, 1 insertion(+), 1 deletion(-)
d4e586
d4e586
diff --git a/doc/sphinx/Pacemaker_Development/components.rst b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
index 68158484ce..c4d10fc9f5 100644
d4e586
--- a/doc/sphinx/Pacemaker_Development/components.rst
d4e586
+++ b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
@@ -171,7 +171,7 @@ messaging layer callback, which calls:
d4e586
 
d4e586
     * ``fenced_process_fencing_reply()``, which calls either
d4e586
       ``request_peer_fencing()`` (to retry a failed operation, or try the next
d4e586
-      device in a topology is appropriate, which issues a new
d4e586
+      device in a topology if appropriate, which issues a new
d4e586
       ``STONITH_OP_FENCE`` request, proceeding as before) or
d4e586
       ``finalize_op()`` (if the operation is definitively failed or
d4e586
       successful).
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 822ee6fbd8583a2939c636b3bccceffcc338c567 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 10 Jan 2022 11:05:40 -0600
d4e586
Subject: [PATCH 14/17] Doc: Pacemaker Development: add a placeholder for how
d4e586
 fencing history works
d4e586
d4e586
---
d4e586
 doc/sphinx/Pacemaker_Development/components.rst | 15 +++++++++++++++
d4e586
 1 file changed, 15 insertions(+)
d4e586
d4e586
diff --git a/doc/sphinx/Pacemaker_Development/components.rst b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
index c4d10fc9f5..760da77c9b 100644
d4e586
--- a/doc/sphinx/Pacemaker_Development/components.rst
d4e586
+++ b/doc/sphinx/Pacemaker_Development/components.rst
d4e586
@@ -183,6 +183,21 @@ Finally, all peers receive the broadcast result and call
d4e586
 * ``finalize_op()``, which sends the result to all local clients.
d4e586
 
d4e586
 
d4e586
+.. index::
d4e586
+   single: fence history
d4e586
+
d4e586
+Fencing History
d4e586
+_______________
d4e586
+
d4e586
+The fencer keeps a running history of all fencing operations. The bulk of the
d4e586
+relevant code is in `fenced_history.c` and ensures the history is synchronized
d4e586
+across all nodes even if a node leaves and rejoins the cluster.
d4e586
+
d4e586
+In libstonithd, this information is represented by `stonith_history_t` and is
d4e586
+queryable by the `stonith_api_operations_t:history()` method. `crm_mon` and
d4e586
+`stonith_admin` use this API to display the history.
d4e586
+
d4e586
+
d4e586
 .. index::
d4e586
    single: scheduler
d4e586
    single: pacemaker-schedulerd
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From d9b4060f2dadb40d5ee7535e0b2890a83d216c1e Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Mon, 10 Jan 2022 11:25:31 -0600
d4e586
Subject: [PATCH 15/17] Log: fencing: add exit reason for results without a
d4e586
 callback
d4e586
d4e586
---
d4e586
 lib/fencing/st_client.c | 6 ++++--
d4e586
 1 file changed, 4 insertions(+), 2 deletions(-)
d4e586
d4e586
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
d4e586
index 9d93ffd481..4823751267 100644
d4e586
--- a/lib/fencing/st_client.c
d4e586
+++ b/lib/fencing/st_client.c
d4e586
@@ -926,9 +926,11 @@ invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
d4e586
                                      cb_info->user_data, cb_info->callback);
d4e586
 
d4e586
     } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
d4e586
-        crm_warn("Fencing action without registered callback failed: %d (%s)",
d4e586
+        crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
d4e586
                  result.exit_status,
d4e586
-                 pcmk_exec_status_str(result.execution_status));
d4e586
+                 pcmk_exec_status_str(result.execution_status),
d4e586
+                 ((result.exit_reason == NULL)? "" : ": "),
d4e586
+                 ((result.exit_reason == NULL)? "" : result.exit_reason));
d4e586
         crm_log_xml_debug(msg, "Failed fence update");
d4e586
     }
d4e586
 
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 9956b3ad2f1c6fba305252616ad0b35a38ab96da Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Tue, 11 Jan 2022 09:28:27 -0600
d4e586
Subject: [PATCH 16/17] Refactor: executor: keep formatting consistent
d4e586
d4e586
... even if the line runs a little long
d4e586
---
d4e586
 daemons/execd/execd_commands.c | 4 ++--
d4e586
 1 file changed, 2 insertions(+), 2 deletions(-)
d4e586
d4e586
diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c
d4e586
index 7ae309d94c..bc3b392b2c 100644
d4e586
--- a/daemons/execd/execd_commands.c
d4e586
+++ b/daemons/execd/execd_commands.c
d4e586
@@ -1,5 +1,5 @@
d4e586
 /*
d4e586
- * Copyright 2012-2021 the Pacemaker project contributors
d4e586
+ * Copyright 2012-2022 the Pacemaker project contributors
d4e586
  *
d4e586
  * The version control history for this file may have further details.
d4e586
  *
d4e586
@@ -1297,7 +1297,7 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
d4e586
     stonith_action_complete(cmd,
d4e586
                             ((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR),
d4e586
                             stonith__legacy2status(rc),
d4e586
-                            rc == -pcmk_err_generic? NULL : pcmk_strerror(rc));
d4e586
+                            ((rc == -pcmk_err_generic)? NULL : pcmk_strerror(rc)));
d4e586
 }
d4e586
 
d4e586
 static int
d4e586
-- 
d4e586
2.27.0
d4e586
d4e586
d4e586
From 69d8ecb17568d6c3ecad0e5735756f58a4bce5a1 Mon Sep 17 00:00:00 2001
d4e586
From: Ken Gaillot <kgaillot@redhat.com>
d4e586
Date: Tue, 11 Jan 2022 09:29:03 -0600
d4e586
Subject: [PATCH 17/17] Test: cts-fence-helper: use more intuitive execution
d4e586
 status for completed tests
d4e586
d4e586
It doesn't matter since the value is only checked against a couple of specific
d4e586
failure values, but this is less confusing.
d4e586
---
d4e586
 daemons/fenced/cts-fence-helper.c | 4 ++--
d4e586
 1 file changed, 2 insertions(+), 2 deletions(-)
d4e586
d4e586
diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c
d4e586
index 2739f57804..e222a59f9f 100644
d4e586
--- a/daemons/fenced/cts-fence-helper.c
d4e586
+++ b/daemons/fenced/cts-fence-helper.c
d4e586
@@ -1,5 +1,5 @@
d4e586
 /*
d4e586
- * Copyright 2009-2021 the Pacemaker project contributors
d4e586
+ * Copyright 2009-2022 the Pacemaker project contributors
d4e586
  *
d4e586
  * This source code is licensed under the GNU General Public License version 2
d4e586
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
d4e586
@@ -89,7 +89,7 @@ mainloop_test_done(const char *origin, bool pass)
d4e586
         crm_info("SUCCESS - %s", origin);
d4e586
         mainloop_iter++;
d4e586
         mainloop_set_trigger(trig);
d4e586
-        result.execution_status = PCMK_EXEC_UNKNOWN;
d4e586
+        result.execution_status = PCMK_EXEC_DONE;
d4e586
         result.exit_status = CRM_EX_OK;
d4e586
     } else {
d4e586
         crm_err("FAILURE - %s (%d: %s)", origin, result.exit_status,
d4e586
-- 
d4e586
2.27.0
d4e586