Blame SOURCES/005-fencing-reasons.patch

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