Blame SOURCES/005-fencing-reasons.patch

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