Blame SOURCES/024-stop_unexpected.patch

ce46a7
From 767b5552ab49850204692c2c990dfb41d37589f3 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Mon, 28 Mar 2022 18:11:52 -0500
ce46a7
Subject: [PATCH 1/9] Refactor: libpacemaker: drop unnecessary argument from
ce46a7
 "rsc-action" message
ce46a7
ce46a7
9875cab129 moved the setting of the "moving" variable from LogActions() to a
ce46a7
new "rsc-action" message, but continued to pass the variable unnecessarily
ce46a7
ce46a7
Also simplify how it's set
ce46a7
---
ce46a7
 lib/pacemaker/pcmk_output.c         | 10 ++++------
ce46a7
 lib/pacemaker/pcmk_sched_native.c   |  4 +---
ce46a7
 2 files changed, 5 insertions(+), 9 deletions(-)
ce46a7
ce46a7
diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c
ce46a7
index d864c8bd2..56963a93f 100644
ce46a7
--- a/lib/pacemaker/pcmk_output.c
ce46a7
+++ b/lib/pacemaker/pcmk_output.c
ce46a7
@@ -873,19 +873,18 @@ digests_xml(pcmk__output_t *out, va_list args)
ce46a7
         }                                                               \
ce46a7
     } while(0)
ce46a7
 
ce46a7
-PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *",
ce46a7
-                  "gboolean")
ce46a7
+PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *")
ce46a7
 static int
ce46a7
 rsc_action_default(pcmk__output_t *out, va_list args)
ce46a7
 {
ce46a7
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
ce46a7
     pe_node_t *current = va_arg(args, pe_node_t *);
ce46a7
     pe_node_t *next = va_arg(args, pe_node_t *);
ce46a7
-    gboolean moving = va_arg(args, gboolean);
ce46a7
 
ce46a7
     GList *possible_matches = NULL;
ce46a7
     char *key = NULL;
ce46a7
     int rc = pcmk_rc_no_output;
ce46a7
+    bool moving = false;
ce46a7
 
ce46a7
     pe_node_t *start_node = NULL;
ce46a7
     pe_action_t *start = NULL;
ce46a7
@@ -901,9 +900,8 @@ rsc_action_default(pcmk__output_t *out, va_list args)
ce46a7
         return rc;
ce46a7
     }
ce46a7
 
ce46a7
-    if (current != NULL && next != NULL && !pcmk__str_eq(current->details->id, next->details->id, pcmk__str_casei)) {
ce46a7
-        moving = TRUE;
ce46a7
-    }
ce46a7
+    moving = (current != NULL) && (next != NULL)
ce46a7
+             && (current->details != next->details);
ce46a7
 
ce46a7
     possible_matches = pe__resource_actions(rsc, next, RSC_START, FALSE);
ce46a7
     if (possible_matches) {
ce46a7
diff --git a/lib/pacemaker/pcmk_sched_resource.c b/lib/pacemaker/pcmk_sched_resource.c
ce46a7
index a3d646775..41631da3d 100644
ce46a7
--- a/lib/pacemaker/pcmk_sched_native.c
ce46a7
+++ b/lib/pacemaker/pcmk_sched_native.c
ce46a7
@@ -2037,8 +2037,6 @@ LogActions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
     pe_node_t *next = NULL;
ce46a7
     pe_node_t *current = NULL;
ce46a7
 
ce46a7
-    gboolean moving = FALSE;
ce46a7
-
ce46a7
     if(rsc->variant == pe_container) {
ce46a7
         pcmk__bundle_log_actions(rsc, data_set);
ce46a7
         return;
ce46a7
@@ -2066,7 +2064,7 @@ LogActions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
         return;
ce46a7
     }
ce46a7
 
ce46a7
-    out->message(out, "rsc-action", rsc, current, next, moving);
ce46a7
+    out->message(out, "rsc-action", rsc, current, next);
ce46a7
 }
ce46a7
 
ce46a7
 gboolean
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 870fb19715618c4ceab9ed4ae13a99658440b662 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Tue, 22 Mar 2022 15:22:23 -0500
ce46a7
Subject: [PATCH 2/9] Refactor: scheduler: functionize scheduling restart
ce46a7
 actions
ce46a7
ce46a7
native_create_actions() is already overlarge, and more needs to be added to it
ce46a7
---
ce46a7
 lib/pacemaker/pcmk_sched_native.c | 85 ++++++++++++++++++++-----------
ce46a7
 1 file changed, 54 insertions(+), 31 deletions(-)
ce46a7
ce46a7
diff --git a/lib/pacemaker/pcmk_sched_native.c b/lib/pacemaker/pcmk_sched_native.c
ce46a7
index 808e97540..b8a1c1e1a 100644
ce46a7
--- a/lib/pacemaker/pcmk_sched_native.c
ce46a7
+++ b/lib/pacemaker/pcmk_sched_native.c
ce46a7
@@ -1185,6 +1185,58 @@ handle_migration_actions(pe_resource_t * rsc, pe_node_t *current, pe_node_t *cho
ce46a7
     }
ce46a7
 }
ce46a7
 
ce46a7
+/*!
ce46a7
+ * \internal
ce46a7
+ * \brief Schedule actions to bring resource down and back to current role
ce46a7
+ *
ce46a7
+ * \param[in] rsc           Resource to restart
ce46a7
+ * \param[in] current       Node that resource should be brought down on
ce46a7
+ * \param[in] chosen        Node that resource should be brought up on
ce46a7
+ * \param[in] need_stop     Whether the resource must be stopped
ce46a7
+ * \param[in] need_promote  Whether the resource must be promoted
ce46a7
+ *
ce46a7
+ * \return Role that resource would have after scheduled actions are taken
ce46a7
+ */
ce46a7
+static void
ce46a7
+schedule_restart_actions(pe_resource_t *rsc, pe_node_t *current,
ce46a7
+                         pe_node_t *chosen, bool need_stop, bool need_promote)
ce46a7
+{
ce46a7
+    enum rsc_role_e role = rsc->role;
ce46a7
+    enum rsc_role_e next_role;
ce46a7
+
ce46a7
+    // Bring resource down to a stop on its current node
ce46a7
+    while (role != RSC_ROLE_STOPPED) {
ce46a7
+        next_role = rsc_state_matrix[role][RSC_ROLE_STOPPED];
ce46a7
+        pe_rsc_trace(rsc, "Creating %s action to take %s down from %s to %s",
ce46a7
+                     (need_stop? "required" : "optional"), rsc->id,
ce46a7
+                     role2text(role), role2text(next_role));
ce46a7
+        if (!rsc_action_matrix[role][next_role](rsc, current, !need_stop,
ce46a7
+                                                rsc->cluster)) {
ce46a7
+            break;
ce46a7
+        }
ce46a7
+        role = next_role;
ce46a7
+    }
ce46a7
+
ce46a7
+    // Bring resource up to its next role on its next node
ce46a7
+    while ((rsc->role <= rsc->next_role) && (role != rsc->role)
ce46a7
+           && !pcmk_is_set(rsc->flags, pe_rsc_block)) {
ce46a7
+        bool required = need_stop;
ce46a7
+
ce46a7
+        next_role = rsc_state_matrix[role][rsc->role];
ce46a7
+        if ((next_role == RSC_ROLE_PROMOTED) && need_promote) {
ce46a7
+            required = true;
ce46a7
+        }
ce46a7
+        pe_rsc_trace(rsc, "Creating %s action to take %s up from %s to %s",
ce46a7
+                     (required? "required" : "optional"), rsc->id,
ce46a7
+                     role2text(role), role2text(next_role));
ce46a7
+        if (!rsc_action_matrix[role][next_role](rsc, chosen, !required,
ce46a7
+                                                rsc->cluster)) {
ce46a7
+            break;
ce46a7
+        }
ce46a7
+        role = next_role;
ce46a7
+    }
ce46a7
+}
ce46a7
+
ce46a7
 void
ce46a7
 native_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
 {
ce46a7
@@ -1332,39 +1384,10 @@ native_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
     /* Create any additional actions required when bringing resource down and
ce46a7
      * back up to same level.
ce46a7
      */
ce46a7
-    role = rsc->role;
ce46a7
-    while (role != RSC_ROLE_STOPPED) {
ce46a7
-        next_role = rsc_state_matrix[role][RSC_ROLE_STOPPED];
ce46a7
-        pe_rsc_trace(rsc, "Creating %s action to take %s down from %s to %s",
ce46a7
-                     (need_stop? "required" : "optional"), rsc->id,
ce46a7
-                     role2text(role), role2text(next_role));
ce46a7
-        if (rsc_action_matrix[role][next_role] (rsc, current, !need_stop, data_set) == FALSE) {
ce46a7
-            break;
ce46a7
-        }
ce46a7
-        role = next_role;
ce46a7
-    }
ce46a7
-
ce46a7
-
ce46a7
-    while ((rsc->role <= rsc->next_role) && (role != rsc->role)
ce46a7
-           && !pcmk_is_set(rsc->flags, pe_rsc_block)) {
ce46a7
-        bool required = need_stop;
ce46a7
-
ce46a7
-        next_role = rsc_state_matrix[role][rsc->role];
ce46a7
-        if ((next_role == RSC_ROLE_PROMOTED) && need_promote) {
ce46a7
-            required = true;
ce46a7
-        }
ce46a7
-        pe_rsc_trace(rsc, "Creating %s action to take %s up from %s to %s",
ce46a7
-                     (required? "required" : "optional"), rsc->id,
ce46a7
-                     role2text(role), role2text(next_role));
ce46a7
-        if (rsc_action_matrix[role][next_role](rsc, chosen, !required,
ce46a7
-                                               data_set) == FALSE) {
ce46a7
-            break;
ce46a7
-        }
ce46a7
-        role = next_role;
ce46a7
-    }
ce46a7
-    role = rsc->role;
ce46a7
+    schedule_restart_actions(rsc, current, chosen, need_stop, need_promote);
ce46a7
 
ce46a7
     /* Required steps from this role to the next */
ce46a7
+    role = rsc->role;
ce46a7
     while (role != rsc->next_role) {
ce46a7
         next_role = rsc_state_matrix[role][rsc->next_role];
ce46a7
         pe_rsc_trace(rsc, "Creating action to take %s from %s to %s (ending at %s)",
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 736d4d8f5e432acf12e577d137e9165904c71b3b Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Mon, 28 Mar 2022 17:42:26 -0500
ce46a7
Subject: [PATCH 3/9] Log: scheduler: improve trace messages when creating
ce46a7
 actions
ce46a7
ce46a7
---
ce46a7
 lib/pacemaker/pcmk_sched_native.c | 22 ++++++++++++++++------
ce46a7
 1 file changed, 16 insertions(+), 6 deletions(-)
ce46a7
ce46a7
diff --git a/lib/pacemaker/pcmk_sched_native.c b/lib/pacemaker/pcmk_sched_native.c
ce46a7
index b8a1c1e1a..8b651ebd2 100644
ce46a7
--- a/lib/pacemaker/pcmk_sched_native.c
ce46a7
+++ b/lib/pacemaker/pcmk_sched_native.c
ce46a7
@@ -1997,7 +1997,6 @@ StopRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_set
ce46a7
     GList *gIter = NULL;
ce46a7
 
ce46a7
     CRM_ASSERT(rsc);
ce46a7
-    pe_rsc_trace(rsc, "%s", rsc->id);
ce46a7
 
ce46a7
     for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
ce46a7
         pe_node_t *current = (pe_node_t *) gIter->data;
ce46a7
@@ -2005,16 +2004,23 @@ StopRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_set
ce46a7
 
ce46a7
         if (rsc->partial_migration_target) {
ce46a7
             if (rsc->partial_migration_target->details == current->details) {
ce46a7
-                pe_rsc_trace(rsc, "Filtered %s -> %s %s", current->details->uname,
ce46a7
-                             next->details->uname, rsc->id);
ce46a7
+                pe_rsc_trace(rsc,
ce46a7
+                             "Skipping stop of %s on %s "
ce46a7
+                             "because migration to %s in progress",
ce46a7
+                             rsc->id, current->details->uname,
ce46a7
+                             next->details->uname);
ce46a7
                 continue;
ce46a7
             } else {
ce46a7
-                pe_rsc_trace(rsc, "Forced on %s %s", current->details->uname, rsc->id);
ce46a7
+                pe_rsc_trace(rsc,
ce46a7
+                             "Forcing stop of %s on %s "
ce46a7
+                             "because migration target changed",
ce46a7
+                             rsc->id, current->details->uname);
ce46a7
                 optional = FALSE;
ce46a7
             }
ce46a7
         }
ce46a7
 
ce46a7
-        pe_rsc_trace(rsc, "%s on %s", rsc->id, current->details->uname);
ce46a7
+        pe_rsc_trace(rsc, "Scheduling stop of %s on %s",
ce46a7
+                     rsc->id, current->details->uname);
ce46a7
         stop = stop_action(rsc, current, optional);
ce46a7
 
ce46a7
         if(rsc->allocated_to == NULL) {
ce46a7
@@ -2048,7 +2054,11 @@ StartRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_se
ce46a7
     pe_action_t *start = NULL;
ce46a7
 
ce46a7
     CRM_ASSERT(rsc);
ce46a7
-    pe_rsc_trace(rsc, "%s on %s %d %d", rsc->id, next ? next->details->uname : "N/A", optional, next ? next->weight : 0);
ce46a7
+
ce46a7
+    pe_rsc_trace(rsc, "Scheduling %s start of %s on %s (weight=%d)",
ce46a7
+                 (optional? "optional" : "required"), rsc->id,
ce46a7
+                 ((next == NULL)? "N/A" : next->details->uname),
ce46a7
+                 ((next == NULL)? 0 : next->weight));
ce46a7
     start = start_action(rsc, next, TRUE);
ce46a7
 
ce46a7
     pcmk__order_vs_unfence(rsc, next, start, pe_order_implies_then, data_set);
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 6f987234d5246ed50f4fe2db90e5edb6a23e877d Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Tue, 1 Mar 2022 16:42:06 -0600
ce46a7
Subject: [PATCH 4/9] Log: scheduler: log a warning if invalid value is given
ce46a7
 for multiple-active
ce46a7
ce46a7
---
ce46a7
 lib/pengine/complex.c | 7 ++++++-
ce46a7
 1 file changed, 6 insertions(+), 1 deletion(-)
ce46a7
ce46a7
diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c
ce46a7
index e82af2aae..f2caef831 100644
ce46a7
--- a/lib/pengine/complex.c
ce46a7
+++ b/lib/pengine/complex.c
ce46a7
@@ -694,7 +694,12 @@ common_unpack(xmlNode * xml_obj, pe_resource_t ** rsc,
ce46a7
         (*rsc)->recovery_type = recovery_block;
ce46a7
         pe_rsc_trace((*rsc), "\tMultiple running resource recovery: block");
ce46a7
 
ce46a7
-    } else {
ce46a7
+    } else { // "stop_start"
ce46a7
+        if (!pcmk__str_eq(value, "stop_start",
ce46a7
+                          pcmk__str_casei|pcmk__str_null_matches)) {
ce46a7
+            pe_warn("%s is not a valid value for " XML_RSC_ATTR_MULTIPLE
ce46a7
+                    ", using default of \"stop_start\"", value);
ce46a7
+        }
ce46a7
         (*rsc)->recovery_type = recovery_stop_start;
ce46a7
         pe_rsc_trace((*rsc), "\tMultiple running resource recovery: stop/start");
ce46a7
     }
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 50456c3e229a6021ca0ba7346af41cd234abcc16 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Tue, 1 Mar 2022 16:49:31 -0600
ce46a7
Subject: [PATCH 5/9] API: libpe_status: add recovery_stop_unexpected to enum
ce46a7
 rsc_recovery_type
ce46a7
ce46a7
The behavior is not implemented as of this commit
ce46a7
---
ce46a7
 include/crm/pengine/common.h | 14 ++++++++++++--
ce46a7
 lib/pengine/complex.c        |  5 +++++
ce46a7
 lib/pengine/native.c         |  7 +++++--
ce46a7
 3 files changed, 22 insertions(+), 4 deletions(-)
ce46a7
ce46a7
diff --git a/include/crm/pengine/common.h b/include/crm/pengine/common.h
ce46a7
index efe89a171..9b9f38f3b 100644
ce46a7
--- a/include/crm/pengine/common.h
ce46a7
+++ b/include/crm/pengine/common.h
ce46a7
@@ -1,5 +1,5 @@
ce46a7
 /*
ce46a7
- * Copyright 2004-2021 the Pacemaker project contributors
ce46a7
+ * Copyright 2004-2022 the Pacemaker project contributors
ce46a7
  *
ce46a7
  * The version control history for this file may have further details.
ce46a7
  *
ce46a7
@@ -78,7 +78,8 @@ enum action_tasks {
ce46a7
 enum rsc_recovery_type {
ce46a7
     recovery_stop_start,
ce46a7
     recovery_stop_only,
ce46a7
-    recovery_block
ce46a7
+    recovery_block,
ce46a7
+    recovery_stop_unexpected,
ce46a7
 };
ce46a7
 
ce46a7
 enum rsc_start_requirement {
ce46a7
@@ -143,6 +144,13 @@ const char *fail2text(enum action_fail_response fail);
ce46a7
 const char *pe_pref(GHashTable * options, const char *name);
ce46a7
 void calculate_active_ops(GList * sorted_op_list, int *start_index, int *stop_index);
ce46a7
 
ce46a7
+/*!
ce46a7
+ * \brief Get readable description of a recovery type
ce46a7
+ *
ce46a7
+ * \param[in] type  Recovery type
ce46a7
+ *
ce46a7
+ * \return Static string describing \p type
ce46a7
+ */
ce46a7
 static inline const char *
ce46a7
 recovery2text(enum rsc_recovery_type type)
ce46a7
 {
ce46a7
@@ -153,6 +161,8 @@ recovery2text(enum rsc_recovery_type type)
ce46a7
             return "attempting recovery";
ce46a7
         case recovery_block:
ce46a7
             return "waiting for an administrator";
ce46a7
+        case recovery_stop_unexpected:
ce46a7
+            return "stopping unexpected instances";
ce46a7
     }
ce46a7
     return "Unknown";
ce46a7
 }
ce46a7
diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c
ce46a7
index f2caef831..fc9028e81 100644
ce46a7
--- a/lib/pengine/complex.c
ce46a7
+++ b/lib/pengine/complex.c
ce46a7
@@ -694,6 +694,11 @@ common_unpack(xmlNode * xml_obj, pe_resource_t ** rsc,
ce46a7
         (*rsc)->recovery_type = recovery_block;
ce46a7
         pe_rsc_trace((*rsc), "\tMultiple running resource recovery: block");
ce46a7
 
ce46a7
+    } else if (pcmk__str_eq(value, "stop_unexpected", pcmk__str_casei)) {
ce46a7
+        (*rsc)->recovery_type = recovery_stop_unexpected;
ce46a7
+        pe_rsc_trace((*rsc), "\tMultiple running resource recovery: "
ce46a7
+                             "stop unexpected instances");
ce46a7
+
ce46a7
     } else { // "stop_start"
ce46a7
         if (!pcmk__str_eq(value, "stop_start",
ce46a7
                           pcmk__str_casei|pcmk__str_null_matches)) {
ce46a7
diff --git a/lib/pengine/native.c b/lib/pengine/native.c
ce46a7
index e16e54bae..fa7dc8960 100644
ce46a7
--- a/lib/pengine/native.c
ce46a7
+++ b/lib/pengine/native.c
ce46a7
@@ -149,8 +149,6 @@ native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * dat
ce46a7
                     }
ce46a7
                 }
ce46a7
                 break;
ce46a7
-            case recovery_stop_start:
ce46a7
-                break;
ce46a7
             case recovery_block:
ce46a7
                 pe__clear_resource_flags(rsc, pe_rsc_managed);
ce46a7
                 pe__set_resource_flags(rsc, pe_rsc_block);
ce46a7
@@ -171,6 +169,11 @@ native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * dat
ce46a7
                     }
ce46a7
                 }
ce46a7
                 break;
ce46a7
+            default: // recovery_stop_start, recovery_stop_unexpected
ce46a7
+                /* The scheduler will do the right thing because the relevant
ce46a7
+                 * variables and flags are set when unpacking the history.
ce46a7
+                 */
ce46a7
+                break;
ce46a7
         }
ce46a7
         crm_debug("%s is active on multiple nodes including %s: %s",
ce46a7
                   rsc->id, node->details->uname,
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 5e994f0633b27e7a53701e0954466739c8f1acf7 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Wed, 30 Mar 2022 16:26:19 -0500
ce46a7
Subject: [PATCH 6/9] API: libpe_status: add pe_rsc_stop_unexpected flag
ce46a7
ce46a7
---
ce46a7
 include/crm/pengine/pe_types.h | 1 +
ce46a7
 1 file changed, 1 insertion(+)
ce46a7
ce46a7
diff --git a/include/crm/pengine/pe_types.h b/include/crm/pengine/pe_types.h
ce46a7
index e3ecaa823..7d5394bff 100644
ce46a7
--- a/include/crm/pengine/pe_types.h
ce46a7
+++ b/include/crm/pengine/pe_types.h
ce46a7
@@ -277,6 +277,7 @@ struct pe_node_s {
ce46a7
 
ce46a7
 #  define pe_rsc_starting                   0x00100000ULL
ce46a7
 #  define pe_rsc_stopping                   0x00200000ULL
ce46a7
+#  define pe_rsc_stop_unexpected            0x00400000ULL
ce46a7
 #  define pe_rsc_allow_migrate              0x00800000ULL
ce46a7
 
ce46a7
 #  define pe_rsc_failure_ignored            0x01000000ULL
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From c1acf05be853d99c17761759b8c961f2ec4a55c2 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Thu, 31 Mar 2022 09:56:34 -0500
ce46a7
Subject: [PATCH 7/9] API: libpe_status: add pe_rsc_restarting flag
ce46a7
ce46a7
This is used to indicate that any actions currently being scheduled are part of
ce46a7
the resource's restart actions (i.e. we are in schedule_restart_actions()).
ce46a7
---
ce46a7
 include/crm/pengine/pe_types.h    | 1 +
ce46a7
 lib/pacemaker/pcmk_sched_native.c | 4 ++++
ce46a7
 2 files changed, 5 insertions(+)
ce46a7
ce46a7
diff --git a/include/crm/pengine/pe_types.h b/include/crm/pengine/pe_types.h
ce46a7
index 7d5394bff..77d28e900 100644
ce46a7
--- a/include/crm/pengine/pe_types.h
ce46a7
+++ b/include/crm/pengine/pe_types.h
ce46a7
@@ -265,6 +265,7 @@ struct pe_node_s {
ce46a7
 #  define pe_rsc_provisional                0x00000100ULL
ce46a7
 #  define pe_rsc_allocating                 0x00000200ULL
ce46a7
 #  define pe_rsc_merging                    0x00000400ULL
ce46a7
+#  define pe_rsc_restarting                 0x00000800ULL
ce46a7
 
ce46a7
 #  define pe_rsc_stop                       0x00001000ULL
ce46a7
 #  define pe_rsc_reload                     0x00002000ULL
ce46a7
diff --git a/lib/pacemaker/pcmk_sched_native.c b/lib/pacemaker/pcmk_sched_native.c
ce46a7
index 8b651ebd2..8002938b5 100644
ce46a7
--- a/lib/pacemaker/pcmk_sched_native.c
ce46a7
+++ b/lib/pacemaker/pcmk_sched_native.c
ce46a7
@@ -1204,6 +1204,8 @@ schedule_restart_actions(pe_resource_t *rsc, pe_node_t *current,
ce46a7
     enum rsc_role_e role = rsc->role;
ce46a7
     enum rsc_role_e next_role;
ce46a7
 
ce46a7
+    pe__set_resource_flags(rsc, pe_rsc_restarting);
ce46a7
+
ce46a7
     // Bring resource down to a stop on its current node
ce46a7
     while (role != RSC_ROLE_STOPPED) {
ce46a7
         next_role = rsc_state_matrix[role][RSC_ROLE_STOPPED];
ce46a7
@@ -1235,6 +1237,8 @@ schedule_restart_actions(pe_resource_t *rsc, pe_node_t *current,
ce46a7
         }
ce46a7
         role = next_role;
ce46a7
     }
ce46a7
+
ce46a7
+    pe__clear_resource_flags(rsc, pe_rsc_restarting);
ce46a7
 }
ce46a7
 
ce46a7
 void
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 871e2201d92520039df45062afc9120fd1fb0f30 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Tue, 1 Mar 2022 17:46:39 -0600
ce46a7
Subject: [PATCH 8/9] Refactor: scheduler: add expected node to primitive
ce46a7
 variant data
ce46a7
ce46a7
Nothing uses it yet
ce46a7
---
ce46a7
 include/crm/pengine/internal.h |  4 ++++
ce46a7
 lib/pengine/native.c           | 38 ++++++++++++++++++++++++++++++++++
ce46a7
 lib/pengine/variant.h          |  8 +++++--
ce46a7
 3 files changed, 48 insertions(+), 2 deletions(-)
ce46a7
ce46a7
diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
ce46a7
index f949684b4..f69e6bcce 100644
ce46a7
--- a/include/crm/pengine/internal.h
ce46a7
+++ b/include/crm/pengine/internal.h
ce46a7
@@ -579,4 +579,8 @@ xmlNode *pe__failed_probe_for_rsc(pe_resource_t *rsc, const char *name);
ce46a7
 
ce46a7
 const char *pe__clone_child_id(pe_resource_t *rsc);
ce46a7
 
ce46a7
+void pe__update_expected_node(pe_resource_t *rsc, pe_node_t *node,
ce46a7
+                              int execution_status, int exit_status,
ce46a7
+                              int expected_exit_status);
ce46a7
+
ce46a7
 #endif
ce46a7
diff --git a/lib/pengine/native.c b/lib/pengine/native.c
ce46a7
index fa7dc8960..591d1c6f5 100644
ce46a7
--- a/lib/pengine/native.c
ce46a7
+++ b/lib/pengine/native.c
ce46a7
@@ -1376,3 +1376,41 @@ pe__native_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_paren
ce46a7
 
ce46a7
     return TRUE;
ce46a7
 }
ce46a7
+
ce46a7
+/*!
ce46a7
+ * \internal
ce46a7
+ * \brief Set a resource's expected node if appropriate for a history result
ce46a7
+ *
ce46a7
+ * \param[in] rsc               Resource to set expected node for
ce46a7
+ * \param[in] node              Node to set as expected node
ce46a7
+ * \param[in] execution_status  History entry's execution status
ce46a7
+ * \param[in] exit_status       History entry's actual exit status
ce46a7
+ * \param[in] expected_status   History entry's expected exit status
ce46a7
+ */
ce46a7
+void
ce46a7
+pe__update_expected_node(pe_resource_t *rsc, pe_node_t *node,
ce46a7
+                         int execution_status, int exit_status,
ce46a7
+                         int expected_exit_status)
ce46a7
+{
ce46a7
+    native_variant_data_t *native_data = NULL;
ce46a7
+
ce46a7
+    get_native_variant_data(native_data, rsc);
ce46a7
+
ce46a7
+    if ((rsc->recovery_type == recovery_stop_unexpected)
ce46a7
+        && (rsc->role > RSC_ROLE_STOPPED)
ce46a7
+        && (execution_status == PCMK_EXEC_DONE)
ce46a7
+        && (exit_status == expected_exit_status)) {
ce46a7
+        // Resource is active and was expected on this node
ce46a7
+        pe_rsc_trace(rsc, "Found expected node %s for %s",
ce46a7
+                     node->details->uname, rsc->id);
ce46a7
+        native_data->expected_node = node;
ce46a7
+        pe__set_resource_flags(rsc, pe_rsc_stop_unexpected);
ce46a7
+
ce46a7
+    } else if ((native_data->expected_node != NULL)
ce46a7
+               && (native_data->expected_node->details == node->details)) {
ce46a7
+        // Resource is not cleanly active here
ce46a7
+        pe_rsc_trace(rsc, "Clearing expected node for %s", rsc->id);
ce46a7
+        native_data->expected_node = NULL;
ce46a7
+        pe__clear_resource_flags(rsc, pe_rsc_stop_unexpected);
ce46a7
+    }
ce46a7
+}
ce46a7
diff --git a/lib/pengine/variant.h b/lib/pengine/variant.h
ce46a7
index cabfbe81f..d8fefa9d6 100644
ce46a7
--- a/lib/pengine/variant.h
ce46a7
+++ b/lib/pengine/variant.h
ce46a7
@@ -1,5 +1,5 @@
ce46a7
 /*
ce46a7
- * Copyright 2004-2021 the Pacemaker project contributors
ce46a7
+ * Copyright 2004-2022 the Pacemaker project contributors
ce46a7
  *
ce46a7
  * The version control history for this file may have further details.
ce46a7
  *
ce46a7
@@ -139,7 +139,11 @@ typedef struct group_variant_data_s {
ce46a7
 #  elif VARIANT_NATIVE
ce46a7
 
ce46a7
 typedef struct native_variant_data_s {
ce46a7
-    int dummy;
ce46a7
+    /* If the resource is multiply active, and has multiple-active set to
ce46a7
+     * stop_unexpected, this will be set to the node where the resource was
ce46a7
+     * found active by an operation with a expected result.
ce46a7
+     */
ce46a7
+    pe_node_t *expected_node;
ce46a7
 } native_variant_data_t;
ce46a7
 
ce46a7
 #    define get_native_variant_data(data, rsc)				\
ce46a7
-- 
ce46a7
2.27.0
ce46a7
ce46a7
ce46a7
From 0e4e17e972f1c3663389f18d8f8c527bd819b3c5 Mon Sep 17 00:00:00 2001
ce46a7
From: Ken Gaillot <kgaillot@redhat.com>
ce46a7
Date: Thu, 7 Apr 2022 10:20:00 -0500
ce46a7
Subject: [PATCH 9/9] Feature: scheduler: implement
ce46a7
 multiple-active=stop_unexpected
ce46a7
ce46a7
The default multiple-active policy of restarting the resource on all nodes
ce46a7
requires no special handling, because at least one of the locations will have
ce46a7
an unexpected rc, causing the resource to be marked as failed and restarted,
ce46a7
and StopRsc() creates stops on all nodes running the resource.
ce46a7
ce46a7
The new stop_unexpected behavior relies on most of the same handling, but
ce46a7
the action creation functions need to skip the node where the resource had the
ce46a7
expected result. For that, we set the new rsc->expected_node when unpacking a
ce46a7
successful result, to be checked by those functions.
ce46a7
ce46a7
Note that this still schedules a start for the resource, which is a pseudo-op
ce46a7
for the resource itself, but (properly) causes any dependent resources to be
ce46a7
restarted.
ce46a7
ce46a7
Fixes T23
ce46a7
---
ce46a7
 lib/pacemaker/pcmk_output.c       | 10 ++++
ce46a7
 lib/pacemaker/pcmk_sched_native.c | 94 ++++++++++++++++++++++++++++++-
ce46a7
 lib/pengine/unpack.c              |  1 +
ce46a7
 3 files changed, 103 insertions(+), 2 deletions(-)
ce46a7
ce46a7
diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c
ce46a7
index 56963a93f..9a522a3e5 100644
ce46a7
--- a/lib/pacemaker/pcmk_output.c
ce46a7
+++ b/lib/pacemaker/pcmk_output.c
ce46a7
@@ -918,6 +918,16 @@ rsc_action_default(pcmk__output_t *out, va_list args)
ce46a7
     if (possible_matches) {
ce46a7
         stop = possible_matches->data;
ce46a7
         g_list_free(possible_matches);
ce46a7
+    } else if (pcmk_is_set(rsc->flags, pe_rsc_stop_unexpected)) {
ce46a7
+        /* The resource is multiply active with multiple-active set to
ce46a7
+         * stop_unexpected, and not stopping on its current node, but it should
ce46a7
+         * be stopping elsewhere.
ce46a7
+         */
ce46a7
+        possible_matches = pe__resource_actions(rsc, NULL, RSC_STOP, FALSE);
ce46a7
+        if (possible_matches != NULL) {
ce46a7
+            stop = possible_matches->data;
ce46a7
+            g_list_free(possible_matches);
ce46a7
+        }
ce46a7
     }
ce46a7
 
ce46a7
     possible_matches = pe__resource_actions(rsc, next, RSC_PROMOTE, FALSE);
ce46a7
diff --git a/lib/pacemaker/pcmk_sched_native.c b/lib/pacemaker/pcmk_sched_native.c
ce46a7
index 8002938b5..c0224849f 100644
ce46a7
--- a/lib/pacemaker/pcmk_sched_native.c
ce46a7
+++ b/lib/pacemaker/pcmk_sched_native.c
ce46a7
@@ -1259,7 +1259,10 @@ native_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
     enum rsc_role_e role = RSC_ROLE_UNKNOWN;
ce46a7
     enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
ce46a7
 
ce46a7
-    CRM_ASSERT(rsc);
ce46a7
+    native_variant_data_t *native_data = NULL;
ce46a7
+
ce46a7
+    get_native_variant_data(native_data, rsc);
ce46a7
+
ce46a7
     chosen = rsc->allocated_to;
ce46a7
     next_role = rsc->next_role;
ce46a7
     if (next_role == RSC_ROLE_UNKNOWN) {
ce46a7
@@ -1323,6 +1326,7 @@ native_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
                        "(will stop on both nodes)",
ce46a7
                        rsc->id, rsc->partial_migration_source->details->uname,
ce46a7
                        rsc->partial_migration_target->details->uname);
ce46a7
+            multiply_active = false;
ce46a7
 
ce46a7
         } else {
ce46a7
             const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
ce46a7
@@ -1345,6 +1349,11 @@ native_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
         allow_migrate = FALSE;
ce46a7
     }
ce46a7
 
ce46a7
+    if (!multiply_active) {
ce46a7
+        native_data->expected_node = NULL;
ce46a7
+        pe__clear_resource_flags(rsc, pe_rsc_stop_unexpected);
ce46a7
+    }
ce46a7
+
ce46a7
     if (pcmk_is_set(rsc->flags, pe_rsc_start_pending)) {
ce46a7
         pe_rsc_trace(rsc, "Creating start action for %s to represent already pending start",
ce46a7
                      rsc->id);
ce46a7
@@ -1995,6 +2004,32 @@ native_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
ce46a7
     out->message(out, "rsc-action", rsc, current, next);
ce46a7
 }
ce46a7
 
ce46a7
+/*!
ce46a7
+ * \internal
ce46a7
+ * \brief Check whether a node is a multiply active resource's expected node
ce46a7
+ *
ce46a7
+ * \param[in] rsc  Resource to check
ce46a7
+ * \param[in] node  Node to check
ce46a7
+ *
ce46a7
+ * \return true if \p rsc is multiply active with multiple-active set to
ce46a7
+ *         stop_unexpected, and \p node is the node where it will remain active
ce46a7
+ * \note This assumes that the resource's next role cannot be changed to stopped
ce46a7
+ *       after this is called, which should be reasonable if status has already
ce46a7
+ *       been unpacked and resources have been assigned to nodes.
ce46a7
+ */
ce46a7
+static bool
ce46a7
+is_expected_node(const pe_resource_t *rsc, const pe_node_t *node)
ce46a7
+{
ce46a7
+    native_variant_data_t *native_data = NULL;
ce46a7
+
ce46a7
+    get_native_variant_data(native_data, rsc);
ce46a7
+    return pcmk_all_flags_set(rsc->flags,
ce46a7
+                              pe_rsc_stop_unexpected|pe_rsc_restarting)
ce46a7
+           && (rsc->next_role > RSC_ROLE_STOPPED)
ce46a7
+           && (native_data->expected_node != NULL) && (node != NULL)
ce46a7
+           && (native_data->expected_node->details == node->details);
ce46a7
+}
ce46a7
+
ce46a7
 gboolean
ce46a7
 StopRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_set_t * data_set)
ce46a7
 {
ce46a7
@@ -2006,6 +2041,18 @@ StopRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_set
ce46a7
         pe_node_t *current = (pe_node_t *) gIter->data;
ce46a7
         pe_action_t *stop;
ce46a7
 
ce46a7
+        if (is_expected_node(rsc, current)) {
ce46a7
+            /* We are scheduling restart actions for a multiply active resource
ce46a7
+             * with multiple-active=stop_unexpected, and this is where it should
ce46a7
+             * not be stopped.
ce46a7
+             */
ce46a7
+            pe_rsc_trace(rsc,
ce46a7
+                         "Skipping stop of multiply active resource %s "
ce46a7
+                         "on expected node %s",
ce46a7
+                         rsc->id, current->details->uname);
ce46a7
+            continue;
ce46a7
+        }
ce46a7
+
ce46a7
         if (rsc->partial_migration_target) {
ce46a7
             if (rsc->partial_migration_target->details == current->details) {
ce46a7
                 pe_rsc_trace(rsc,
ce46a7
@@ -2029,6 +2076,17 @@ StopRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_set
ce46a7
 
ce46a7
         if(rsc->allocated_to == NULL) {
ce46a7
             pe_action_set_reason(stop, "node availability", TRUE);
ce46a7
+        } else if (pcmk_is_set(rsc->flags, pe_rsc_restarting)) {
ce46a7
+            native_variant_data_t *native_data = NULL;
ce46a7
+
ce46a7
+            get_native_variant_data(native_data, rsc);
ce46a7
+            if (native_data->expected_node != NULL) {
ce46a7
+                /* We are stopping a multiply active resource on a node that is
ce46a7
+                 * not its expected node, and we are still scheduling restart
ce46a7
+                 * actions, so the stop is for being multiply active.
ce46a7
+                 */
ce46a7
+                pe_action_set_reason(stop, "being multiply active", TRUE);
ce46a7
+            }
ce46a7
         }
ce46a7
 
ce46a7
         if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
ce46a7
@@ -2071,6 +2129,16 @@ StartRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_se
ce46a7
         pe__clear_action_flags(start, pe_action_optional);
ce46a7
     }
ce46a7
 
ce46a7
+    if (is_expected_node(rsc, next)) {
ce46a7
+        /* This could be a problem if the start becomes necessary for other
ce46a7
+         * reasons later.
ce46a7
+         */
ce46a7
+        pe_rsc_trace(rsc,
ce46a7
+                     "Start of multiply active resouce %s "
ce46a7
+                     "on expected node %s will be a pseudo-action",
ce46a7
+                     rsc->id, next->details->uname);
ce46a7
+        pe__set_action_flags(start, pe_action_pseudo);
ce46a7
+    }
ce46a7
 
ce46a7
     return TRUE;
ce46a7
 }
ce46a7
@@ -2084,6 +2152,7 @@ PromoteRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_
ce46a7
 
ce46a7
     CRM_ASSERT(rsc);
ce46a7
     CRM_CHECK(next != NULL, return FALSE);
ce46a7
+
ce46a7
     pe_rsc_trace(rsc, "%s on %s", rsc->id, next->details->uname);
ce46a7
 
ce46a7
     action_list = pe__resource_actions(rsc, next, RSC_START, TRUE);
ce46a7
@@ -2098,7 +2167,19 @@ PromoteRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_
ce46a7
     g_list_free(action_list);
ce46a7
 
ce46a7
     if (runnable) {
ce46a7
-        promote_action(rsc, next, optional);
ce46a7
+        pe_action_t *promote = promote_action(rsc, next, optional);
ce46a7
+
ce46a7
+        if (is_expected_node(rsc, next)) {
ce46a7
+            /* This could be a problem if the promote becomes necessary for
ce46a7
+             * other reasons later.
ce46a7
+             */
ce46a7
+            pe_rsc_trace(rsc,
ce46a7
+                         "Promotion of multiply active resouce %s "
ce46a7
+                         "on expected node %s will be a pseudo-action",
ce46a7
+                         rsc->id, next->details->uname);
ce46a7
+            pe__set_action_flags(promote, pe_action_pseudo);
ce46a7
+        }
ce46a7
+
ce46a7
         return TRUE;
ce46a7
     }
ce46a7
 
ce46a7
@@ -2122,6 +2203,15 @@ DemoteRsc(pe_resource_t * rsc, pe_node_t * next, gboolean optional, pe_working_s
ce46a7
     GList *gIter = NULL;
ce46a7
 
ce46a7
     CRM_ASSERT(rsc);
ce46a7
+
ce46a7
+    if (is_expected_node(rsc, next)) {
ce46a7
+        pe_rsc_trace(rsc,
ce46a7
+                     "Skipping demote of multiply active resource %s "
ce46a7
+                     "on expected node %s",
ce46a7
+                     rsc->id, next->details->uname);
ce46a7
+        return TRUE;
ce46a7
+    }
ce46a7
+
ce46a7
     pe_rsc_trace(rsc, "%s", rsc->id);
ce46a7
 
ce46a7
     /* CRM_CHECK(rsc->next_role == RSC_ROLE_UNPROMOTED, return FALSE); */
ce46a7
diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
ce46a7
index d218f523f..edaa9de48 100644
ce46a7
--- a/lib/pengine/unpack.c
ce46a7
+++ b/lib/pengine/unpack.c
ce46a7
@@ -3974,6 +3974,7 @@ unpack_rsc_op(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op,
ce46a7
     }
ce46a7
 
ce46a7
 done:
ce46a7
+    pe__update_expected_node(rsc, node, status, rc, target_rc);
ce46a7
     pe_rsc_trace(rsc, "Resource %s after %s: role=%s, next=%s",
ce46a7
                  rsc->id, task, role2text(rsc->role),
ce46a7
                  role2text(rsc->next_role));
ce46a7
-- 
ce46a7
2.27.0
ce46a7