From 47debe0d06f4e87d23e543e8ea148daf98519b2b Mon Sep 17 00:00:00 2001
From: "Gao,Yan" <ygao@suse.com>
Date: Wed, 7 Dec 2022 21:52:00 +0100
Subject: [PATCH 5/6] Fix: scheduler: prevent inactive instances from starting
 if probe is unrunnable on any nodes

Although the ordering between the probe of the clone instance and the
start of its parent has been added in pcmk__probe_rsc_on_node(), we
avoided enforcing `pe_order_runnable_left` order type for that as long as
any of the clone instances are running to prevent them from being
unexpectedly stopped.

On the other hand, we still need to prevent any inactive instances from
starting unless the probe is runnable so that we don't risk starting too
many instances before we know the state on all nodes.
---
 lib/pacemaker/pcmk_sched_allocate.c | 81 ++++++++++++++++++++++++++++---
 1 file changed, 75 insertions(+), 6 deletions(-)

Index: pacemaker-2.0.4+20200616.2deceaa3a/lib/pacemaker/pcmk_sched_allocate.c
===================================================================
--- pacemaker-2.0.4+20200616.2deceaa3a.orig/lib/pacemaker/pcmk_sched_allocate.c
+++ pacemaker-2.0.4+20200616.2deceaa3a/lib/pacemaker/pcmk_sched_allocate.c
@@ -2476,6 +2476,77 @@ order_first_probes_imply_stops(pe_workin
     }
 }
 
+/*!
+ * \internal
+ * \brief Add necessary orderings between probe and starts of clone instances
+ *
+ * , in additon to the ordering with the parent resource added upon creating
+ * the probe.
+ *
+ * \param[in,out] probe     Probe as 'first' action in an ordering
+ * \param[in,out] after     'then' action wrapper in the ordering
+ */
+static void
+add_start_orderings_for_probe(pe_action_t *probe, pe_action_wrapper_t *after)
+{
+    uint32_t flags = pe_order_optional|pe_order_runnable_left;
+
+    /* Although the ordering between the probe of the clone instance and the
+     * start of its parent has been added in pcmk__probe_rsc_on_node(), we
+     * avoided enforcing `pe_order_runnable_left` order type for that as long as
+     * any of the clone instances are running to prevent them from being
+     * unexpectedly stopped.
+     *
+     * On the other hand, we still need to prevent any inactive instances from
+     * starting unless the probe is runnable so that we don't risk starting too
+     * many instances before we know the state on all nodes.
+     */
+    if (after->action->rsc->variant <= pe_group
+        || is_set(probe->flags, pe_action_runnable)
+        // The order type is already enforced for its parent.
+        || is_set(after->type, pe_order_runnable_left)
+        || uber_parent(probe->rsc) != after->action->rsc
+        || safe_str_neq(after->action->task, RSC_START)) {
+        return;
+    }
+
+    crm_trace("Adding probe start orderings for '%s@%s (%s) "
+              "then instances of %s@%s'",
+              probe->uuid,
+              probe->node ? probe->node->details->uname : "",
+              is_set(probe->flags, pe_action_runnable)? "runnable" : "unrunnable",
+              after->action->uuid,
+              after->action->node ? after->action->node->details->uname : "");
+
+    for (GList *then_iter = after->action->actions_after; then_iter != NULL;
+         then_iter = then_iter->next) {
+
+        pe_action_wrapper_t *then = (pe_action_wrapper_t *) then_iter->data;
+
+        if (then->action->rsc->running_on
+            || uber_parent(then->action->rsc) != after->action->rsc
+            || safe_str_neq(then->action->task, RSC_START)) {
+            continue;
+        }
+
+        crm_trace("Adding probe start ordering for '%s@%s (%s) "
+                  "then %s@%s' (type=%#.6x)",
+                  probe->uuid,
+                  probe->node ? probe->node->details->uname : "",
+                  is_set(probe->flags, pe_action_runnable)? "runnable" : "unrunnable",
+                  then->action->uuid,
+                  then->action->node ? then->action->node->details->uname : "",
+                  flags);
+
+        /* Prevent the instance from starting if the instance can't, but don't
+         * cause any other intances to stop if already active.
+         */
+        order_actions(probe, then->action, flags);
+    }
+
+    return;
+}
+
 static void
 order_first_probe_then_restart_repromote(pe_action_t * probe,
                                          pe_action_t * after,
@@ -2646,6 +2717,7 @@ order_first_rsc_probes(pe_resource_t * r
         for (aIter = probe->actions_after; aIter != NULL; aIter = aIter->next) {
             pe_action_wrapper_t *after_wrapper = (pe_action_wrapper_t *) aIter->data;
 
+            add_start_orderings_for_probe(probe, after_wrapper);
             order_first_probe_then_restart_repromote(probe, after_wrapper->action, data_set);
             clear_actions_tracking_flag(data_set);
         }
