Blame SOURCES/005-fencing-reasons.patch

0aa0b6
From 3d10dad9a555aae040d8473edfe31a4e4279c066 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 11 Nov 2021 12:34:03 -0600
0aa0b6
Subject: [PATCH 01/19] Refactor: libcrmcommon: add internal API for checking
0aa0b6
 for fencing action
0aa0b6
0aa0b6
The naming is a little awkward -- "fencing action" has multiple meanings
0aa0b6
depending on the context. It can refer to fencer API requests, fence device
0aa0b6
actions, fence agent actions, or just those actions that fence a node (off and
0aa0b6
reboot).
0aa0b6
0aa0b6
This new function pcmk__is_fencing_action() uses the last meaning, so it does
0aa0b6
*not* return true for unfencing ("on" actions).
0aa0b6
---
0aa0b6
 include/crm/common/internal.h |  1 +
0aa0b6
 lib/common/operations.c       | 14 ++++++++++++++
0aa0b6
 2 files changed, 15 insertions(+)
0aa0b6
0aa0b6
diff --git a/include/crm/common/internal.h b/include/crm/common/internal.h
0aa0b6
index a35c5769a..694fc6cd4 100644
0aa0b6
--- a/include/crm/common/internal.h
0aa0b6
+++ b/include/crm/common/internal.h
0aa0b6
@@ -218,6 +218,7 @@ char *pcmk__notify_key(const char *rsc_id, const char *notify_type,
0aa0b6
 char *pcmk__transition_key(int transition_id, int action_id, int target_rc,
0aa0b6
                            const char *node);
0aa0b6
 void pcmk__filter_op_for_digest(xmlNode *param_set);
0aa0b6
+bool pcmk__is_fencing_action(const char *action);
0aa0b6
 
0aa0b6
 
0aa0b6
 // bitwise arithmetic utilities
0aa0b6
diff --git a/lib/common/operations.c b/lib/common/operations.c
0aa0b6
index aa7106ce6..366c18970 100644
0aa0b6
--- a/lib/common/operations.c
0aa0b6
+++ b/lib/common/operations.c
0aa0b6
@@ -523,3 +523,17 @@ crm_op_needs_metadata(const char *rsc_class, const char *op)
0aa0b6
                             CRMD_ACTION_MIGRATE, CRMD_ACTION_MIGRATED,
0aa0b6
                             CRMD_ACTION_NOTIFY, NULL);
0aa0b6
 }
0aa0b6
+
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Check whether an action name is for a fencing action
0aa0b6
+ *
0aa0b6
+ * \param[in] action  Action name to check
0aa0b6
+ *
0aa0b6
+ * \return true if \p action is "off", "reboot", or "poweroff", otherwise false
0aa0b6
+ */
0aa0b6
+bool
0aa0b6
+pcmk__is_fencing_action(const char *action)
0aa0b6
+{
0aa0b6
+    return pcmk__str_any_of(action, "off", "reboot", "poweroff", NULL);
0aa0b6
+}
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 86ac00fb3e99d79ca2c442ae1670fe850146f734 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 11 Nov 2021 12:38:58 -0600
0aa0b6
Subject: [PATCH 02/19] Low: fencer,scheduler: compare fence action names
0aa0b6
 case-sensitively
0aa0b6
0aa0b6
Use the new convenience function pcmk__is_fencing_action() to check whether
0aa0b6
an action name is a fencing action ("off", "reboot", or "poweroff"). This
0aa0b6
changes the behavior from case-insensitive to case-sensitive, which is more
0aa0b6
appropriate (the case-insensitivity was inherited from lazy use of the old
0aa0b6
safe_str_eq() function which was always case-insensitive).
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c    | 6 +++---
0aa0b6
 daemons/fenced/fenced_remote.c      | 2 +-
0aa0b6
 lib/pacemaker/pcmk_graph_producer.c | 2 +-
0aa0b6
 lib/pengine/common.c                | 8 +-------
0aa0b6
 4 files changed, 6 insertions(+), 12 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 63bfad3a9..46c840f2a 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -128,7 +128,7 @@ get_action_delay_max(stonith_device_t * device, const char * action)
0aa0b6
     const char *value = NULL;
0aa0b6
     int delay_max = 0;
0aa0b6
 
0aa0b6
-    if (!pcmk__strcase_any_of(action, "off", "reboot", NULL)) {
0aa0b6
+    if (!pcmk__is_fencing_action(action)) {
0aa0b6
         return 0;
0aa0b6
     }
0aa0b6
 
0aa0b6
@@ -146,7 +146,7 @@ get_action_delay_base(stonith_device_t *device, const char *action, const char *
0aa0b6
     char *hash_value = NULL;
0aa0b6
     int delay_base = 0;
0aa0b6
 
0aa0b6
-    if (!pcmk__strcase_any_of(action, "off", "reboot", NULL)) {
0aa0b6
+    if (!pcmk__is_fencing_action(action)) {
0aa0b6
         return 0;
0aa0b6
     }
0aa0b6
 
0aa0b6
@@ -448,7 +448,7 @@ stonith_device_execute(stonith_device_t * device)
0aa0b6
 
0aa0b6
     if (pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT,
0aa0b6
                          STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) {
0aa0b6
-        if (pcmk__strcase_any_of(cmd->action, "reboot", "off", NULL)) {
0aa0b6
+        if (pcmk__is_fencing_action(cmd->action)) {
0aa0b6
             if (node_does_watchdog_fencing(stonith_our_uname)) {
0aa0b6
                 pcmk__panic(__func__);
0aa0b6
                 goto done;
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 963433bf3..358ea3aa7 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -1758,7 +1758,7 @@ all_topology_devices_found(remote_fencing_op_t * op)
0aa0b6
     if (!tp) {
0aa0b6
         return FALSE;
0aa0b6
     }
0aa0b6
-    if (pcmk__strcase_any_of(op->action, "off", "reboot", NULL)) {
0aa0b6
+    if (pcmk__is_fencing_action(op->action)) {
0aa0b6
         /* Don't count the devices on the target node if we are killing
0aa0b6
          * the target node. */
0aa0b6
         skip_target = TRUE;
0aa0b6
diff --git a/lib/pacemaker/pcmk_graph_producer.c b/lib/pacemaker/pcmk_graph_producer.c
0aa0b6
index ffcbd1274..5bec9d8ce 100644
0aa0b6
--- a/lib/pacemaker/pcmk_graph_producer.c
0aa0b6
+++ b/lib/pacemaker/pcmk_graph_producer.c
0aa0b6
@@ -721,7 +721,7 @@ add_downed_nodes(xmlNode *xml, const pe_action_t *action,
0aa0b6
         /* Fencing makes the action's node and any hosted guest nodes down */
0aa0b6
         const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
0aa0b6
 
0aa0b6
-        if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
0aa0b6
+        if (pcmk__is_fencing_action(fence)) {
0aa0b6
             xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
0aa0b6
             add_node_to_xml_by_id(action->node->details->id, downed);
0aa0b6
             pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
0aa0b6
diff --git a/lib/pengine/common.c b/lib/pengine/common.c
0aa0b6
index 236fc26b1..fe4223816 100644
0aa0b6
--- a/lib/pengine/common.c
0aa0b6
+++ b/lib/pengine/common.c
0aa0b6
@@ -27,12 +27,6 @@ check_health(const char *value)
0aa0b6
                            "migrate-on-red", NULL);
0aa0b6
 }
0aa0b6
 
0aa0b6
-static bool
0aa0b6
-check_stonith_action(const char *value)
0aa0b6
-{
0aa0b6
-    return pcmk__strcase_any_of(value, "reboot", "poweroff", "off", NULL);
0aa0b6
-}
0aa0b6
-
0aa0b6
 static bool
0aa0b6
 check_placement_strategy(const char *value)
0aa0b6
 {
0aa0b6
@@ -114,7 +108,7 @@ static pcmk__cluster_option_t pe_opts[] = {
0aa0b6
     },
0aa0b6
     {
0aa0b6
         "stonith-action", NULL, "select", "reboot, off, poweroff",
0aa0b6
-        "reboot", check_stonith_action,
0aa0b6
+        "reboot", pcmk__is_fencing_action,
0aa0b6
         "Action to send to fence device when a node needs to be fenced "
0aa0b6
             "(\"poweroff\" is a deprecated alias for \"off\")",
0aa0b6
         NULL
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From c8f6e8a04c4fa4271db817af0a23aa941c9d7689 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Fri, 12 Nov 2021 17:42:21 -0600
0aa0b6
Subject: [PATCH 03/19] Refactor: fencing: rename type for peer query replies
0aa0b6
0aa0b6
st_query_result_t contains the device information parsed from a peer's query
0aa0b6
reply, but the name could easily be confused with the actual success/failure
0aa0b6
result of the query action itself. Rename it to peer_device_info_t.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_remote.c | 103 +++++++++++++++++----------------
0aa0b6
 1 file changed, 52 insertions(+), 51 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 358ea3aa7..9e2f62804 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -41,7 +41,7 @@
0aa0b6
 
0aa0b6
 /* When one fencer queries its peers for devices able to handle a fencing
0aa0b6
  * request, each peer will reply with a list of such devices available to it.
0aa0b6
- * Each reply will be parsed into a st_query_result_t, with each device's
0aa0b6
+ * Each reply will be parsed into a peer_device_info_t, with each device's
0aa0b6
  * information kept in a device_properties_t.
0aa0b6
  */
0aa0b6
 
0aa0b6
@@ -72,18 +72,19 @@ typedef struct st_query_result_s {
0aa0b6
     int ndevices;
0aa0b6
     /* Devices available to this host that are capable of fencing the target */
0aa0b6
     GHashTable *devices;
0aa0b6
-} st_query_result_t;
0aa0b6
+} peer_device_info_t;
0aa0b6
 
0aa0b6
 GHashTable *stonith_remote_op_list = NULL;
0aa0b6
 
0aa0b6
-void call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc);
0aa0b6
+void call_remote_stonith(remote_fencing_op_t *op, peer_device_info_t *peer,
0aa0b6
+                         int rc);
0aa0b6
 static void remote_op_done(remote_fencing_op_t * op, xmlNode * data, int rc, int dup);
0aa0b6
 extern xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
0aa0b6
                                   int call_options);
0aa0b6
 
0aa0b6
 static void report_timeout_period(remote_fencing_op_t * op, int op_timeout);
0aa0b6
 static int get_op_total_timeout(const remote_fencing_op_t *op,
0aa0b6
-                                const st_query_result_t *chosen_peer);
0aa0b6
+                                const peer_device_info_t *chosen_peer);
0aa0b6
 
0aa0b6
 static gint
0aa0b6
 sort_strings(gconstpointer a, gconstpointer b)
0aa0b6
@@ -95,7 +96,7 @@ static void
0aa0b6
 free_remote_query(gpointer data)
0aa0b6
 {
0aa0b6
     if (data) {
0aa0b6
-        st_query_result_t *query = data;
0aa0b6
+        peer_device_info_t *query = data;
0aa0b6
 
0aa0b6
         crm_trace("Free'ing query result from %s", query->host);
0aa0b6
         g_hash_table_destroy(query->devices);
0aa0b6
@@ -150,8 +151,8 @@ count_peer_device(gpointer key, gpointer value, gpointer user_data)
0aa0b6
  * \return Number of devices available to peer that were not already executed
0aa0b6
  */
0aa0b6
 static int
0aa0b6
-count_peer_devices(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
-                   gboolean verified_only)
0aa0b6
+count_peer_devices(const remote_fencing_op_t *op,
0aa0b6
+                   const peer_device_info_t *peer, gboolean verified_only)
0aa0b6
 {
0aa0b6
     struct peer_count_data data;
0aa0b6
 
0aa0b6
@@ -175,7 +176,7 @@ count_peer_devices(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
  * \return Device properties if found, NULL otherwise
0aa0b6
  */
0aa0b6
 static device_properties_t *
0aa0b6
-find_peer_device(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
+find_peer_device(const remote_fencing_op_t *op, const peer_device_info_t *peer,
0aa0b6
                  const char *device)
0aa0b6
 {
0aa0b6
     device_properties_t *props = g_hash_table_lookup(peer->devices, device);
0aa0b6
@@ -196,7 +197,7 @@ find_peer_device(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
  * \return TRUE if device was found and marked, FALSE otherwise
0aa0b6
  */
0aa0b6
 static gboolean
0aa0b6
-grab_peer_device(const remote_fencing_op_t *op, st_query_result_t *peer,
0aa0b6
+grab_peer_device(const remote_fencing_op_t *op, peer_device_info_t *peer,
0aa0b6
                  const char *device, gboolean verified_devices_only)
0aa0b6
 {
0aa0b6
     device_properties_t *props = find_peer_device(op, peer, device);
0aa0b6
@@ -1216,7 +1217,7 @@ enum find_best_peer_options {
0aa0b6
     FIND_PEER_VERIFIED_ONLY = 0x0004,
0aa0b6
 };
0aa0b6
 
0aa0b6
-static st_query_result_t *
0aa0b6
+static peer_device_info_t *
0aa0b6
 find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer_options options)
0aa0b6
 {
0aa0b6
     GList *iter = NULL;
0aa0b6
@@ -1227,7 +1228,7 @@ find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer
0aa0b6
     }
0aa0b6
 
0aa0b6
     for (iter = op->query_results; iter != NULL; iter = iter->next) {
0aa0b6
-        st_query_result_t *peer = iter->data;
0aa0b6
+        peer_device_info_t *peer = iter->data;
0aa0b6
 
0aa0b6
         crm_trace("Testing result from %s targeting %s with %d device%s: %d %x",
0aa0b6
                   peer->host, op->target, peer->ndevices,
0aa0b6
@@ -1257,11 +1258,11 @@ find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer
0aa0b6
     return NULL;
0aa0b6
 }
0aa0b6
 
0aa0b6
-static st_query_result_t *
0aa0b6
+static peer_device_info_t *
0aa0b6
 stonith_choose_peer(remote_fencing_op_t * op)
0aa0b6
 {
0aa0b6
     const char *device = NULL;
0aa0b6
-    st_query_result_t *peer = NULL;
0aa0b6
+    peer_device_info_t *peer = NULL;
0aa0b6
     uint32_t active = fencing_active_peers();
0aa0b6
 
0aa0b6
     do {
0aa0b6
@@ -1317,8 +1318,8 @@ stonith_choose_peer(remote_fencing_op_t * op)
0aa0b6
 }
0aa0b6
 
0aa0b6
 static int
0aa0b6
-get_device_timeout(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
-                   const char *device)
0aa0b6
+get_device_timeout(const remote_fencing_op_t *op,
0aa0b6
+                   const peer_device_info_t *peer, const char *device)
0aa0b6
 {
0aa0b6
     device_properties_t *props;
0aa0b6
 
0aa0b6
@@ -1338,7 +1339,7 @@ get_device_timeout(const remote_fencing_op_t *op, const st_query_result_t *peer,
0aa0b6
 
0aa0b6
 struct timeout_data {
0aa0b6
     const remote_fencing_op_t *op;
0aa0b6
-    const st_query_result_t *peer;
0aa0b6
+    const peer_device_info_t *peer;
0aa0b6
     int total_timeout;
0aa0b6
 };
0aa0b6
 
0aa0b6
@@ -1365,7 +1366,7 @@ add_device_timeout(gpointer key, gpointer value, gpointer user_data)
0aa0b6
 }
0aa0b6
 
0aa0b6
 static int
0aa0b6
-get_peer_timeout(const remote_fencing_op_t *op, const st_query_result_t *peer)
0aa0b6
+get_peer_timeout(const remote_fencing_op_t *op, const peer_device_info_t *peer)
0aa0b6
 {
0aa0b6
     struct timeout_data timeout;
0aa0b6
 
0aa0b6
@@ -1380,7 +1381,7 @@ get_peer_timeout(const remote_fencing_op_t *op, const st_query_result_t *peer)
0aa0b6
 
0aa0b6
 static int
0aa0b6
 get_op_total_timeout(const remote_fencing_op_t *op,
0aa0b6
-                     const st_query_result_t *chosen_peer)
0aa0b6
+                     const peer_device_info_t *chosen_peer)
0aa0b6
 {
0aa0b6
     int total_timeout = 0;
0aa0b6
     stonith_topology_t *tp = find_topology_for_host(op->target);
0aa0b6
@@ -1403,7 +1404,7 @@ get_op_total_timeout(const remote_fencing_op_t *op,
0aa0b6
             }
0aa0b6
             for (device_list = tp->levels[i]; device_list; device_list = device_list->next) {
0aa0b6
                 for (iter = op->query_results; iter != NULL; iter = iter->next) {
0aa0b6
-                    const st_query_result_t *peer = iter->data;
0aa0b6
+                    const peer_device_info_t *peer = iter->data;
0aa0b6
 
0aa0b6
                     if (find_peer_device(op, peer, device_list->data)) {
0aa0b6
                         total_timeout += get_device_timeout(op, peer,
0aa0b6
@@ -1555,7 +1556,7 @@ check_watchdog_fencing_and_wait(remote_fencing_op_t * op)
0aa0b6
 }
0aa0b6
 
0aa0b6
 void
0aa0b6
-call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc)
0aa0b6
+call_remote_stonith(remote_fencing_op_t *op, peer_device_info_t *peer, int rc)
0aa0b6
 {
0aa0b6
     const char *device = NULL;
0aa0b6
     int timeout = op->base_timeout;
0aa0b6
@@ -1734,8 +1735,8 @@ call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc)
0aa0b6
 static gint
0aa0b6
 sort_peers(gconstpointer a, gconstpointer b)
0aa0b6
 {
0aa0b6
-    const st_query_result_t *peer_a = a;
0aa0b6
-    const st_query_result_t *peer_b = b;
0aa0b6
+    const peer_device_info_t *peer_a = a;
0aa0b6
+    const peer_device_info_t *peer_b = b;
0aa0b6
 
0aa0b6
     return (peer_b->ndevices - peer_a->ndevices);
0aa0b6
 }
0aa0b6
@@ -1768,7 +1769,7 @@ all_topology_devices_found(remote_fencing_op_t * op)
0aa0b6
         for (device = tp->levels[i]; device; device = device->next) {
0aa0b6
             match = NULL;
0aa0b6
             for (iter = op->query_results; iter && !match; iter = iter->next) {
0aa0b6
-                st_query_result_t *peer = iter->data;
0aa0b6
+                peer_device_info_t *peer = iter->data;
0aa0b6
 
0aa0b6
                 if (skip_target && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
0aa0b6
                     continue;
0aa0b6
@@ -1850,31 +1851,31 @@ parse_action_specific(xmlNode *xml, const char *peer, const char *device,
0aa0b6
  *
0aa0b6
  * \param[in]     xml       XML node containing device properties
0aa0b6
  * \param[in,out] op        Operation that query and reply relate to
0aa0b6
- * \param[in,out] result    Peer's results
0aa0b6
+ * \param[in,out] peer      Peer's device information
0aa0b6
  * \param[in]     device    ID of device being parsed
0aa0b6
  */
0aa0b6
 static void
0aa0b6
 add_device_properties(xmlNode *xml, remote_fencing_op_t *op,
0aa0b6
-                      st_query_result_t *result, const char *device)
0aa0b6
+                      peer_device_info_t *peer, const char *device)
0aa0b6
 {
0aa0b6
     xmlNode *child;
0aa0b6
     int verified = 0;
0aa0b6
     device_properties_t *props = calloc(1, sizeof(device_properties_t));
0aa0b6
 
0aa0b6
-    /* Add a new entry to this result's devices list */
0aa0b6
+    /* Add a new entry to this peer's devices list */
0aa0b6
     CRM_ASSERT(props != NULL);
0aa0b6
-    g_hash_table_insert(result->devices, strdup(device), props);
0aa0b6
+    g_hash_table_insert(peer->devices, strdup(device), props);
0aa0b6
 
0aa0b6
     /* Peers with verified (monitored) access will be preferred */
0aa0b6
     crm_element_value_int(xml, F_STONITH_DEVICE_VERIFIED, &verified);
0aa0b6
     if (verified) {
0aa0b6
         crm_trace("Peer %s has confirmed a verified device %s",
0aa0b6
-                  result->host, device);
0aa0b6
+                  peer->host, device);
0aa0b6
         props->verified = TRUE;
0aa0b6
     }
0aa0b6
 
0aa0b6
     /* Parse action-specific device properties */
0aa0b6
-    parse_action_specific(xml, result->host, device, op_requested_action(op),
0aa0b6
+    parse_action_specific(xml, peer->host, device, op_requested_action(op),
0aa0b6
                           op, st_phase_requested, props);
0aa0b6
     for (child = pcmk__xml_first_child(xml); child != NULL;
0aa0b6
          child = pcmk__xml_next(child)) {
0aa0b6
@@ -1883,10 +1884,10 @@ add_device_properties(xmlNode *xml, remote_fencing_op_t *op,
0aa0b6
          * winds up getting remapped.
0aa0b6
          */
0aa0b6
         if (pcmk__str_eq(ID(child), "off", pcmk__str_casei)) {
0aa0b6
-            parse_action_specific(child, result->host, device, "off",
0aa0b6
+            parse_action_specific(child, peer->host, device, "off",
0aa0b6
                                   op, st_phase_off, props);
0aa0b6
         } else if (pcmk__str_eq(ID(child), "on", pcmk__str_casei)) {
0aa0b6
-            parse_action_specific(child, result->host, device, "on",
0aa0b6
+            parse_action_specific(child, peer->host, device, "on",
0aa0b6
                                   op, st_phase_on, props);
0aa0b6
         }
0aa0b6
     }
0aa0b6
@@ -1903,17 +1904,17 @@ add_device_properties(xmlNode *xml, remote_fencing_op_t *op,
0aa0b6
  *
0aa0b6
  * \return Newly allocated result structure with parsed reply
0aa0b6
  */
0aa0b6
-static st_query_result_t *
0aa0b6
+static peer_device_info_t *
0aa0b6
 add_result(remote_fencing_op_t *op, const char *host, int ndevices, xmlNode *xml)
0aa0b6
 {
0aa0b6
-    st_query_result_t *result = calloc(1, sizeof(st_query_result_t));
0aa0b6
+    peer_device_info_t *peer = calloc(1, sizeof(peer_device_info_t));
0aa0b6
     xmlNode *child;
0aa0b6
 
0aa0b6
     // cppcheck seems not to understand the abort logic in CRM_CHECK
0aa0b6
     // cppcheck-suppress memleak
0aa0b6
-    CRM_CHECK(result != NULL, return NULL);
0aa0b6
-    result->host = strdup(host);
0aa0b6
-    result->devices = pcmk__strkey_table(free, free);
0aa0b6
+    CRM_CHECK(peer != NULL, return NULL);
0aa0b6
+    peer->host = strdup(host);
0aa0b6
+    peer->devices = pcmk__strkey_table(free, free);
0aa0b6
 
0aa0b6
     /* Each child element describes one capable device available to the peer */
0aa0b6
     for (child = pcmk__xml_first_child(xml); child != NULL;
0aa0b6
@@ -1921,17 +1922,17 @@ add_result(remote_fencing_op_t *op, const char *host, int ndevices, xmlNode *xml
0aa0b6
         const char *device = ID(child);
0aa0b6
 
0aa0b6
         if (device) {
0aa0b6
-            add_device_properties(child, op, result, device);
0aa0b6
+            add_device_properties(child, op, peer, device);
0aa0b6
         }
0aa0b6
     }
0aa0b6
 
0aa0b6
-    result->ndevices = g_hash_table_size(result->devices);
0aa0b6
-    CRM_CHECK(ndevices == result->ndevices,
0aa0b6
+    peer->ndevices = g_hash_table_size(peer->devices);
0aa0b6
+    CRM_CHECK(ndevices == peer->ndevices,
0aa0b6
               crm_err("Query claimed to have %d device%s but %d found",
0aa0b6
-                      ndevices, pcmk__plural_s(ndevices), result->ndevices));
0aa0b6
+                      ndevices, pcmk__plural_s(ndevices), peer->ndevices));
0aa0b6
 
0aa0b6
-    op->query_results = g_list_insert_sorted(op->query_results, result, sort_peers);
0aa0b6
-    return result;
0aa0b6
+    op->query_results = g_list_insert_sorted(op->query_results, peer, sort_peers);
0aa0b6
+    return peer;
0aa0b6
 }
0aa0b6
 
0aa0b6
 /*!
0aa0b6
@@ -1957,7 +1958,7 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
     const char *id = NULL;
0aa0b6
     const char *host = NULL;
0aa0b6
     remote_fencing_op_t *op = NULL;
0aa0b6
-    st_query_result_t *result = NULL;
0aa0b6
+    peer_device_info_t *peer = NULL;
0aa0b6
     uint32_t replies_expected;
0aa0b6
     xmlNode *dev = get_xpath_object("//@" F_STONITH_REMOTE_OP_ID, msg, LOG_ERR);
0aa0b6
 
0aa0b6
@@ -1991,7 +1992,7 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
              op->replies, replies_expected, host,
0aa0b6
              op->target, op->action, ndevices, pcmk__plural_s(ndevices), id);
0aa0b6
     if (ndevices > 0) {
0aa0b6
-        result = add_result(op, host, ndevices, dev);
0aa0b6
+        peer = add_result(op, host, ndevices, dev);
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (pcmk_is_set(op->call_options, st_opt_topology)) {
0aa0b6
@@ -2001,7 +2002,7 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
         if (op->state == st_query && all_topology_devices_found(op)) {
0aa0b6
             /* All the query results are in for the topology, start the fencing ops. */
0aa0b6
             crm_trace("All topology devices found");
0aa0b6
-            call_remote_stonith(op, result, pcmk_ok);
0aa0b6
+            call_remote_stonith(op, peer, pcmk_ok);
0aa0b6
 
0aa0b6
         } else if (have_all_replies) {
0aa0b6
             crm_info("All topology query replies have arrived, continuing (%d expected/%d received) ",
0aa0b6
@@ -2010,15 +2011,15 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
         }
0aa0b6
 
0aa0b6
     } else if (op->state == st_query) {
0aa0b6
-        int nverified = count_peer_devices(op, result, TRUE);
0aa0b6
+        int nverified = count_peer_devices(op, peer, TRUE);
0aa0b6
 
0aa0b6
         /* We have a result for a non-topology fencing op that looks promising,
0aa0b6
          * go ahead and start fencing before query timeout */
0aa0b6
-        if (result && (host_is_target == FALSE) && nverified) {
0aa0b6
+        if ((peer != NULL) && !host_is_target && nverified) {
0aa0b6
             /* we have a verified device living on a peer that is not the target */
0aa0b6
             crm_trace("Found %d verified device%s",
0aa0b6
                       nverified, pcmk__plural_s(nverified));
0aa0b6
-            call_remote_stonith(op, result, pcmk_ok);
0aa0b6
+            call_remote_stonith(op, peer, pcmk_ok);
0aa0b6
 
0aa0b6
         } else if (have_all_replies) {
0aa0b6
             crm_info("All query replies have arrived, continuing (%d expected/%d received) ",
0aa0b6
@@ -2029,10 +2030,10 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
             crm_trace("Waiting for more peer results before launching fencing operation");
0aa0b6
         }
0aa0b6
 
0aa0b6
-    } else if (result && (op->state == st_done)) {
0aa0b6
+    } else if ((peer != NULL) && (op->state == st_done)) {
0aa0b6
         crm_info("Discarding query result from %s (%d device%s): "
0aa0b6
-                 "Operation is %s", result->host,
0aa0b6
-                 result->ndevices, pcmk__plural_s(result->ndevices),
0aa0b6
+                 "Operation is %s", peer->host,
0aa0b6
+                 peer->ndevices, pcmk__plural_s(peer->ndevices),
0aa0b6
                  stonith_op_state_str(op->state));
0aa0b6
     }
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 913e0620310089d2250e9ecde383df757f8e8063 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 11 Nov 2021 12:46:37 -0600
0aa0b6
Subject: [PATCH 04/19] Low: fencer: improve broadcasting replies for fenced
0aa0b6
 originators
0aa0b6
0aa0b6
If the target of a fencing action was also the originator, the executioner
0aa0b6
broadcasts the result on their behalf.
0aa0b6
0aa0b6
Previously, it would check if the action was not in a list of actions that are
0aa0b6
never broadcasted. However we really only want to broadcast off/reboot results
0aa0b6
so just check for that instead.
0aa0b6
0aa0b6
This also rearranges reply creation slightly so we don't trace-log the reply
0aa0b6
until it is fully created.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 19 +++++++++----------
0aa0b6
 1 file changed, 9 insertions(+), 10 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 46c840f2a..e4185f6e1 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2385,32 +2385,31 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
0aa0b6
                  int pid, bool merged)
0aa0b6
 {
0aa0b6
     xmlNode *reply = NULL;
0aa0b6
-    gboolean bcast = FALSE;
0aa0b6
+    bool bcast = false;
0aa0b6
 
0aa0b6
     CRM_CHECK((cmd != NULL) && (result != NULL), return);
0aa0b6
 
0aa0b6
     reply = construct_async_reply(cmd, result);
0aa0b6
 
0aa0b6
-    // Only replies for certain actions are broadcast
0aa0b6
-    if (pcmk__str_any_of(cmd->action, "metadata", "monitor", "list", "status",
0aa0b6
-                         NULL)) {
0aa0b6
-        crm_trace("Never broadcast '%s' replies", cmd->action);
0aa0b6
+    // If target was also the originator, broadcast fencing results for it
0aa0b6
+    if (!stand_alone && pcmk__is_fencing_action(cmd->action)
0aa0b6
+        && pcmk__str_eq(cmd->origin, cmd->victim, pcmk__str_casei)) {
0aa0b6
 
0aa0b6
-    } else if (!stand_alone && pcmk__str_eq(cmd->origin, cmd->victim, pcmk__str_casei) && !pcmk__str_eq(cmd->action, "on", pcmk__str_casei)) {
0aa0b6
-        crm_trace("Broadcast '%s' reply for %s", cmd->action, cmd->victim);
0aa0b6
+        crm_trace("Broadcast '%s' result for %s (target was also originator)",
0aa0b6
+                  cmd->action, cmd->victim);
0aa0b6
         crm_xml_add(reply, F_SUBTYPE, "broadcast");
0aa0b6
-        bcast = TRUE;
0aa0b6
+        crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY);
0aa0b6
+        bcast = true;
0aa0b6
     }
0aa0b6
 
0aa0b6
     log_async_result(cmd, result, pid, NULL, merged);
0aa0b6
-    crm_log_xml_trace(reply, "Reply");
0aa0b6
 
0aa0b6
     if (merged) {
0aa0b6
         crm_xml_add(reply, F_STONITH_MERGED, "true");
0aa0b6
     }
0aa0b6
+    crm_log_xml_trace(reply, "Reply");
0aa0b6
 
0aa0b6
     if (bcast) {
0aa0b6
-        crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY);
0aa0b6
         send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE);
0aa0b6
 
0aa0b6
     } else if (cmd->origin) {
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 8b8f94fd9ca5e61922cb81e32c8a3d0f1d75fb0b Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 11 Nov 2021 14:40:49 -0600
0aa0b6
Subject: [PATCH 05/19] Refactor: fencer: avoid code duplication when sending
0aa0b6
 async reply
0aa0b6
0aa0b6
... and clean up reply function
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 33 ++++++++++++++++++--------------
0aa0b6
 1 file changed, 19 insertions(+), 14 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index e4185f6e1..4ea0a337a 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2411,15 +2411,8 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
0aa0b6
 
0aa0b6
     if (bcast) {
0aa0b6
         send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE);
0aa0b6
-
0aa0b6
-    } else if (cmd->origin) {
0aa0b6
-        crm_trace("Directed reply to %s", cmd->origin);
0aa0b6
-        send_cluster_message(crm_get_peer(0, cmd->origin), crm_msg_stonith_ng, reply, FALSE);
0aa0b6
-
0aa0b6
     } else {
0aa0b6
-        crm_trace("Directed local %ssync reply to %s",
0aa0b6
-                  (cmd->options & st_opt_sync_call) ? "" : "a-", cmd->client_name);
0aa0b6
-        do_local_reply(reply, cmd->client, cmd->options & st_opt_sync_call, FALSE);
0aa0b6
+        stonith_send_reply(reply, cmd->options, cmd->origin, cmd->client);
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (stand_alone) {
0aa0b6
@@ -2814,16 +2807,28 @@ check_alternate_host(const char *target)
0aa0b6
     return alternate_host;
0aa0b6
 }
0aa0b6
 
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Send a reply to a CPG peer or IPC client
0aa0b6
+ *
0aa0b6
+ * \param[in] reply         XML reply to send
0aa0b6
+ * \param[in] call_options  Send synchronously if st_opt_sync_call is set here
0aa0b6
+ * \param[in] remote_peer   If not NULL, name of peer node to send CPG reply
0aa0b6
+ * \param[in] client_id     If not NULL, name of client to send IPC reply
0aa0b6
+ */
0aa0b6
 static void
0aa0b6
-stonith_send_reply(xmlNode * reply, int call_options, const char *remote_peer,
0aa0b6
+stonith_send_reply(xmlNode *reply, int call_options, const char *remote_peer,
0aa0b6
                    const char *client_id)
0aa0b6
 {
0aa0b6
-    if (remote_peer) {
0aa0b6
-        send_cluster_message(crm_get_peer(0, remote_peer), crm_msg_stonith_ng, reply, FALSE);
0aa0b6
-    } else {
0aa0b6
+    CRM_CHECK((reply != NULL) && ((remote_peer != NULL) || (client_id != NULL)),
0aa0b6
+              return);
0aa0b6
+
0aa0b6
+    if (remote_peer == NULL) {
0aa0b6
         do_local_reply(reply, client_id,
0aa0b6
-                       pcmk_is_set(call_options, st_opt_sync_call),
0aa0b6
-                       (remote_peer != NULL));
0aa0b6
+                       pcmk_is_set(call_options, st_opt_sync_call), FALSE);
0aa0b6
+    } else {
0aa0b6
+        send_cluster_message(crm_get_peer(0, remote_peer), crm_msg_stonith_ng,
0aa0b6
+                             reply, FALSE);
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 2cdbda58f0e9f38a0e302506107fd933cb415144 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 23 Nov 2021 17:24:09 -0600
0aa0b6
Subject: [PATCH 06/19] Refactor: fencer: ensure all requests get clean-up
0aa0b6
0aa0b6
handle_request() has if-else blocks for each type of request. Previously, if a
0aa0b6
request didn't need a reply, the function would do any clean-up needed and
0aa0b6
return immediately. Now, we track whether a reply is needed, and all request
0aa0b6
types flow to the end of the function for consistent clean-up.
0aa0b6
0aa0b6
This doesn't change any behavior at this point, but allows us to do more at the
0aa0b6
end of request handling.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 46 ++++++++++++++++++--------------
0aa0b6
 1 file changed, 26 insertions(+), 20 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 4ea0a337a..19477b49b 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2892,6 +2892,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
 
0aa0b6
     xmlNode *data = NULL;
0aa0b6
     xmlNode *reply = NULL;
0aa0b6
+    bool need_reply = true;
0aa0b6
 
0aa0b6
     char *output = NULL;
0aa0b6
     const char *op = crm_element_value(request, F_STONITH_OPERATION);
0aa0b6
@@ -2921,10 +2922,12 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         pcmk__ipc_send_xml(client, id, reply, flags);
0aa0b6
         client->request_id = 0;
0aa0b6
         free_xml(reply);
0aa0b6
-        return 0;
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        need_reply = false;
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_EXEC, pcmk__str_none)) {
0aa0b6
         rc = stonith_device_action(request, &output);
0aa0b6
+        need_reply = (rc != -EINPROGRESS);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_TIMEOUT_UPDATE, pcmk__str_none)) {
0aa0b6
         const char *call_id = crm_element_value(request, F_STONITH_CALLID);
0aa0b6
@@ -2933,7 +2936,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
 
0aa0b6
         crm_element_value_int(request, F_STONITH_TIMEOUT, &op_timeout);
0aa0b6
         do_stonith_async_timeout_update(client_id, call_id, op_timeout);
0aa0b6
-        return 0;
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        need_reply = false;
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) {
0aa0b6
         if (remote_peer) {
0aa0b6
@@ -2944,7 +2948,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         remove_relay_op(request);
0aa0b6
 
0aa0b6
         stonith_query(request, remote_peer, client_id, call_options);
0aa0b6
-        return 0;
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        need_reply = false;
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, T_STONITH_NOTIFY, pcmk__str_none)) {
0aa0b6
         const char *flag_name = NULL;
0aa0b6
@@ -2965,7 +2970,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         }
0aa0b6
 
0aa0b6
         pcmk__ipc_send_ack(client, id, flags, "ack", CRM_EX_OK);
0aa0b6
-        return 0;
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        need_reply = false;
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_RELAY, pcmk__str_none)) {
0aa0b6
         xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
0aa0b6
@@ -2977,8 +2983,11 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                    crm_element_value(dev, F_STONITH_ACTION),
0aa0b6
                    crm_element_value(dev, F_STONITH_TARGET));
0aa0b6
 
0aa0b6
-        if (initiate_remote_stonith_op(NULL, request, FALSE) != NULL) {
0aa0b6
+        if (initiate_remote_stonith_op(NULL, request, FALSE) == NULL) {
0aa0b6
+            rc = -EPROTO;
0aa0b6
+        } else {
0aa0b6
             rc = -EINPROGRESS;
0aa0b6
+            need_reply = false;
0aa0b6
         }
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_FENCE, pcmk__str_none)) {
0aa0b6
@@ -3012,7 +3021,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                 crm_element_value_int(dev, F_STONITH_TOLERANCE, &tolerance);
0aa0b6
 
0aa0b6
                 if (stonith_check_fence_tolerance(tolerance, target, action)) {
0aa0b6
-                    rc = 0;
0aa0b6
+                    rc = pcmk_ok;
0aa0b6
                     goto done;
0aa0b6
                 }
0aa0b6
 
0aa0b6
@@ -3047,10 +3056,13 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                                      FALSE);
0aa0b6
                 rc = -EINPROGRESS;
0aa0b6
 
0aa0b6
-            } else if (initiate_remote_stonith_op(client, request, FALSE) != NULL) {
0aa0b6
+            } else if (initiate_remote_stonith_op(client, request, FALSE) == NULL) {
0aa0b6
+                rc = -EPROTO;
0aa0b6
+            } else {
0aa0b6
                 rc = -EINPROGRESS;
0aa0b6
             }
0aa0b6
         }
0aa0b6
+        need_reply = (rc != -EINPROGRESS);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_FENCE_HISTORY, pcmk__str_none)) {
0aa0b6
         rc = stonith_fence_history(request, &data, remote_peer, call_options);
0aa0b6
@@ -3058,8 +3070,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
             /* we don't expect answers to the broadcast
0aa0b6
              * we might have sent out
0aa0b6
              */
0aa0b6
-            free_xml(data);
0aa0b6
-            return pcmk_ok;
0aa0b6
+            rc = pcmk_ok;
0aa0b6
+            need_reply = false;
0aa0b6
         }
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_DEVICE_ADD, pcmk__str_none)) {
0aa0b6
@@ -3111,8 +3123,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         crm_element_value_int(request, XML_ATTR_ID, &node_id);
0aa0b6
         name = crm_element_value(request, XML_ATTR_UNAME);
0aa0b6
         reap_crm_member(node_id, name);
0aa0b6
-
0aa0b6
-        return pcmk_ok;
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        need_reply = false;
0aa0b6
 
0aa0b6
     } else {
0aa0b6
         crm_err("Unknown IPC request %s from %s %s", op,
0aa0b6
@@ -3120,20 +3132,14 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                 ((client == NULL)? remote_peer : pcmk__client_name(client)));
0aa0b6
     }
0aa0b6
 
0aa0b6
-  done:
0aa0b6
-
0aa0b6
+done:
0aa0b6
     if (rc == -EACCES) {
0aa0b6
         crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
0aa0b6
                  crm_str(op), pcmk__client_name(client));
0aa0b6
     }
0aa0b6
 
0aa0b6
-    /* Always reply unless the request is in process still.
0aa0b6
-     * If in progress, a reply will happen async after the request
0aa0b6
-     * processing is finished */
0aa0b6
-    if (rc != -EINPROGRESS) {
0aa0b6
-        crm_trace("Reply handling: %p %u %u %d %d %s", client, client?client->request_id:0,
0aa0b6
-                  id, pcmk_is_set(call_options, st_opt_sync_call), call_options,
0aa0b6
-                  crm_element_value(request, F_STONITH_CALLOPTS));
0aa0b6
+    // Reply if result is known
0aa0b6
+    if (need_reply) {
0aa0b6
 
0aa0b6
         if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
             CRM_ASSERT(client == NULL || client->request_id == id);
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 067d655ebd3fbb0ed27f4e7426db4c3b661ba777 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 23 Nov 2021 17:26:32 -0600
0aa0b6
Subject: [PATCH 07/19] Log: fencer: improve debug logs when processing CPG/IPC
0aa0b6
 messages
0aa0b6
0aa0b6
By moving the result log messages from stonith_command() to handle_reply() and
0aa0b6
handle_request(), we can simplify stonith_command() and give slightly better
0aa0b6
messages.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 80 +++++++++++++++-----------------
0aa0b6
 1 file changed, 38 insertions(+), 42 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 19477b49b..98af0e04f 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2883,7 +2883,7 @@ remove_relay_op(xmlNode * request)
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
-static int
0aa0b6
+static void
0aa0b6
 handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                xmlNode *request, const char *remote_peer)
0aa0b6
 {
0aa0b6
@@ -3152,73 +3152,69 @@ done:
0aa0b6
     free_xml(data);
0aa0b6
     free_xml(reply);
0aa0b6
 
0aa0b6
-    return rc;
0aa0b6
+    crm_debug("Processed %s request from %s %s: %s (rc=%d)",
0aa0b6
+              op, ((client == NULL)? "peer" : "client"),
0aa0b6
+              ((client == NULL)? remote_peer : pcmk__client_name(client)),
0aa0b6
+              ((rc > 0)? "" : pcmk_strerror(rc)), rc);
0aa0b6
 }
0aa0b6
 
0aa0b6
 static void
0aa0b6
 handle_reply(pcmk__client_t *client, xmlNode *request, const char *remote_peer)
0aa0b6
 {
0aa0b6
-    const char *op = crm_element_value(request, F_STONITH_OPERATION);
0aa0b6
+    // Copy, because request might be freed before we want to log this
0aa0b6
+    char *op = crm_element_value_copy(request, F_STONITH_OPERATION);
0aa0b6
 
0aa0b6
     if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) {
0aa0b6
         process_remote_stonith_query(request);
0aa0b6
-    } else if (pcmk__str_eq(op, T_STONITH_NOTIFY, pcmk__str_none)) {
0aa0b6
-        process_remote_stonith_exec(request);
0aa0b6
-    } else if (pcmk__str_eq(op, STONITH_OP_FENCE, pcmk__str_none)) {
0aa0b6
-        /* Reply to a complex fencing op */
0aa0b6
+    } else if (pcmk__str_any_of(op, T_STONITH_NOTIFY, STONITH_OP_FENCE, NULL)) {
0aa0b6
         process_remote_stonith_exec(request);
0aa0b6
     } else {
0aa0b6
-        crm_err("Unknown %s reply from %s %s", op,
0aa0b6
-                ((client == NULL)? "peer" : "client"),
0aa0b6
+        crm_err("Ignoring unknown %s reply from %s %s",
0aa0b6
+                crm_str(op), ((client == NULL)? "peer" : "client"),
0aa0b6
                 ((client == NULL)? remote_peer : pcmk__client_name(client)));
0aa0b6
         crm_log_xml_warn(request, "UnknownOp");
0aa0b6
+        free(op);
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
+    crm_debug("Processed %s reply from %s %s",
0aa0b6
+              op, ((client == NULL)? "peer" : "client"),
0aa0b6
+              ((client == NULL)? remote_peer : pcmk__client_name(client)));
0aa0b6
+    free(op);
0aa0b6
 }
0aa0b6
 
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Handle a message from an IPC client or CPG peer
0aa0b6
+ *
0aa0b6
+ * \param[in] client      If not NULL, IPC client that sent message
0aa0b6
+ * \param[in] id          If from IPC client, IPC message ID
0aa0b6
+ * \param[in] flags       Message flags
0aa0b6
+ * \param[in] message     Message XML
0aa0b6
+ * \param[in] remote_peer If not NULL, CPG peer that sent message
0aa0b6
+ */
0aa0b6
 void
0aa0b6
 stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
-                xmlNode *request, const char *remote_peer)
0aa0b6
+                xmlNode *message, const char *remote_peer)
0aa0b6
 {
0aa0b6
-    int call_options = 0;
0aa0b6
-    int rc = 0;
0aa0b6
-    gboolean is_reply = FALSE;
0aa0b6
-
0aa0b6
-    /* Copy op for reporting. The original might get freed by handle_reply()
0aa0b6
-     * before we use it in crm_debug():
0aa0b6
-     *     handle_reply()
0aa0b6
-     *     |- process_remote_stonith_exec()
0aa0b6
-     *     |-- remote_op_done()
0aa0b6
-     *     |--- handle_local_reply_and_notify()
0aa0b6
-     *     |---- crm_xml_add(...F_STONITH_OPERATION...)
0aa0b6
-     *     |--- free_xml(op->request)
0aa0b6
-     */
0aa0b6
-    char *op = crm_element_value_copy(request, F_STONITH_OPERATION);
0aa0b6
-
0aa0b6
-    if (get_xpath_object("//" T_STONITH_REPLY, request, LOG_NEVER)) {
0aa0b6
-        is_reply = TRUE;
0aa0b6
-    }
0aa0b6
+    int call_options = st_opt_none;
0aa0b6
+    bool is_reply = get_xpath_object("//" T_STONITH_REPLY, message,
0aa0b6
+                                     LOG_NEVER) != NULL;
0aa0b6
 
0aa0b6
-    crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
0aa0b6
-    crm_debug("Processing %s%s %u from %s %s with call options 0x%08x",
0aa0b6
-              op, (is_reply? " reply" : ""), id,
0aa0b6
+    crm_element_value_int(message, F_STONITH_CALLOPTS, &call_options);
0aa0b6
+    crm_debug("Processing %ssynchronous %s %s %u from %s %s",
0aa0b6
+              pcmk_is_set(call_options, st_opt_sync_call)? "" : "a",
0aa0b6
+              crm_element_value(message, F_STONITH_OPERATION),
0aa0b6
+              (is_reply? "reply" : "request"), id,
0aa0b6
               ((client == NULL)? "peer" : "client"),
0aa0b6
-              ((client == NULL)? remote_peer : pcmk__client_name(client)),
0aa0b6
-              call_options);
0aa0b6
+              ((client == NULL)? remote_peer : pcmk__client_name(client)));
0aa0b6
 
0aa0b6
     if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
         CRM_ASSERT(client == NULL || client->request_id == id);
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (is_reply) {
0aa0b6
-        handle_reply(client, request, remote_peer);
0aa0b6
+        handle_reply(client, message, remote_peer);
0aa0b6
     } else {
0aa0b6
-        rc = handle_request(client, id, flags, request, remote_peer);
0aa0b6
+        handle_request(client, id, flags, message, remote_peer);
0aa0b6
     }
0aa0b6
-
0aa0b6
-    crm_debug("Processed %s%s from %s %s: %s (rc=%d)",
0aa0b6
-              op, (is_reply? " reply" : ""),
0aa0b6
-              ((client == NULL)? "peer" : "client"),
0aa0b6
-              ((client == NULL)? remote_peer : pcmk__client_name(client)),
0aa0b6
-              ((rc > 0)? "" : pcmk_strerror(rc)), rc);
0aa0b6
-    free(op);
0aa0b6
 }
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 44cb340c11b4652f452a47eb2b0050b4a459382b Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Mon, 15 Nov 2021 16:29:09 -0600
0aa0b6
Subject: [PATCH 08/19] Refactor: fencer: drop unused argument from
0aa0b6
 notification functions
0aa0b6
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c  | 12 ++++++------
0aa0b6
 daemons/fenced/fenced_history.c   |  6 +++---
0aa0b6
 daemons/fenced/fenced_remote.c    |  6 +++---
0aa0b6
 daemons/fenced/pacemaker-fenced.c | 18 +++++++++---------
0aa0b6
 daemons/fenced/pacemaker-fenced.h |  6 +++---
0aa0b6
 5 files changed, 24 insertions(+), 24 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 98af0e04f..946ce4042 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2428,8 +2428,8 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
0aa0b6
         crm_xml_add(notify_data, F_STONITH_REMOTE_OP_ID, cmd->remote_op_id);
0aa0b6
         crm_xml_add(notify_data, F_STONITH_ORIGIN, cmd->client);
0aa0b6
 
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_FENCE, rc, notify_data);
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY, 0, NULL);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_FENCE, rc, notify_data);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
     }
0aa0b6
 
0aa0b6
     free_xml(reply);
0aa0b6
@@ -3082,7 +3082,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
         }
0aa0b6
-        do_stonith_notify_device(call_options, op, rc, device_id);
0aa0b6
+        do_stonith_notify_device(op, rc, device_id);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_DEVICE_DEL, pcmk__str_none)) {
0aa0b6
         xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, request, LOG_ERR);
0aa0b6
@@ -3093,7 +3093,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
         }
0aa0b6
-        do_stonith_notify_device(call_options, op, rc, device_id);
0aa0b6
+        do_stonith_notify_device(op, rc, device_id);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_LEVEL_ADD, pcmk__str_none)) {
0aa0b6
         char *device_id = NULL;
0aa0b6
@@ -3103,7 +3103,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
         }
0aa0b6
-        do_stonith_notify_level(call_options, op, rc, device_id);
0aa0b6
+        do_stonith_notify_level(op, rc, device_id);
0aa0b6
         free(device_id);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_LEVEL_DEL, pcmk__str_none)) {
0aa0b6
@@ -3114,7 +3114,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
         }
0aa0b6
-        do_stonith_notify_level(call_options, op, rc, device_id);
0aa0b6
+        do_stonith_notify_level(op, rc, device_id);
0aa0b6
 
0aa0b6
     } else if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) {
0aa0b6
         int node_id = 0;
0aa0b6
diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c
0aa0b6
index 1ba034ba9..7127593b6 100644
0aa0b6
--- a/daemons/fenced/fenced_history.c
0aa0b6
+++ b/daemons/fenced/fenced_history.c
0aa0b6
@@ -100,7 +100,7 @@ stonith_fence_history_cleanup(const char *target,
0aa0b6
         g_hash_table_foreach_remove(stonith_remote_op_list,
0aa0b6
                              stonith_remove_history_entry,
0aa0b6
                              (gpointer) target);
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY, 0, NULL);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
@@ -396,7 +396,7 @@ stonith_local_history_diff_and_merge(GHashTable *remote_history,
0aa0b6
 
0aa0b6
     if (updated) {
0aa0b6
         stonith_fence_history_trim();
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY, 0, NULL);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (cnt == 0) {
0aa0b6
@@ -470,7 +470,7 @@ stonith_fence_history(xmlNode *msg, xmlNode **output,
0aa0b6
            is done so send a notification for anything
0aa0b6
            that smells like history-sync
0aa0b6
          */
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY_SYNCED, 0, NULL);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_HISTORY_SYNCED, pcmk_ok, NULL);
0aa0b6
         if (crm_element_value(msg, F_STONITH_CALLID)) {
0aa0b6
             /* this is coming from the stonith-API
0aa0b6
             *
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 9e2f62804..c907cd120 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -423,8 +423,8 @@ handle_local_reply_and_notify(remote_fencing_op_t * op, xmlNode * data, int rc)
0aa0b6
     do_local_reply(reply, op->client_id, op->call_options & st_opt_sync_call, FALSE);
0aa0b6
 
0aa0b6
     /* bcast to all local clients that the fencing operation happend */
0aa0b6
-    do_stonith_notify(0, T_STONITH_NOTIFY_FENCE, rc, notify_data);
0aa0b6
-    do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY, 0, NULL);
0aa0b6
+    do_stonith_notify(T_STONITH_NOTIFY_FENCE, rc, notify_data);
0aa0b6
+    do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
 
0aa0b6
     /* mark this op as having notify's already sent */
0aa0b6
     op->notify_sent = TRUE;
0aa0b6
@@ -1119,7 +1119,7 @@ create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer)
0aa0b6
 
0aa0b6
     if (op->state != st_duplicate) {
0aa0b6
         /* kick history readers */
0aa0b6
-        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY, 0, NULL);
0aa0b6
+        do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
     }
0aa0b6
 
0aa0b6
     /* safe to trim as long as that doesn't touch pending ops */
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c
0aa0b6
index a64004ce1..a290e1670 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.c
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.c
0aa0b6
@@ -357,7 +357,7 @@ do_stonith_async_timeout_update(const char *client_id, const char *call_id, int
0aa0b6
 }
0aa0b6
 
0aa0b6
 void
0aa0b6
-do_stonith_notify(int options, const char *type, int result, xmlNode * data)
0aa0b6
+do_stonith_notify(const char *type, int result, xmlNode *data)
0aa0b6
 {
0aa0b6
     /* TODO: Standardize the contents of data */
0aa0b6
     xmlNode *update_msg = create_xml_node(NULL, "notify");
0aa0b6
@@ -380,7 +380,7 @@ do_stonith_notify(int options, const char *type, int result, xmlNode * data)
0aa0b6
 }
0aa0b6
 
0aa0b6
 static void
0aa0b6
-do_stonith_notify_config(int options, const char *op, int rc,
0aa0b6
+do_stonith_notify_config(const char *op, int rc,
0aa0b6
                          const char *desc, int active)
0aa0b6
 {
0aa0b6
     xmlNode *notify_data = create_xml_node(NULL, op);
0aa0b6
@@ -390,20 +390,20 @@ do_stonith_notify_config(int options, const char *op, int rc,
0aa0b6
     crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
0aa0b6
     crm_xml_add_int(notify_data, F_STONITH_ACTIVE, active);
0aa0b6
 
0aa0b6
-    do_stonith_notify(options, op, rc, notify_data);
0aa0b6
+    do_stonith_notify(op, rc, notify_data);
0aa0b6
     free_xml(notify_data);
0aa0b6
 }
0aa0b6
 
0aa0b6
 void
0aa0b6
-do_stonith_notify_device(int options, const char *op, int rc, const char *desc)
0aa0b6
+do_stonith_notify_device(const char *op, int rc, const char *desc)
0aa0b6
 {
0aa0b6
-    do_stonith_notify_config(options, op, rc, desc, g_hash_table_size(device_list));
0aa0b6
+    do_stonith_notify_config(op, rc, desc, g_hash_table_size(device_list));
0aa0b6
 }
0aa0b6
 
0aa0b6
 void
0aa0b6
-do_stonith_notify_level(int options, const char *op, int rc, const char *desc)
0aa0b6
+do_stonith_notify_level(const char *op, int rc, const char *desc)
0aa0b6
 {
0aa0b6
-    do_stonith_notify_config(options, op, rc, desc, g_hash_table_size(topology));
0aa0b6
+    do_stonith_notify_config(op, rc, desc, g_hash_table_size(topology));
0aa0b6
 }
0aa0b6
 
0aa0b6
 static void
0aa0b6
@@ -418,7 +418,7 @@ topology_remove_helper(const char *node, int level)
0aa0b6
     crm_xml_add(data, XML_ATTR_STONITH_TARGET, node);
0aa0b6
 
0aa0b6
     rc = stonith_level_remove(data, &desc);
0aa0b6
-    do_stonith_notify_level(0, STONITH_OP_LEVEL_DEL, rc, desc);
0aa0b6
+    do_stonith_notify_level(STONITH_OP_LEVEL_DEL, rc, desc);
0aa0b6
 
0aa0b6
     free_xml(data);
0aa0b6
     free(desc);
0aa0b6
@@ -468,7 +468,7 @@ handle_topology_change(xmlNode *match, bool remove)
0aa0b6
     }
0aa0b6
 
0aa0b6
     rc = stonith_level_register(match, &desc);
0aa0b6
-    do_stonith_notify_level(0, STONITH_OP_LEVEL_ADD, rc, desc);
0aa0b6
+    do_stonith_notify_level(STONITH_OP_LEVEL_ADD, rc, desc);
0aa0b6
 
0aa0b6
     free(desc);
0aa0b6
 }
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
0aa0b6
index a64b57693..3e41d867e 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.h
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.h
0aa0b6
@@ -233,9 +233,9 @@ xmlNode *stonith_construct_reply(xmlNode * request, const char *output, xmlNode
0aa0b6
 void
0aa0b6
  do_stonith_async_timeout_update(const char *client, const char *call_id, int timeout);
0aa0b6
 
0aa0b6
-void do_stonith_notify(int options, const char *type, int result, xmlNode * data);
0aa0b6
-void do_stonith_notify_device(int options, const char *op, int rc, const char *desc);
0aa0b6
-void do_stonith_notify_level(int options, const char *op, int rc, const char *desc);
0aa0b6
+void do_stonith_notify(const char *type, int result, xmlNode *data);
0aa0b6
+void do_stonith_notify_device(const char *op, int rc, const char *desc);
0aa0b6
+void do_stonith_notify_level(const char *op, int rc, const char *desc);
0aa0b6
 
0aa0b6
 remote_fencing_op_t *initiate_remote_stonith_op(pcmk__client_t *client,
0aa0b6
                                                 xmlNode *request,
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From a49df4901b663b3366634c1d58f04625ecba4005 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 16 Nov 2021 11:57:14 -0600
0aa0b6
Subject: [PATCH 09/19] Refactor: fencer: functionize checking for privileged
0aa0b6
 client
0aa0b6
0aa0b6
... for readability and to make planned changes easier
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 49 +++++++++++++++++++-------------
0aa0b6
 1 file changed, 30 insertions(+), 19 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 946ce4042..34c956f5c 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2883,6 +2883,32 @@ remove_relay_op(xmlNode * request)
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Check whether an API request was sent by a privileged user
0aa0b6
+ *
0aa0b6
+ * API commands related to fencing configuration may be done only by privileged
0aa0b6
+ * IPC users (i.e. root or hacluster), because all other users should go through
0aa0b6
+ * the CIB to have ACLs applied. If no client was given, this is a peer request,
0aa0b6
+ * which is always allowed.
0aa0b6
+ *
0aa0b6
+ * \param[in] c   IPC client that sent request (or NULL if sent by CPG peer)
0aa0b6
+ * \param[in] op  Requested API operation (for logging only)
0aa0b6
+ *
0aa0b6
+ * \return true if sender is peer or privileged client, otherwise false
0aa0b6
+ */
0aa0b6
+static inline bool
0aa0b6
+is_privileged(pcmk__client_t *c, const char *op)
0aa0b6
+{
0aa0b6
+    if ((c == NULL) || pcmk_is_set(c->flags, pcmk__client_privileged)) {
0aa0b6
+        return true;
0aa0b6
+    } else {
0aa0b6
+        crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
0aa0b6
+                 crm_str(op), pcmk__client_name(c));
0aa0b6
+        return false;
0aa0b6
+    }
0aa0b6
+}
0aa0b6
+
0aa0b6
 static void
0aa0b6
 handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
                xmlNode *request, const char *remote_peer)
0aa0b6
@@ -2898,15 +2924,6 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     const char *op = crm_element_value(request, F_STONITH_OPERATION);
0aa0b6
     const char *client_id = crm_element_value(request, F_STONITH_CLIENTID);
0aa0b6
 
0aa0b6
-    /* IPC commands related to fencing configuration may be done only by
0aa0b6
-     * privileged users (i.e. root or hacluster), because all other users should
0aa0b6
-     * go through the CIB to have ACLs applied.
0aa0b6
-     *
0aa0b6
-     * If no client was given, this is a peer request, which is always allowed.
0aa0b6
-     */
0aa0b6
-    bool allowed = (client == NULL)
0aa0b6
-                   || pcmk_is_set(client->flags, pcmk__client_privileged);
0aa0b6
-
0aa0b6
     crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
0aa0b6
 
0aa0b6
     if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
@@ -3077,7 +3094,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_DEVICE_ADD, pcmk__str_none)) {
0aa0b6
         const char *device_id = NULL;
0aa0b6
 
0aa0b6
-        if (allowed) {
0aa0b6
+        if (is_privileged(client, op)) {
0aa0b6
             rc = stonith_device_register(request, &device_id, FALSE);
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
@@ -3088,7 +3105,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, request, LOG_ERR);
0aa0b6
         const char *device_id = crm_element_value(dev, XML_ATTR_ID);
0aa0b6
 
0aa0b6
-        if (allowed) {
0aa0b6
+        if (is_privileged(client, op)) {
0aa0b6
             rc = stonith_device_remove(device_id, FALSE);
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
@@ -3098,7 +3115,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_LEVEL_ADD, pcmk__str_none)) {
0aa0b6
         char *device_id = NULL;
0aa0b6
 
0aa0b6
-        if (allowed) {
0aa0b6
+        if (is_privileged(client, op)) {
0aa0b6
             rc = stonith_level_register(request, &device_id);
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
@@ -3109,7 +3126,7 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_LEVEL_DEL, pcmk__str_none)) {
0aa0b6
         char *device_id = NULL;
0aa0b6
 
0aa0b6
-        if (allowed) {
0aa0b6
+        if (is_privileged(client, op)) {
0aa0b6
             rc = stonith_level_remove(request, &device_id);
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
@@ -3133,14 +3150,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     }
0aa0b6
 
0aa0b6
 done:
0aa0b6
-    if (rc == -EACCES) {
0aa0b6
-        crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
0aa0b6
-                 crm_str(op), pcmk__client_name(client));
0aa0b6
-    }
0aa0b6
-
0aa0b6
     // Reply if result is known
0aa0b6
     if (need_reply) {
0aa0b6
-
0aa0b6
         if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
             CRM_ASSERT(client == NULL || client->request_id == id);
0aa0b6
         }
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 10ca8a5ef5266159bc3f993802aeae6537ceeb11 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 16 Nov 2021 16:59:03 -0600
0aa0b6
Subject: [PATCH 10/19] Low: fencer: return -ETIME for peer fencing timeouts
0aa0b6
0aa0b6
94c55684 set the result as pcmk_ok, but it appears that the intent was just to
0aa0b6
keep the delegate from being set, and -ETIME should still do that, while being
0aa0b6
more appropriate.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_remote.c | 2 +-
0aa0b6
 1 file changed, 1 insertion(+), 1 deletion(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index c907cd120..dc7b802da 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -608,7 +608,7 @@ remote_op_timeout_one(gpointer userdata)
0aa0b6
 
0aa0b6
     crm_notice("Peer's '%s' action targeting %s for client %s timed out " CRM_XS
0aa0b6
                " id=%.8s", op->action, op->target, op->client_name, op->id);
0aa0b6
-    call_remote_stonith(op, NULL, pcmk_ok);
0aa0b6
+    call_remote_stonith(op, NULL, -ETIME);
0aa0b6
     return FALSE;
0aa0b6
 }
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From fb2eefeb695cc92e1a2aed6f1f1d2b900d4fb83e Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 16 Nov 2021 17:54:56 -0600
0aa0b6
Subject: [PATCH 11/19] Refactor: fencer: functionize common part of timeout
0aa0b6
 handling
0aa0b6
0aa0b6
Previously, remote_op_timeout() was called from multiple places, but only one
0aa0b6
of those places needed the full processing. The common part is now in a new
0aa0b6
function finalize_timed_out_op() called from all the places, and
0aa0b6
remote_op_timeout() now has just the additional processing needed by the one
0aa0b6
place plus a call to the new function.
0aa0b6
0aa0b6
This will allow a future change to set a different exit reason depending on
0aa0b6
which step timed out.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_remote.c | 49 +++++++++++++++++++++++-----------
0aa0b6
 1 file changed, 34 insertions(+), 15 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index dc7b802da..22c4b0772 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -612,20 +612,18 @@ remote_op_timeout_one(gpointer userdata)
0aa0b6
     return FALSE;
0aa0b6
 }
0aa0b6
 
0aa0b6
-static gboolean
0aa0b6
-remote_op_timeout(gpointer userdata)
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Finalize a remote fencer operation that timed out
0aa0b6
+ *
0aa0b6
+ * \param[in] op      Fencer operation that timed out
0aa0b6
+ */
0aa0b6
+static void
0aa0b6
+finalize_timed_out_op(remote_fencing_op_t *op)
0aa0b6
 {
0aa0b6
-    remote_fencing_op_t *op = userdata;
0aa0b6
 
0aa0b6
     op->op_timer_total = 0;
0aa0b6
 
0aa0b6
-    if (op->state == st_done) {
0aa0b6
-        crm_debug("Action '%s' targeting %s for client %s already completed "
0aa0b6
-                  CRM_XS " id=%.8s",
0aa0b6
-                  op->action, op->target, op->client_name, op->id);
0aa0b6
-        return FALSE;
0aa0b6
-    }
0aa0b6
-
0aa0b6
     crm_debug("Action '%s' targeting %s for client %s timed out "
0aa0b6
               CRM_XS " id=%.8s",
0aa0b6
               op->action, op->target, op->client_name, op->id);
0aa0b6
@@ -637,14 +635,35 @@ remote_op_timeout(gpointer userdata)
0aa0b6
          */
0aa0b6
         op->state = st_done;
0aa0b6
         remote_op_done(op, NULL, pcmk_ok, FALSE);
0aa0b6
-        return FALSE;
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
 
0aa0b6
     op->state = st_failed;
0aa0b6
 
0aa0b6
     remote_op_done(op, NULL, -ETIME, FALSE);
0aa0b6
+}
0aa0b6
 
0aa0b6
-    return FALSE;
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Finalize a remote fencer operation that timed out
0aa0b6
+ *
0aa0b6
+ * \param[in] userdata  Fencer operation that timed out
0aa0b6
+ *
0aa0b6
+ * \return G_SOURCE_REMOVE (which tells glib not to restart timer)
0aa0b6
+ */
0aa0b6
+static gboolean
0aa0b6
+remote_op_timeout(gpointer userdata)
0aa0b6
+{
0aa0b6
+    remote_fencing_op_t *op = userdata;
0aa0b6
+
0aa0b6
+    if (op->state == st_done) {
0aa0b6
+        crm_debug("Action '%s' targeting %s for client %s already completed "
0aa0b6
+                  CRM_XS " id=%.8s",
0aa0b6
+                  op->action, op->target, op->client_name, op->id);
0aa0b6
+    } else {
0aa0b6
+        finalize_timed_out_op(userdata);
0aa0b6
+    }
0aa0b6
+    return G_SOURCE_REMOVE;
0aa0b6
 }
0aa0b6
 
0aa0b6
 static gboolean
0aa0b6
@@ -670,7 +689,7 @@ remote_op_query_timeout(gpointer data)
0aa0b6
             g_source_remove(op->op_timer_total);
0aa0b6
             op->op_timer_total = 0;
0aa0b6
         }
0aa0b6
-        remote_op_timeout(op);
0aa0b6
+        finalize_timed_out_op(op);
0aa0b6
     }
0aa0b6
 
0aa0b6
     return FALSE;
0aa0b6
@@ -1675,8 +1694,8 @@ call_remote_stonith(remote_fencing_op_t *op, peer_device_info_t *peer, int rc)
0aa0b6
         crm_info("No remaining peers capable of fencing (%s) %s for client %s "
0aa0b6
                  CRM_XS " state=%s", op->action, op->target, op->client_name,
0aa0b6
                  stonith_op_state_str(op->state));
0aa0b6
-        CRM_LOG_ASSERT(op->state < st_done);
0aa0b6
-        remote_op_timeout(op);
0aa0b6
+        CRM_CHECK(op->state < st_done, return);
0aa0b6
+        finalize_timed_out_op(op);
0aa0b6
 
0aa0b6
     } else if(op->replies >= op->replies_expected || op->replies >= fencing_active_peers()) {
0aa0b6
 //        int rc = -EHOSTUNREACH;
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From c047005a112ac7da5ba62084e39c79db739f0923 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 18 Nov 2021 10:05:18 -0600
0aa0b6
Subject: [PATCH 12/19] Low: fencer: handle malformed manual confirmation
0aa0b6
 requests better
0aa0b6
0aa0b6
Rename stonith_manual_ack() to fenced_handle_manual_confirmation(), and move
0aa0b6
more of the manual confirmation handling in handle_request() into it, for
0aa0b6
better code isolation. This will also make planned changes easier.
0aa0b6
0aa0b6
The one behavioral difference is that a failure of initiate_remote_stonith_op()
0aa0b6
will now be ignored rather than segmentation fault trying to dereference NULL.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c  | 20 ++++++++++++--------
0aa0b6
 daemons/fenced/fenced_remote.c    | 29 ++++++++++++++++++++++++-----
0aa0b6
 daemons/fenced/pacemaker-fenced.h |  2 +-
0aa0b6
 3 files changed, 37 insertions(+), 14 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 34c956f5c..6f325b9e8 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -3012,14 +3012,18 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         if (remote_peer || stand_alone) {
0aa0b6
             rc = stonith_fence(request);
0aa0b6
 
0aa0b6
-        } else if (call_options & st_opt_manual_ack) {
0aa0b6
-            remote_fencing_op_t *rop = NULL;
0aa0b6
-            xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
0aa0b6
-            const char *target = crm_element_value(dev, F_STONITH_TARGET);
0aa0b6
-
0aa0b6
-            crm_notice("Received manual confirmation that %s is fenced", target);
0aa0b6
-            rop = initiate_remote_stonith_op(client, request, TRUE);
0aa0b6
-            rc = stonith_manual_ack(request, rop);
0aa0b6
+        } else if (pcmk_is_set(call_options, st_opt_manual_ack)) {
0aa0b6
+            switch (fenced_handle_manual_confirmation(client, request)) {
0aa0b6
+                case pcmk_rc_ok:
0aa0b6
+                    rc = pcmk_ok;
0aa0b6
+                    break;
0aa0b6
+                case EINPROGRESS:
0aa0b6
+                    rc = -EINPROGRESS;
0aa0b6
+                    break;
0aa0b6
+                default:
0aa0b6
+                    rc = -EPROTO;
0aa0b6
+                    break;
0aa0b6
+            }
0aa0b6
 
0aa0b6
         } else {
0aa0b6
             const char *alternate_host = NULL;
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 22c4b0772..60ee5e32e 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -1003,22 +1003,41 @@ static uint32_t fencing_active_peers(void)
0aa0b6
     return count;
0aa0b6
 }
0aa0b6
 
0aa0b6
+/*!
0aa0b6
+ * \internal
0aa0b6
+ * \brief Process a manual confirmation of a pending fence action
0aa0b6
+ *
0aa0b6
+ * \param[in]  client  IPC client that sent confirmation
0aa0b6
+ * \param[in]  msg     Request XML with manual confirmation
0aa0b6
+ *
0aa0b6
+ * \return Standard Pacemaker return code
0aa0b6
+ */
0aa0b6
 int
0aa0b6
-stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op)
0aa0b6
+fenced_handle_manual_confirmation(pcmk__client_t *client, xmlNode *msg)
0aa0b6
 {
0aa0b6
+    remote_fencing_op_t *op = NULL;
0aa0b6
     xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_ERR);
0aa0b6
 
0aa0b6
+    CRM_CHECK(dev != NULL, return EPROTO);
0aa0b6
+
0aa0b6
+    crm_notice("Received manual confirmation that %s has been fenced",
0aa0b6
+               crm_str(crm_element_value(dev, F_STONITH_TARGET)));
0aa0b6
+    op = initiate_remote_stonith_op(client, msg, TRUE);
0aa0b6
+    if (op == NULL) {
0aa0b6
+        return EPROTO;
0aa0b6
+    }
0aa0b6
     op->state = st_done;
0aa0b6
     set_fencing_completed(op);
0aa0b6
     op->delegate = strdup("a human");
0aa0b6
 
0aa0b6
-    crm_notice("Injecting manual confirmation that %s is safely off/down",
0aa0b6
-               crm_element_value(dev, F_STONITH_TARGET));
0aa0b6
+    // For the fencer's purposes, the fencing operation is done
0aa0b6
 
0aa0b6
     remote_op_done(op, msg, pcmk_ok, FALSE);
0aa0b6
 
0aa0b6
-    // Replies are sent via done_cb -> send_async_reply() -> do_local_reply()
0aa0b6
-    return -EINPROGRESS;
0aa0b6
+    /* For the requester's purposes, the operation is still pending. The
0aa0b6
+     * actual result will be sent asynchronously via the operation's done_cb().
0aa0b6
+     */
0aa0b6
+    return EINPROGRESS;
0aa0b6
 }
0aa0b6
 
0aa0b6
 /*!
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
0aa0b6
index 3e41d867e..cf88644f1 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.h
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.h
0aa0b6
@@ -256,7 +256,7 @@ bool fencing_peer_active(crm_node_t *peer);
0aa0b6
 
0aa0b6
 void set_fencing_completed(remote_fencing_op_t * op);
0aa0b6
 
0aa0b6
-int stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op);
0aa0b6
+int fenced_handle_manual_confirmation(pcmk__client_t *client, xmlNode *msg);
0aa0b6
 
0aa0b6
 gboolean node_has_attr(const char *node, const char *name, const char *value);
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From ec60f014b5a8f774aa57a26e40a2b1b94a7e3d3a Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 18 Nov 2021 10:35:31 -0600
0aa0b6
Subject: [PATCH 13/19] Low: fencer: handle malformed topology level removal
0aa0b6
 requests better
0aa0b6
0aa0b6
Log the malformed request, and return -EPROTO instead of -EINVAL. If a request
0aa0b6
is missing a level number, treat it as malformed instead of as a request to
0aa0b6
remove all.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 18 +++++++++---------
0aa0b6
 1 file changed, 9 insertions(+), 9 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 6f325b9e8..358844203 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -1678,27 +1678,27 @@ stonith_level_register(xmlNode *msg, char **desc)
0aa0b6
 int
0aa0b6
 stonith_level_remove(xmlNode *msg, char **desc)
0aa0b6
 {
0aa0b6
-    int id = 0;
0aa0b6
+    int id = -1;
0aa0b6
     stonith_topology_t *tp;
0aa0b6
     char *target;
0aa0b6
 
0aa0b6
     /* Unlike additions, removal requests should always have one level tag */
0aa0b6
     xmlNode *level = get_xpath_object("//" XML_TAG_FENCING_LEVEL, msg, LOG_ERR);
0aa0b6
 
0aa0b6
-    CRM_CHECK(level != NULL, return -EINVAL);
0aa0b6
+    CRM_CHECK(level != NULL, return -EPROTO);
0aa0b6
 
0aa0b6
     target = stonith_level_key(level, -1);
0aa0b6
     crm_element_value_int(level, XML_ATTR_STONITH_INDEX, &id;;
0aa0b6
+
0aa0b6
+    CRM_CHECK((id >= 0) && (id < ST_LEVEL_MAX),
0aa0b6
+              crm_log_xml_warn(msg, "invalid level");
0aa0b6
+              free(target);
0aa0b6
+              return -EPROTO);
0aa0b6
+
0aa0b6
     if (desc) {
0aa0b6
         *desc = crm_strdup_printf("%s[%d]", target, id);
0aa0b6
     }
0aa0b6
 
0aa0b6
-    /* Sanity-check arguments */
0aa0b6
-    if (id >= ST_LEVEL_MAX) {
0aa0b6
-        free(target);
0aa0b6
-        return -EINVAL;
0aa0b6
-    }
0aa0b6
-
0aa0b6
     tp = g_hash_table_lookup(topology, target);
0aa0b6
     if (tp == NULL) {
0aa0b6
         guint nentries = g_hash_table_size(topology);
0aa0b6
@@ -1714,7 +1714,7 @@ stonith_level_remove(xmlNode *msg, char **desc)
0aa0b6
                  "(%d active %s remaining)", target, nentries,
0aa0b6
                  pcmk__plural_alt(nentries, "entry", "entries"));
0aa0b6
 
0aa0b6
-    } else if (id > 0 && tp->levels[id] != NULL) {
0aa0b6
+    } else if (tp->levels[id] != NULL) {
0aa0b6
         guint nlevels;
0aa0b6
 
0aa0b6
         g_list_free_full(tp->levels[id], free);
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From ee0cfb6b284c2d6d21f8e77bf6ff286b1364235d Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 18 Nov 2021 12:33:05 -0600
0aa0b6
Subject: [PATCH 14/19] Refactor: fencer: avoid obscuring a variable
0aa0b6
0aa0b6
handle_request() declared a xmlNode *reply variable, and then one of its "if"
0aa0b6
blocks defined another one, obscuring the first. Drop the first declaration,
0aa0b6
and instead move it to the one other place that needed it.
0aa0b6
0aa0b6
Also remove a redundant assertion.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 13 +++++--------
0aa0b6
 1 file changed, 5 insertions(+), 8 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index 358844203..af0a92450 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2917,7 +2917,6 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
     int rc = -EOPNOTSUPP;
0aa0b6
 
0aa0b6
     xmlNode *data = NULL;
0aa0b6
-    xmlNode *reply = NULL;
0aa0b6
     bool need_reply = true;
0aa0b6
 
0aa0b6
     char *output = NULL;
0aa0b6
@@ -2926,8 +2925,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
 
0aa0b6
     crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
0aa0b6
 
0aa0b6
-    if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
-        CRM_ASSERT(client == NULL || client->request_id == id);
0aa0b6
+    if (pcmk_is_set(call_options, st_opt_sync_call) && (client != NULL)) {
0aa0b6
+        CRM_ASSERT(client->request_id == id);
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) {
0aa0b6
@@ -3156,16 +3155,14 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
 done:
0aa0b6
     // Reply if result is known
0aa0b6
     if (need_reply) {
0aa0b6
-        if (pcmk_is_set(call_options, st_opt_sync_call)) {
0aa0b6
-            CRM_ASSERT(client == NULL || client->request_id == id);
0aa0b6
-        }
0aa0b6
-        reply = stonith_construct_reply(request, output, data, rc);
0aa0b6
+        xmlNode *reply = stonith_construct_reply(request, output, data, rc);
0aa0b6
+
0aa0b6
         stonith_send_reply(reply, call_options, remote_peer, client_id);
0aa0b6
+        free_xml(reply);
0aa0b6
     }
0aa0b6
 
0aa0b6
     free(output);
0aa0b6
     free_xml(data);
0aa0b6
-    free_xml(reply);
0aa0b6
 
0aa0b6
     crm_debug("Processed %s request from %s %s: %s (rc=%d)",
0aa0b6
               op, ((client == NULL)? "peer" : "client"),
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From a5fef7b95b7541860e29c1ff33be38db327208fb Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Thu, 18 Nov 2021 12:37:10 -0600
0aa0b6
Subject: [PATCH 15/19] Refactor: fencer: add convenience function for setting
0aa0b6
 protocol error result
0aa0b6
0aa0b6
The fencer will soon track and return the full result (rather than just a
0aa0b6
legacy return code) for fencing actions, for callbacks and notifications.
0aa0b6
To simplify that process as well as move away from the legacy codes in general,
0aa0b6
all fencer API operations will be modified to return a full result.
0aa0b6
0aa0b6
This convenience function will come in handy for that.
0aa0b6
---
0aa0b6
 daemons/fenced/pacemaker-fenced.h | 7 +++++++
0aa0b6
 1 file changed, 7 insertions(+)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
0aa0b6
index cf88644f1..3bc5dc3d1 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.h
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.h
0aa0b6
@@ -262,6 +262,13 @@ gboolean node_has_attr(const char *node, const char *name, const char *value);
0aa0b6
 
0aa0b6
 gboolean node_does_watchdog_fencing(const char *node);
0aa0b6
 
0aa0b6
+static inline void
0aa0b6
+fenced_set_protocol_error(pcmk__action_result_t *result)
0aa0b6
+{
0aa0b6
+    pcmk__set_result(result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID,
0aa0b6
+                     "Fencer API request missing required information (bug?)");
0aa0b6
+}
0aa0b6
+
0aa0b6
 extern char *stonith_our_uname;
0aa0b6
 extern gboolean stand_alone;
0aa0b6
 extern GHashTable *device_list;
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From ed770d36fb34dc7b3344cd326830a6c06cc789ce Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Fri, 19 Nov 2021 09:59:51 -0600
0aa0b6
Subject: [PATCH 16/19] Refactor: fencer: make a few functions return void
0aa0b6
0aa0b6
... to make planned changes easier. The return values were previously ignored.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c  | 17 ++++++++-------
0aa0b6
 daemons/fenced/fenced_history.c   |  6 +-----
0aa0b6
 daemons/fenced/fenced_remote.c    | 35 ++++++++++++++-----------------
0aa0b6
 daemons/fenced/pacemaker-fenced.c |  6 +++---
0aa0b6
 daemons/fenced/pacemaker-fenced.h |  8 +++----
0aa0b6
 5 files changed, 33 insertions(+), 39 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index af0a92450..ea7d281ce 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -1411,8 +1411,8 @@ stonith_device_register(xmlNode * msg, const char **desc, gboolean from_cib)
0aa0b6
     return pcmk_ok;
0aa0b6
 }
0aa0b6
 
0aa0b6
-int
0aa0b6
-stonith_device_remove(const char *id, gboolean from_cib)
0aa0b6
+void
0aa0b6
+stonith_device_remove(const char *id, bool from_cib)
0aa0b6
 {
0aa0b6
     stonith_device_t *device = g_hash_table_lookup(device_list, id);
0aa0b6
     guint ndevices = 0;
0aa0b6
@@ -1421,7 +1421,7 @@ stonith_device_remove(const char *id, gboolean from_cib)
0aa0b6
         ndevices = g_hash_table_size(device_list);
0aa0b6
         crm_info("Device '%s' not found (%d active device%s)",
0aa0b6
                  id, ndevices, pcmk__plural_s(ndevices));
0aa0b6
-        return pcmk_ok;
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (from_cib) {
0aa0b6
@@ -1443,7 +1443,6 @@ stonith_device_remove(const char *id, gboolean from_cib)
0aa0b6
                   (device->cib_registered? " cib" : ""),
0aa0b6
                   (device->api_registered? " api" : ""));
0aa0b6
     }
0aa0b6
-    return pcmk_ok;
0aa0b6
 }
0aa0b6
 
0aa0b6
 /*!
0aa0b6
@@ -3085,8 +3084,9 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         need_reply = (rc != -EINPROGRESS);
0aa0b6
 
0aa0b6
     } else if (pcmk__str_eq(op, STONITH_OP_FENCE_HISTORY, pcmk__str_none)) {
0aa0b6
-        rc = stonith_fence_history(request, &data, remote_peer, call_options);
0aa0b6
-        if (call_options & st_opt_discard_reply) {
0aa0b6
+        stonith_fence_history(request, &data, remote_peer, call_options);
0aa0b6
+        rc = pcmk_ok;
0aa0b6
+        if (pcmk_is_set(call_options, st_opt_discard_reply)) {
0aa0b6
             /* we don't expect answers to the broadcast
0aa0b6
              * we might have sent out
0aa0b6
              */
0aa0b6
@@ -3109,7 +3109,8 @@ handle_request(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
         const char *device_id = crm_element_value(dev, XML_ATTR_ID);
0aa0b6
 
0aa0b6
         if (is_privileged(client, op)) {
0aa0b6
-            rc = stonith_device_remove(device_id, FALSE);
0aa0b6
+            stonith_device_remove(device_id, false);
0aa0b6
+            rc = pcmk_ok;
0aa0b6
         } else {
0aa0b6
             rc = -EACCES;
0aa0b6
         }
0aa0b6
@@ -3179,7 +3180,7 @@ handle_reply(pcmk__client_t *client, xmlNode *request, const char *remote_peer)
0aa0b6
     if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) {
0aa0b6
         process_remote_stonith_query(request);
0aa0b6
     } else if (pcmk__str_any_of(op, T_STONITH_NOTIFY, STONITH_OP_FENCE, NULL)) {
0aa0b6
-        process_remote_stonith_exec(request);
0aa0b6
+        fenced_process_fencing_reply(request);
0aa0b6
     } else {
0aa0b6
         crm_err("Ignoring unknown %s reply from %s %s",
0aa0b6
                 crm_str(op), ((client == NULL)? "peer" : "client"),
0aa0b6
diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c
0aa0b6
index 7127593b6..bc159383c 100644
0aa0b6
--- a/daemons/fenced/fenced_history.c
0aa0b6
+++ b/daemons/fenced/fenced_history.c
0aa0b6
@@ -433,14 +433,11 @@ stonith_local_history(gboolean add_id, const char *target)
0aa0b6
  *                      a reply from
0aa0b6
  * \param[in] remote_peer
0aa0b6
  * \param[in] options   call-options from the request
0aa0b6
- *
0aa0b6
- * \return always success as there is actully nothing that can go really wrong
0aa0b6
  */
0aa0b6
-int
0aa0b6
+void
0aa0b6
 stonith_fence_history(xmlNode *msg, xmlNode **output,
0aa0b6
                       const char *remote_peer, int options)
0aa0b6
 {
0aa0b6
-    int rc = 0;
0aa0b6
     const char *target = NULL;
0aa0b6
     xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_NEVER);
0aa0b6
     xmlNode *out_history = NULL;
0aa0b6
@@ -525,5 +522,4 @@ stonith_fence_history(xmlNode *msg, xmlNode **output,
0aa0b6
         *output = stonith_local_history(FALSE, target);
0aa0b6
     }
0aa0b6
     free_xml(out_history);
0aa0b6
-    return rc;
0aa0b6
 }
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 60ee5e32e..6338aebde 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -2086,11 +2086,9 @@ process_remote_stonith_query(xmlNode * msg)
0aa0b6
  * or attempt another device as appropriate.
0aa0b6
  *
0aa0b6
  * \param[in] msg  XML reply received
0aa0b6
- *
0aa0b6
- * \return pcmk_ok on success, -errno on error
0aa0b6
  */
0aa0b6
-int
0aa0b6
-process_remote_stonith_exec(xmlNode * msg)
0aa0b6
+void
0aa0b6
+fenced_process_fencing_reply(xmlNode *msg)
0aa0b6
 {
0aa0b6
     int rc = 0;
0aa0b6
     const char *id = NULL;
0aa0b6
@@ -2098,13 +2096,13 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
     remote_fencing_op_t *op = NULL;
0aa0b6
     xmlNode *dev = get_xpath_object("//@" F_STONITH_REMOTE_OP_ID, msg, LOG_ERR);
0aa0b6
 
0aa0b6
-    CRM_CHECK(dev != NULL, return -EPROTO);
0aa0b6
+    CRM_CHECK(dev != NULL, return);
0aa0b6
 
0aa0b6
     id = crm_element_value(dev, F_STONITH_REMOTE_OP_ID);
0aa0b6
-    CRM_CHECK(id != NULL, return -EPROTO);
0aa0b6
+    CRM_CHECK(id != NULL, return);
0aa0b6
 
0aa0b6
     dev = get_xpath_object("//@" F_STONITH_RC, msg, LOG_ERR);
0aa0b6
-    CRM_CHECK(dev != NULL, return -EPROTO);
0aa0b6
+    CRM_CHECK(dev != NULL, return);
0aa0b6
 
0aa0b6
     crm_element_value_int(dev, F_STONITH_RC, &rc);
0aa0b6
 
0aa0b6
@@ -2125,35 +2123,35 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
         /* Could be for an event that began before we started */
0aa0b6
         /* TODO: Record the op for later querying */
0aa0b6
         crm_info("Received peer result of unknown or expired operation %s", id);
0aa0b6
-        return -EOPNOTSUPP;
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (op->devices && device && !pcmk__str_eq(op->devices->data, device, pcmk__str_casei)) {
0aa0b6
         crm_err("Received outdated reply for device %s (instead of %s) to "
0aa0b6
                 "fence (%s) %s. Operation already timed out at peer level.",
0aa0b6
                 device, (const char *) op->devices->data, op->action, op->target);
0aa0b6
-        return rc;
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (pcmk__str_eq(crm_element_value(msg, F_SUBTYPE), "broadcast", pcmk__str_casei)) {
0aa0b6
         crm_debug("Finalizing action '%s' targeting %s on behalf of %s@%s: %s "
0aa0b6
-                  CRM_XS " rc=%d id=%.8s",
0aa0b6
+                  CRM_XS " id=%.8s",
0aa0b6
                   op->action, op->target, op->client_name, op->originator,
0aa0b6
-                  pcmk_strerror(rc), rc, op->id);
0aa0b6
+                  pcmk_strerror(rc), op->id);
0aa0b6
         if (rc == pcmk_ok) {
0aa0b6
             op->state = st_done;
0aa0b6
         } else {
0aa0b6
             op->state = st_failed;
0aa0b6
         }
0aa0b6
         remote_op_done(op, msg, rc, FALSE);
0aa0b6
-        return pcmk_ok;
0aa0b6
+        return;
0aa0b6
     } else if (!pcmk__str_eq(op->originator, stonith_our_uname, pcmk__str_casei)) {
0aa0b6
         /* If this isn't a remote level broadcast, and we are not the
0aa0b6
          * originator of the operation, we should not be receiving this msg. */
0aa0b6
         crm_err("Received non-broadcast fencing result for operation %.8s "
0aa0b6
                 "we do not own (device %s targeting %s)",
0aa0b6
                 op->id, device, op->target);
0aa0b6
-        return rc;
0aa0b6
+        return;
0aa0b6
     }
0aa0b6
 
0aa0b6
     if (pcmk_is_set(op->call_options, st_opt_topology)) {
0aa0b6
@@ -2168,7 +2166,7 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
          * and notify our local clients. */
0aa0b6
         if (op->state == st_done) {
0aa0b6
             remote_op_done(op, msg, rc, FALSE);
0aa0b6
-            return rc;
0aa0b6
+            return;
0aa0b6
         }
0aa0b6
 
0aa0b6
         if ((op->phase == 2) && (rc != pcmk_ok)) {
0aa0b6
@@ -2184,14 +2182,14 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
             /* An operation completed successfully. Try another device if
0aa0b6
              * necessary, otherwise mark the operation as done. */
0aa0b6
             advance_topology_device_in_level(op, device, msg, rc);
0aa0b6
-            return rc;
0aa0b6
+            return;
0aa0b6
         } else {
0aa0b6
             /* This device failed, time to try another topology level. If no other
0aa0b6
              * levels are available, mark this operation as failed and report results. */
0aa0b6
             if (advance_topology_level(op, false) != pcmk_rc_ok) {
0aa0b6
                 op->state = st_failed;
0aa0b6
                 remote_op_done(op, msg, rc, FALSE);
0aa0b6
-                return rc;
0aa0b6
+                return;
0aa0b6
             }
0aa0b6
         }
0aa0b6
     } else if (rc == pcmk_ok && op->devices == NULL) {
0aa0b6
@@ -2199,12 +2197,12 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
 
0aa0b6
         op->state = st_done;
0aa0b6
         remote_op_done(op, msg, rc, FALSE);
0aa0b6
-        return rc;
0aa0b6
+        return;
0aa0b6
     } else if (rc == -ETIME && op->devices == NULL) {
0aa0b6
         /* If the operation timed out don't bother retrying other peers. */
0aa0b6
         op->state = st_failed;
0aa0b6
         remote_op_done(op, msg, rc, FALSE);
0aa0b6
-        return rc;
0aa0b6
+        return;
0aa0b6
     } else {
0aa0b6
         /* fall-through and attempt other fencing action using another peer */
0aa0b6
     }
0aa0b6
@@ -2213,7 +2211,6 @@ process_remote_stonith_exec(xmlNode * msg)
0aa0b6
     crm_trace("Next for %s on behalf of %s@%s (rc was %d)", op->target, op->originator,
0aa0b6
               op->client_name, rc);
0aa0b6
     call_remote_stonith(op, NULL, rc);
0aa0b6
-    return rc;
0aa0b6
 }
0aa0b6
 
0aa0b6
 gboolean
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c
0aa0b6
index a290e1670..0a8b3bf6f 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.c
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.c
0aa0b6
@@ -445,7 +445,7 @@ remove_cib_device(xmlXPathObjectPtr xpathObj)
0aa0b6
 
0aa0b6
         rsc_id = crm_element_value(match, XML_ATTR_ID);
0aa0b6
 
0aa0b6
-        stonith_device_remove(rsc_id, TRUE);
0aa0b6
+        stonith_device_remove(rsc_id, true);
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
@@ -610,7 +610,7 @@ watchdog_device_update(void)
0aa0b6
     } else {
0aa0b6
         /* be silent if no device - todo parameter to stonith_device_remove */
0aa0b6
         if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID)) {
0aa0b6
-            stonith_device_remove(STONITH_WATCHDOG_ID, TRUE);
0aa0b6
+            stonith_device_remove(STONITH_WATCHDOG_ID, true);
0aa0b6
         }
0aa0b6
     }
0aa0b6
 }
0aa0b6
@@ -847,7 +847,7 @@ update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
0aa0b6
             }
0aa0b6
             if (search != NULL) {
0aa0b6
                 *search = 0;
0aa0b6
-                stonith_device_remove(rsc_id, TRUE);
0aa0b6
+                stonith_device_remove(rsc_id, true);
0aa0b6
                 /* watchdog_device_update called afterwards
0aa0b6
                    to fall back to implicit definition if needed */
0aa0b6
             } else {
0aa0b6
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
0aa0b6
index 3bc5dc3d1..5162ada75 100644
0aa0b6
--- a/daemons/fenced/pacemaker-fenced.h
0aa0b6
+++ b/daemons/fenced/pacemaker-fenced.h
0aa0b6
@@ -214,7 +214,7 @@ void stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags,
0aa0b6
 
0aa0b6
 int stonith_device_register(xmlNode * msg, const char **desc, gboolean from_cib);
0aa0b6
 
0aa0b6
-int stonith_device_remove(const char *id, gboolean from_cib);
0aa0b6
+void stonith_device_remove(const char *id, bool from_cib);
0aa0b6
 
0aa0b6
 char *stonith_level_key(xmlNode * msg, int mode);
0aa0b6
 int stonith_level_kind(xmlNode * msg);
0aa0b6
@@ -241,14 +241,14 @@ remote_fencing_op_t *initiate_remote_stonith_op(pcmk__client_t *client,
0aa0b6
                                                 xmlNode *request,
0aa0b6
                                                 gboolean manual_ack);
0aa0b6
 
0aa0b6
-int process_remote_stonith_exec(xmlNode * msg);
0aa0b6
+void fenced_process_fencing_reply(xmlNode *msg);
0aa0b6
 
0aa0b6
 int process_remote_stonith_query(xmlNode * msg);
0aa0b6
 
0aa0b6
 void *create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer);
0aa0b6
 
0aa0b6
-int stonith_fence_history(xmlNode *msg, xmlNode **output,
0aa0b6
-                          const char *remote_peer, int options);
0aa0b6
+void stonith_fence_history(xmlNode *msg, xmlNode **output,
0aa0b6
+                           const char *remote_peer, int options);
0aa0b6
 
0aa0b6
 void stonith_fence_history_trim(void);
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 27df49460930738e77f5ca42536aff1d3bdfcae7 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Fri, 19 Nov 2021 10:06:43 -0600
0aa0b6
Subject: [PATCH 17/19] Refactor: fencer: drop unnecessary argument when
0aa0b6
 advancing topology device
0aa0b6
0aa0b6
If we're advancing to the next device in a topology level, by necessity that
0aa0b6
means any previous device succeeded.
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_remote.c | 19 +++++++++----------
0aa0b6
 1 file changed, 9 insertions(+), 10 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index 6338aebde..d54e6a4ef 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -1519,14 +1519,13 @@ report_timeout_period(remote_fencing_op_t * op, int op_timeout)
0aa0b6
  * \internal
0aa0b6
  * \brief Advance an operation to the next device in its topology
0aa0b6
  *
0aa0b6
- * \param[in,out] op      Operation to advance
0aa0b6
- * \param[in]     device  ID of device just completed
0aa0b6
- * \param[in]     msg     XML reply that contained device result (if available)
0aa0b6
- * \param[in]     rc      Return code of device's execution
0aa0b6
+ * \param[in] op      Fencer operation to advance
0aa0b6
+ * \param[in] device  ID of device that just completed
0aa0b6
+ * \param[in] msg     If not NULL, XML reply of last delegated fencing operation
0aa0b6
  */
0aa0b6
 static void
0aa0b6
 advance_topology_device_in_level(remote_fencing_op_t *op, const char *device,
0aa0b6
-                                 xmlNode *msg, int rc)
0aa0b6
+                                 xmlNode *msg)
0aa0b6
 {
0aa0b6
     /* Advance to the next device at this topology level, if any */
0aa0b6
     if (op->devices) {
0aa0b6
@@ -1556,8 +1555,8 @@ advance_topology_device_in_level(remote_fencing_op_t *op, const char *device,
0aa0b6
 
0aa0b6
     if (op->devices) {
0aa0b6
         /* Necessary devices remain, so execute the next one */
0aa0b6
-        crm_trace("Next targeting %s on behalf of %s@%s (rc was %d)",
0aa0b6
-                  op->target, op->client_name, op->originator, rc);
0aa0b6
+        crm_trace("Next targeting %s on behalf of %s@%s",
0aa0b6
+                  op->target, op->client_name, op->originator);
0aa0b6
 
0aa0b6
         // The requested delay has been applied for the first device
0aa0b6
         if (op->delay > 0) {
0aa0b6
@@ -1570,7 +1569,7 @@ advance_topology_device_in_level(remote_fencing_op_t *op, const char *device,
0aa0b6
         crm_trace("Marking complex fencing op targeting %s as complete",
0aa0b6
                   op->target);
0aa0b6
         op->state = st_done;
0aa0b6
-        remote_op_done(op, msg, rc, FALSE);
0aa0b6
+        remote_op_done(op, msg, pcmk_ok, FALSE);
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
@@ -1701,7 +1700,7 @@ call_remote_stonith(remote_fencing_op_t *op, peer_device_info_t *peer, int rc)
0aa0b6
          */
0aa0b6
         crm_warn("Ignoring %s 'on' failure (no capable peers) targeting %s "
0aa0b6
                  "after successful 'off'", device, op->target);
0aa0b6
-        advance_topology_device_in_level(op, device, NULL, pcmk_ok);
0aa0b6
+        advance_topology_device_in_level(op, device, NULL);
0aa0b6
         return;
0aa0b6
 
0aa0b6
     } else if (op->owner == FALSE) {
0aa0b6
@@ -2181,7 +2180,7 @@ fenced_process_fencing_reply(xmlNode *msg)
0aa0b6
         if (rc == pcmk_ok) {
0aa0b6
             /* An operation completed successfully. Try another device if
0aa0b6
              * necessary, otherwise mark the operation as done. */
0aa0b6
-            advance_topology_device_in_level(op, device, msg, rc);
0aa0b6
+            advance_topology_device_in_level(op, device, msg);
0aa0b6
             return;
0aa0b6
         } else {
0aa0b6
             /* This device failed, time to try another topology level. If no other
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 05437e1339bc1f9071b43e97d5846a939687951d Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Mon, 29 Nov 2021 11:59:17 -0600
0aa0b6
Subject: [PATCH 18/19] Refactor: fencer: minor renames for consistency
0aa0b6
0aa0b6
... per review
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_remote.c | 13 ++++++-------
0aa0b6
 1 file changed, 6 insertions(+), 7 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c
0aa0b6
index d54e6a4ef..8feb40147 100644
0aa0b6
--- a/daemons/fenced/fenced_remote.c
0aa0b6
+++ b/daemons/fenced/fenced_remote.c
0aa0b6
@@ -63,7 +63,7 @@ typedef struct device_properties_s {
0aa0b6
     int delay_base[st_phase_max];
0aa0b6
 } device_properties_t;
0aa0b6
 
0aa0b6
-typedef struct st_query_result_s {
0aa0b6
+typedef struct {
0aa0b6
     /* Name of peer that sent this result */
0aa0b6
     char *host;
0aa0b6
     /* Only try peers for non-topology based operations once */
0aa0b6
@@ -95,13 +95,12 @@ sort_strings(gconstpointer a, gconstpointer b)
0aa0b6
 static void
0aa0b6
 free_remote_query(gpointer data)
0aa0b6
 {
0aa0b6
-    if (data) {
0aa0b6
-        peer_device_info_t *query = data;
0aa0b6
+    if (data != NULL) {
0aa0b6
+        peer_device_info_t *peer = data;
0aa0b6
 
0aa0b6
-        crm_trace("Free'ing query result from %s", query->host);
0aa0b6
-        g_hash_table_destroy(query->devices);
0aa0b6
-        free(query->host);
0aa0b6
-        free(query);
0aa0b6
+        g_hash_table_destroy(peer->devices);
0aa0b6
+        free(peer->host);
0aa0b6
+        free(peer);
0aa0b6
     }
0aa0b6
 }
0aa0b6
 
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6
0aa0b6
0aa0b6
From 86974d7cef05bafbed540d02e59514292581ae65 Mon Sep 17 00:00:00 2001
0aa0b6
From: Ken Gaillot <kgaillot@redhat.com>
0aa0b6
Date: Tue, 30 Nov 2021 08:33:41 -0600
0aa0b6
Subject: [PATCH 19/19] Refactor: fencer: simplify send_async_reply()
0aa0b6
0aa0b6
... as suggested in review
0aa0b6
---
0aa0b6
 daemons/fenced/fenced_commands.c | 28 ++++++++++++----------------
0aa0b6
 1 file changed, 12 insertions(+), 16 deletions(-)
0aa0b6
0aa0b6
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
0aa0b6
index ea7d281ce..f34cb4f13 100644
0aa0b6
--- a/daemons/fenced/fenced_commands.c
0aa0b6
+++ b/daemons/fenced/fenced_commands.c
0aa0b6
@@ -2384,36 +2384,34 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
0aa0b6
                  int pid, bool merged)
0aa0b6
 {
0aa0b6
     xmlNode *reply = NULL;
0aa0b6
-    bool bcast = false;
0aa0b6
 
0aa0b6
     CRM_CHECK((cmd != NULL) && (result != NULL), return);
0aa0b6
 
0aa0b6
+    log_async_result(cmd, result, pid, NULL, merged);
0aa0b6
+
0aa0b6
     reply = construct_async_reply(cmd, result);
0aa0b6
+    if (merged) {
0aa0b6
+        crm_xml_add(reply, F_STONITH_MERGED, "true");
0aa0b6
+    }
0aa0b6
 
0aa0b6
-    // If target was also the originator, broadcast fencing results for it
0aa0b6
     if (!stand_alone && pcmk__is_fencing_action(cmd->action)
0aa0b6
         && pcmk__str_eq(cmd->origin, cmd->victim, pcmk__str_casei)) {
0aa0b6
-
0aa0b6
+        /* The target was also the originator, so broadcast the result on its
0aa0b6
+         * behalf (since it will be unable to).
0aa0b6
+         */
0aa0b6
         crm_trace("Broadcast '%s' result for %s (target was also originator)",
0aa0b6
                   cmd->action, cmd->victim);
0aa0b6
         crm_xml_add(reply, F_SUBTYPE, "broadcast");
0aa0b6
         crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY);
0aa0b6
-        bcast = true;
0aa0b6
-    }
0aa0b6
-
0aa0b6
-    log_async_result(cmd, result, pid, NULL, merged);
0aa0b6
-
0aa0b6
-    if (merged) {
0aa0b6
-        crm_xml_add(reply, F_STONITH_MERGED, "true");
0aa0b6
-    }
0aa0b6
-    crm_log_xml_trace(reply, "Reply");
0aa0b6
-
0aa0b6
-    if (bcast) {
0aa0b6
         send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE);
0aa0b6
     } else {
0aa0b6
+        // Reply only to the originator
0aa0b6
         stonith_send_reply(reply, cmd->options, cmd->origin, cmd->client);
0aa0b6
     }
0aa0b6
 
0aa0b6
+    crm_log_xml_trace(reply, "Reply");
0aa0b6
+    free_xml(reply);
0aa0b6
+
0aa0b6
     if (stand_alone) {
0aa0b6
         /* Do notification with a clean data object */
0aa0b6
         xmlNode *notify_data = create_xml_node(NULL, T_STONITH_NOTIFY_FENCE);
0aa0b6
@@ -2430,8 +2428,6 @@ send_async_reply(async_command_t *cmd, const pcmk__action_result_t *result,
0aa0b6
         do_stonith_notify(T_STONITH_NOTIFY_FENCE, rc, notify_data);
0aa0b6
         do_stonith_notify(T_STONITH_NOTIFY_HISTORY, pcmk_ok, NULL);
0aa0b6
     }
0aa0b6
-
0aa0b6
-    free_xml(reply);
0aa0b6
 }
0aa0b6
 
0aa0b6
 static void
0aa0b6
-- 
0aa0b6
2.27.0
0aa0b6