**Build scan:**
https://gradle-enterprise.elastic.co/s/ccuezgxbievzg/tests/:server:internalClusterTest/org.elasticsearch.recovery.FullRollingRestartIT/testNoRebalanceOnRollingRestart

**Reproduction line:**
`./gradlew ':server:internalClusterTest' --tests "org.elasticsearch.recovery.FullRollingRestartIT.testNoRebalanceOnRollingRestart" -Dtests.seed=41CBBA733A6A03C3 -Dtests.locale=ga-IE -Dtests.timezone=Asia/Dili -Druntime.java=17`

**Applicable branches:**
main

**Reproduces locally?:**
No

**Failure history:**
https://gradle-enterprise.elastic.co/scans/tests?tests.container=org.elasticsearch.recovery.FullRollingRestartIT&tests.test=testNoRebalanceOnRollingRestart

**Failure excerpt:**
```
java.lang.AssertionError: relocated from: {node_t3}{EyyY-ftJSNudMYp5ZaNFdg}{og_ER-C-Sm-ycZCX9Ud44g}{node_t3}{127.0.0.1}{127.0.0.1:18854}{d} to: {node_t2}{omgXq9tVTbupq30bjCzm8w}{vlVodKB7QeKUdh92j9_WlA}{node_t2}{127.0.0.1}{127.0.0.1:18852}{d}-- 
before: 
cluster uuid: mEXdG06hSQGGtxtIaiKfZw [committed: true]
version: 13
state uuid: 47_pnsK9Q8SnGtede1V5HA
from_diff: false
meta data version: 8
   coordination_metadata:
      term: 1
      last_committed_config: VotingConfiguration{-dRfiVsgS0GqVuosHJ_Fhg}
      last_accepted_config: VotingConfiguration{-dRfiVsgS0GqVuosHJ_Fhg}
      voting tombstones: []
   [test/GasklFRaSBm1M9jduWKOJA]: v[6], mv[2], sv[1], av[1]
      0: p_term [1], isa_ids [PGuXQetKQgy4AbFMN4nHhA]
      1: p_term [1], isa_ids [RR60xWjgRriA_cV4Ne4ADw]
      2: p_term [1], isa_ids [NgxmsdRYSdWaNwua6QntbQ]
      3: p_term [1], isa_ids [Dr9qdp87SMGN4BKcFaQfpg]
      4: p_term [1], isa_ids [-zPxDnYZR0SEDiyIwu5XxQ]
      5: p_term [1], isa_ids [8-NhlnM4T8K6e3pyLc3dRw]
metadata customs:
   persistent_tasks: {"last_allocation_id":2,"tasks":[{"id":"health-node","task":{"health-node":{"params":{}}},"allocation_id":2,"assignment":{"executor_node":"omgXq9tVTbupq30bjCzm8w","explanation":""},"allocation_id_on_last_status_update":1}]}   index-graveyard: IndexGraveyard[[]]
nodes: 
   {node_t1}{pAVNxSNSSqiHdFDOgpad8Q}{S8nNtWoPRhyFow3vcFWdLA}{node_t1}{127.0.0.1}{127.0.0.1:18853}{d}
   {node_t2}{omgXq9tVTbupq30bjCzm8w}{FOQwYr4dT_mUODAHRXN9wg}{node_t2}{127.0.0.1}{127.0.0.1:18852}{d}
   {node_t3}{EyyY-ftJSNudMYp5ZaNFdg}{og_ER-C-Sm-ycZCX9Ud44g}{node_t3}{127.0.0.1}{127.0.0.1:18854}{d}
   {node_t0}{-dRfiVsgS0GqVuosHJ_Fhg}{1wrgT-RGSJKJtvuMmlx_1A}{node_t0}{127.0.0.1}{127.0.0.1:18851}{m}, local, master
routing_table (version 5):
-- index [[test/GasklFRaSBm1M9jduWKOJA]]
----shard_id [test][0]
--------[test][0], node[omgXq9tVTbupq30bjCzm8w], [P], s[STARTED], a[id=PGuXQetKQgy4AbFMN4nHhA], failed_attempts[0]
----shard_id [test][1]
--------[test][1], node[EyyY-ftJSNudMYp5ZaNFdg], [P], s[STARTED], a[id=RR60xWjgRriA_cV4Ne4ADw], failed_attempts[0]
----shard_id [test][2]
--------[test][2], node[pAVNxSNSSqiHdFDOgpad8Q], [P], s[STARTED], a[id=NgxmsdRYSdWaNwua6QntbQ], failed_attempts[0]
----shard_id [test][3]
--------[test][3], node[omgXq9tVTbupq30bjCzm8w], [P], s[STARTED], a[id=Dr9qdp87SMGN4BKcFaQfpg], failed_attempts[0]
----shard_id [test][4]
--------[test][4], node[EyyY-ftJSNudMYp5ZaNFdg], [P], s[STARTED], a[id=-zPxDnYZR0SEDiyIwu5XxQ], failed_attempts[0]
----shard_id [test][5]
--------[test][5], node[pAVNxSNSSqiHdFDOgpad8Q], [P], s[STARTED], a[id=8-NhlnM4T8K6e3pyLc3dRw], failed_attempts[0]

routing_nodes:
-----node_id[omgXq9tVTbupq30bjCzm8w][V]
--------[test][0], node[omgXq9tVTbupq30bjCzm8w], [P], s[STARTED], a[id=PGuXQetKQgy4AbFMN4nHhA], failed_attempts[0]
--------[test][3], node[omgXq9tVTbupq30bjCzm8w], [P], s[STARTED], a[id=Dr9qdp87SMGN4BKcFaQfpg], failed_attempts[0]
-----node_id[EyyY-ftJSNudMYp5ZaNFdg][V]
--------[test][1], node[EyyY-ftJSNudMYp5ZaNFdg], [P], s[STARTED], a[id=RR60xWjgRriA_cV4Ne4ADw], failed_attempts[0]
--------[test][4], node[EyyY-ftJSNudMYp5ZaNFdg], [P], s[STARTED], a[id=-zPxDnYZR0SEDiyIwu5XxQ], failed_attempts[0]
-----node_id[pAVNxSNSSqiHdFDOgpad8Q][V]
--------[test][2], node[pAVNxSNSSqiHdFDOgpad8Q], [P], s[STARTED], a[id=NgxmsdRYSdWaNwua6QntbQ], failed_attempts[0]
--------[test][5], node[pAVNxSNSSqiHdFDOgpad8Q], [P], s[STARTED], a[id=8-NhlnM4T8K6e3pyLc3dRw], failed_attempts[0]
---- unassigned
customs:
   health: org.elasticsearch.health.metadata.HealthMetadata@ff2c405a

  at __randomizedtesting.SeedInfo.seed([41CBBA733A6A03C3:497E64700C4572BD]:0)
  at org.junit.Assert.fail(Assert.java:88)
  at org.junit.Assert.assertTrue(Assert.java:41)
  at org.elasticsearch.recovery.FullRollingRestartIT.testNoRebalanceOnRollingRestart(FullRollingRestartIT.java:213)
  at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
  at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
  at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:568)
  at com.carrotsearch.randomizedtesting.RandomizedRunner.invoke(RandomizedRunner.java:1758)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$8.evaluate(RandomizedRunner.java:946)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$9.evaluate(RandomizedRunner.java:982)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$10.evaluate(RandomizedRunner.java:996)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at org.apache.lucene.tests.util.TestRuleSetupTeardownChained$1.evaluate(TestRuleSetupTeardownChained.java:44)
  at org.apache.lucene.tests.util.AbstractBeforeAfterRule$1.evaluate(AbstractBeforeAfterRule.java:43)
  at org.apache.lucene.tests.util.TestRuleThreadAndTestName$1.evaluate(TestRuleThreadAndTestName.java:45)
  at org.apache.lucene.tests.util.TestRuleIgnoreAfterMaxFailures$1.evaluate(TestRuleIgnoreAfterMaxFailures.java:60)
  at org.apache.lucene.tests.util.TestRuleMarkFailure$1.evaluate(TestRuleMarkFailure.java:44)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at com.carrotsearch.randomizedtesting.ThreadLeakControl$StatementRunner.run(ThreadLeakControl.java:390)
  at com.carrotsearch.randomizedtesting.ThreadLeakControl.forkTimeoutingTask(ThreadLeakControl.java:843)
  at com.carrotsearch.randomizedtesting.ThreadLeakControl$3.evaluate(ThreadLeakControl.java:490)
  at com.carrotsearch.randomizedtesting.RandomizedRunner.runSingleTest(RandomizedRunner.java:955)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$5.evaluate(RandomizedRunner.java:840)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$6.evaluate(RandomizedRunner.java:891)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$7.evaluate(RandomizedRunner.java:902)
  at org.apache.lucene.tests.util.AbstractBeforeAfterRule$1.evaluate(AbstractBeforeAfterRule.java:43)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at org.apache.lucene.tests.util.TestRuleStoreClassName$1.evaluate(TestRuleStoreClassName.java:38)
  at com.carrotsearch.randomizedtesting.rules.NoShadowingOrOverridesOnMethodsRule$1.evaluate(NoShadowingOrOverridesOnMethodsRule.java:40)
  at com.carrotsearch.randomizedtesting.rules.NoShadowingOrOverridesOnMethodsRule$1.evaluate(NoShadowingOrOverridesOnMethodsRule.java:40)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at org.apache.lucene.tests.util.TestRuleAssertionsRequired$1.evaluate(TestRuleAssertionsRequired.java:53)
  at org.apache.lucene.tests.util.AbstractBeforeAfterRule$1.evaluate(AbstractBeforeAfterRule.java:43)
  at org.apache.lucene.tests.util.TestRuleMarkFailure$1.evaluate(TestRuleMarkFailure.java:44)
  at org.apache.lucene.tests.util.TestRuleIgnoreAfterMaxFailures$1.evaluate(TestRuleIgnoreAfterMaxFailures.java:60)
  at org.apache.lucene.tests.util.TestRuleIgnoreTestSuites$1.evaluate(TestRuleIgnoreTestSuites.java:47)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at com.carrotsearch.randomizedtesting.ThreadLeakControl$StatementRunner.run(ThreadLeakControl.java:390)
  at com.carrotsearch.randomizedtesting.ThreadLeakControl.lambda$forkTimeoutingTask$0(ThreadLeakControl.java:850)
  at java.lang.Thread.run(Thread.java:833)

```
server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputerTests.java
);
        }
        clusterState = ClusterState.builder(clusterState)
            .routingTable(RoutingTable.of(clusterState.routingTable().version(), routingNodes))
            .build();
        var desiredBalance = desiredBalanceComputer.compute(
            DesiredBalance.INITIAL,
            createInput(clusterState),
            queue(
                new MoveAllocationCommand(index.getName(), 0, "node-1", "node-2"),
                new MoveAllocationCommand(index.getName(), 1, "node-1", "node-2")
            ),
            input -> true
        );
        assertDesiredAssignments(
            desiredBalance,
            Map.of(
                new ShardId(index, 0),
                new ShardAssignment(Set.of("node-0", "node-2"), 2, 0, 0),
                new ShardId(index, 1),
                new ShardAssignment(Set.of("node-0", "node-2"), 2, 0, 0)
            )
        );
    }
    public void testDesiredBalanceShouldConvergeInABigCluster() {
        var nodes = randomIntBetween(3, 7);
        var nodeIds = new ArrayList<String>(nodes);
        var discoveryNodesBuilder = DiscoveryNodes.builder();
        for (int node = 0; node < nodes; node++) {
            var nodeId = "node-" + node;