This is an automated email from the ASF dual-hosted git repository.

xyuanlu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git


The following commit(s) were added to refs/heads/master by this push:
     new 054d77ad5 Instance Evacuation prevent baseline re-computation after 
dropped (#2740)
054d77ad5 is described below

commit 054d77ad577d7a0823cf9dfb360b544191d51e57
Author: Zachary Pinto <zapi...@linkedin.com>
AuthorDate: Mon Jan 29 16:18:30 2024 -0800

    Instance Evacuation prevent baseline re-computation after dropped (#2740)
    
    Instance Evacuation logic is moved to BaseControllerDataProvider cache and 
will only cause baseline recalculation when the evacuate is triggered instead 
of evacuating the node and then recalculating baseline after node is dropped 
causing more shuffling. Also fix getAllLiveInstances to exclude 
TimedOutForMaintenance nodes.
---
 .../dataproviders/BaseControllerDataProvider.java  | 31 ++++++++++++-----
 .../controller/rebalancer/AbstractRebalancer.java  |  2 +-
 .../rebalancer/DelayedAutoRebalancer.java          | 18 +++-------
 .../rebalancer/util/DelayedRebalanceUtil.java      | 20 +++--------
 .../rebalancer/waged/WagedRebalancer.java          | 10 ++----
 .../org/apache/helix/manager/zk/ZKHelixAdmin.java  |  4 ++-
 .../rebalancer/TestInstanceOperation.java          | 14 ++++++--
 .../helix/rest/server/TestPerInstanceAccessor.java | 39 +++++++++++-----------
 8 files changed, 70 insertions(+), 68 deletions(-)

diff --git 
a/helix-core/src/main/java/org/apache/helix/controller/dataproviders/BaseControllerDataProvider.java
 
b/helix-core/src/main/java/org/apache/helix/controller/dataproviders/BaseControllerDataProvider.java
index 761fb6974..c6c799dd1 100644
--- 
a/helix-core/src/main/java/org/apache/helix/controller/dataproviders/BaseControllerDataProvider.java
+++ 
b/helix-core/src/main/java/org/apache/helix/controller/dataproviders/BaseControllerDataProvider.java
@@ -128,7 +128,9 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
   private final Set<String> _enabledSwapInInstanceNames = new HashSet<>();
   private final Map<String, MonitoredAbnormalResolver> 
_abnormalStateResolverMap = new HashMap<>();
   private final Set<String> _timedOutInstanceDuringMaintenance = new 
HashSet<>();
-  private Map<String, LiveInstance> _liveInstanceExcludeTimedOutForMaintenance 
= new HashMap<>();
+  private Map<String, LiveInstance> 
_allLiveInstanceExcludeTimedOutForMaintenance = new HashMap<>();
+  private Map<String, LiveInstance> 
_assignableLiveInstanceExcludeTimedOutForMaintenance =
+      new HashMap<>();
 
   public BaseControllerDataProvider() {
     this(AbstractDataCache.UNKNOWN_CLUSTER, 
AbstractDataCache.UNKNOWN_PIPELINE);
@@ -345,7 +347,6 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
    * Refreshes the assignable instances and SWAP related caches. This should 
be called after
    * liveInstance and instanceConfig caches are refreshed. To determine what 
instances are
    * assignable and live, it takes a combination of both the all 
instanceConfigs and liveInstances.
-   * TODO: Add EVACUATE InstanceOperation to be filtered out in assignable 
nodes.
    *
    * @param instanceConfigMap InstanceConfig map from instanceConfig cache
    * @param liveInstancesMap  LiveInstance map from liveInstance cache
@@ -406,7 +407,9 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
           _assignableInstanceConfigMap.put(node, currentInstanceConfig);
           filteredInstancesByLogicalId.put(currentInstanceLogicalId, node);
         }
-      } else {
+      } else if (!currentInstanceConfig.getInstanceOperation()
+          .equals(InstanceConstants.InstanceOperation.EVACUATE.name())) {
+        // EVACUATE instances are not considered to be assignable.
         _assignableInstanceConfigMap.put(node, currentInstanceConfig);
         filteredInstancesByLogicalId.put(currentInstanceLogicalId, node);
       }
@@ -472,7 +475,8 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
     // If maintenance mode has exited, clear cached timed-out nodes
     if (!_isMaintenanceModeEnabled) {
       _timedOutInstanceDuringMaintenance.clear();
-      _liveInstanceExcludeTimedOutForMaintenance.clear();
+      _allLiveInstanceExcludeTimedOutForMaintenance.clear();
+      _assignableLiveInstanceExcludeTimedOutForMaintenance.clear();
     }
   }
 
@@ -484,21 +488,26 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
       timeOutWindow = clusterConfig.getOfflineNodeTimeOutForMaintenanceMode();
     }
     if (timeOutWindow >= 0 && isMaintenanceModeEnabled) {
-      for (String instance : _assignableLiveInstancesMap.keySet()) {
+      for (String instance : _allLiveInstanceCache.getPropertyMap().keySet()) {
         // 1. Check timed-out cache and don't do repeated work;
         // 2. Check for nodes that didn't exist in the last iteration, because 
it has been checked;
         // 3. For all other nodes, check if it's timed-out.
         // When maintenance mode is first entered, all nodes will be checked 
as a result.
         if (!_timedOutInstanceDuringMaintenance.contains(instance)
-            && 
!_liveInstanceExcludeTimedOutForMaintenance.containsKey(instance)
+            && 
!_allLiveInstanceExcludeTimedOutForMaintenance.containsKey(instance)
             && isInstanceTimedOutDuringMaintenance(accessor, instance, 
timeOutWindow)) {
           _timedOutInstanceDuringMaintenance.add(instance);
         }
       }
     }
     if (isMaintenanceModeEnabled) {
-      _liveInstanceExcludeTimedOutForMaintenance = 
_assignableLiveInstancesMap.entrySet().stream()
-          .filter(e -> 
!_timedOutInstanceDuringMaintenance.contains(e.getKey()))
+      _allLiveInstanceExcludeTimedOutForMaintenance =
+          _allLiveInstanceCache.getPropertyMap().entrySet().stream()
+              .filter(e -> 
!_timedOutInstanceDuringMaintenance.contains(e.getKey()))
+              .collect(Collectors.toMap(Map.Entry::getKey, 
Map.Entry::getValue));
+      _assignableLiveInstanceExcludeTimedOutForMaintenance =
+          _assignableLiveInstancesMap.entrySet().stream()
+              .filter(e -> 
!_timedOutInstanceDuringMaintenance.contains(e.getKey()))
               .collect(Collectors.toMap(Map.Entry::getKey, 
Map.Entry::getValue));
     }
   }
@@ -649,7 +658,7 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
    */
   public Map<String, LiveInstance> getAssignableLiveInstances() {
     if (isMaintenanceModeEnabled()) {
-      return 
Collections.unmodifiableMap(_liveInstanceExcludeTimedOutForMaintenance);
+      return 
Collections.unmodifiableMap(_assignableLiveInstanceExcludeTimedOutForMaintenance);
     }
 
     return Collections.unmodifiableMap(_assignableLiveInstancesMap);
@@ -663,6 +672,10 @@ public class BaseControllerDataProvider implements 
ControlContextProvider {
    * @return A map of LiveInstances to their instance names
    */
   public Map<String, LiveInstance> getLiveInstances() {
+    if (isMaintenanceModeEnabled()) {
+      return 
Collections.unmodifiableMap(_allLiveInstanceExcludeTimedOutForMaintenance);
+    }
+
     return _allLiveInstanceCache.getPropertyMap();
   }
 
diff --git 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/AbstractRebalancer.java
 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/AbstractRebalancer.java
index 51158cb91..160e4eda6 100644
--- 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/AbstractRebalancer.java
+++ 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/AbstractRebalancer.java
@@ -104,7 +104,7 @@ public abstract class AbstractRebalancer<T extends 
BaseControllerDataProvider> i
       List<String> preferenceList = getPreferenceList(partition, idealState,
           
Collections.unmodifiableSet(cache.getAssignableLiveInstances().keySet()));
       Map<String, String> bestStateForPartition =
-          
computeBestPossibleStateForPartition(cache.getAssignableLiveInstances().keySet(),
+          
computeBestPossibleStateForPartition(cache.getLiveInstances().keySet(),
               stateModelDef,
               preferenceList, currentStateOutput, 
disabledInstancesForPartition, idealState,
               cache.getClusterConfig(), partition,
diff --git 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/DelayedAutoRebalancer.java
 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/DelayedAutoRebalancer.java
index 56979d2aa..252b63255 100644
--- 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/DelayedAutoRebalancer.java
+++ 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/DelayedAutoRebalancer.java
@@ -19,7 +19,6 @@ package org.apache.helix.controller.rebalancer;
  * under the License.
  */
 
-import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -33,7 +32,6 @@ import java.util.Set;
 
 import org.apache.helix.HelixDefinedState;
 import org.apache.helix.api.config.StateTransitionThrottleConfig;
-import org.apache.helix.constants.InstanceConstants;
 import 
org.apache.helix.controller.dataproviders.ResourceControllerDataProvider;
 import 
org.apache.helix.controller.rebalancer.constraint.MonitoredAbnormalResolver;
 import org.apache.helix.controller.rebalancer.util.DelayedRebalanceUtil;
@@ -55,8 +53,6 @@ import org.slf4j.LoggerFactory;
  */
 public class DelayedAutoRebalancer extends 
AbstractRebalancer<ResourceControllerDataProvider> {
   private static final Logger LOG = 
LoggerFactory.getLogger(DelayedAutoRebalancer.class);
-  public static ImmutableSet<String> 
INSTANCE_OPERATION_TO_EXCLUDE_FROM_ASSIGNMENT =
-      ImmutableSet.of(InstanceConstants.InstanceOperation.EVACUATE.name());
 
   @Override
   public IdealState computeNewIdealState(String resourceName,
@@ -160,14 +156,8 @@ public class DelayedAutoRebalancer extends 
AbstractRebalancer<ResourceController
             stateCountMap, maxPartition);
 
     List<String> allNodeList = new ArrayList<>(assignableNodes);
+    List<String> liveEnabledAssignableNodeList = new 
ArrayList<>(assignableLiveEnabledNodes);
 
-    // TODO: Currently we have 2 groups of instances and compute preference 
list twice and merge.
-    // Eventually we want to have exclusive groups of instance for different 
instance tag.
-    List<String> liveEnabledAssignableNodeList = new ArrayList<>(
-        // We will not assign partitions to instances with EVACUATE 
InstanceOperation.
-        DelayedRebalanceUtil.filterOutEvacuatingInstances(
-            clusterData.getAssignableInstanceConfigMap(),
-            assignableLiveEnabledNodes));
     // sort node lists to ensure consistent preferred assignments
     Collections.sort(allNodeList);
     Collections.sort(liveEnabledAssignableNodeList);
@@ -276,7 +266,9 @@ public class DelayedAutoRebalancer extends 
AbstractRebalancer<ResourceController
           cache.getDisabledInstancesForPartition(resource.getResourceName(), 
partition.toString());
       List<String> preferenceList = getPreferenceList(partition, idealState, 
activeNodes);
       Map<String, String> bestStateForPartition =
-          computeBestPossibleStateForPartition(liveNodes, stateModelDef, 
preferenceList,
+          // We use cache.getLiveInstances().keySet() to make sure we 
gracefully handle n -> n + 1 replicas if possible
+          // when the one of the current nodes holding the replica is no 
longer considered assignable. (ex: EVACUATE)
+          
computeBestPossibleStateForPartition(cache.getLiveInstances().keySet(), 
stateModelDef, preferenceList,
               currentStateOutput, disabledInstancesForPartition, idealState, 
clusterConfig,
               partition, cache.getAbnormalStateResolver(stateModelDefName), 
cache);
 
@@ -404,7 +396,7 @@ public class DelayedAutoRebalancer extends 
AbstractRebalancer<ResourceController
 
     // If the load-balance finishes (all replica are migrated to new 
instances),
     // we should drop all partitions from previous assigned instances.
-    if 
(!currentMapWithPreferenceList.values().contains(HelixDefinedState.ERROR.name())
+    if 
(!currentMapWithPreferenceList.containsValue(HelixDefinedState.ERROR.name())
         && bestPossibleStateMap.size() > numReplicas && 
readyToDrop(currentStateMap,
         bestPossibleStateMap, preferenceList, combinedPreferenceList)) {
       for (int i = 0; i < combinedPreferenceList.size() - numReplicas; i++) {
diff --git 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/util/DelayedRebalanceUtil.java
 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/util/DelayedRebalanceUtil.java
index f4fb26541..2796064db 100644
--- 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/util/DelayedRebalanceUtil.java
+++ 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/util/DelayedRebalanceUtil.java
@@ -85,28 +85,28 @@ public class DelayedRebalanceUtil {
   }
 
   /**
-   * @return all active nodes (live nodes not marked as evacuate plus 
offline-yet-active nodes)
+   * @return all active nodes (live nodes plus offline-yet-active nodes)
    * while considering cluster delay rebalance configurations.
    */
   public static Set<String> getActiveNodes(Set<String> allNodes, Set<String> 
liveEnabledNodes,
       Map<String, Long> instanceOfflineTimeMap, Set<String> liveNodes,
       Map<String, InstanceConfig> instanceConfigMap, ClusterConfig 
clusterConfig) {
     if (!isDelayRebalanceEnabled(clusterConfig)) {
-      return filterOutEvacuatingInstances(instanceConfigMap, liveEnabledNodes);
+      return liveEnabledNodes;
     }
     return getActiveNodes(allNodes, liveEnabledNodes, instanceOfflineTimeMap, 
liveNodes,
         instanceConfigMap, clusterConfig.getRebalanceDelayTime(), 
clusterConfig);
   }
 
   /**
-   * @return all active nodes (live nodes not marked as evacuate plus 
offline-yet-active nodes)
+   * @return all active nodes (live nodes plus offline-yet-active nodes)
    * while considering cluster delay rebalance configurations.
    */
   public static Set<String> getActiveNodes(Set<String> allNodes, IdealState 
idealState,
       Set<String> liveEnabledNodes, Map<String, Long> instanceOfflineTimeMap, 
Set<String> liveNodes,
       Map<String, InstanceConfig> instanceConfigMap, long delay, ClusterConfig 
clusterConfig) {
     if (!isDelayRebalanceEnabled(idealState, clusterConfig)) {
-      return filterOutEvacuatingInstances(instanceConfigMap, liveEnabledNodes);
+      return liveEnabledNodes;
     }
     return getActiveNodes(allNodes, liveEnabledNodes, instanceOfflineTimeMap, 
liveNodes,
         instanceConfigMap, delay, clusterConfig);
@@ -128,17 +128,7 @@ public class DelayedRebalanceUtil {
         activeNodes.add(ins);
       }
     }
-    // TODO: change this after merging operation and helix-enable field.
-    return filterOutEvacuatingInstances(instanceConfigMap, activeNodes);
-  }
-
-  public static Set<String> filterOutEvacuatingInstances(Map<String, 
InstanceConfig> instanceConfigMap,
-      Set<String> nodes) {
-    return nodes.stream()
-        .filter(instance -> (instanceConfigMap.get(instance) != null && 
!instanceConfigMap.get(instance)
-            .getInstanceOperation()
-            .equals(InstanceConstants.InstanceOperation.EVACUATE.name())))
-        .collect(Collectors.toSet());
+    return activeNodes;
   }
 
   /**
diff --git 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/WagedRebalancer.java
 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/WagedRebalancer.java
index 4c4f9cf94..b0527e5e8 100644
--- 
a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/WagedRebalancer.java
+++ 
b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/WagedRebalancer.java
@@ -401,10 +401,7 @@ public class WagedRebalancer implements 
StatefulRebalancer<ResourceControllerDat
       RebalanceAlgorithm algorithm) throws HelixRebalanceException {
 
     // the "real" live nodes at the time
-    // TODO: Move evacuation into BaseControllerDataProvider assignableNode 
logic.
-    final Set<String> enabledLiveInstances = 
DelayedRebalanceUtil.filterOutEvacuatingInstances(
-        clusterData.getAssignableInstanceConfigMap(),
-        clusterData.getAssignableEnabledLiveInstances());
+    final Set<String> enabledLiveInstances = 
clusterData.getAssignableEnabledLiveInstances();
 
     if (activeNodes.equals(enabledLiveInstances) || 
!requireRebalanceOverwrite(clusterData, currentResourceAssignment)) {
       // no need for additional process, return the current resource assignment
@@ -626,10 +623,7 @@ public class WagedRebalancer implements 
StatefulRebalancer<ResourceControllerDat
       String resourceName = resourceAssignment.getResourceName();
       IdealState currentIdealState = clusterData.getIdealState(resourceName);
 
-      // TODO: Move evacuation into BaseControllerDataProvider assignableNode 
logic.
-      Set<String> enabledLiveInstances = 
DelayedRebalanceUtil.filterOutEvacuatingInstances(
-          clusterData.getAssignableInstanceConfigMap(),
-          clusterData.getAssignableEnabledLiveInstances());
+      Set<String> enabledLiveInstances = 
clusterData.getAssignableEnabledLiveInstances();
 
       int numReplica = 
currentIdealState.getReplicaCount(enabledLiveInstances.size());
       int minActiveReplica = 
DelayedRebalanceUtil.getMinActiveReplica(ResourceConfig
diff --git 
a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixAdmin.java 
b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixAdmin.java
index aa94a0244..c5303cdd2 100644
--- a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixAdmin.java
+++ b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixAdmin.java
@@ -121,6 +121,8 @@ public class ZKHelixAdmin implements HelixAdmin {
   private static final int DEFAULT_SUPERCLUSTER_REPLICA = 3;
   private static final ImmutableSet<String> 
ALLOWED_INSTANCE_OPERATIONS_FOR_ADD_INSTANCE =
       ImmutableSet.of("", InstanceConstants.InstanceOperation.SWAP_IN.name());
+  private static final ImmutableSet<String> 
INSTANCE_OPERATION_TO_EXCLUDE_FROM_ASSIGNMENT =
+      ImmutableSet.of(InstanceConstants.InstanceOperation.EVACUATE.name());
 
   private final RealmAwareZkClient _zkClient;
   private final ConfigAccessor _configAccessor;
@@ -840,7 +842,7 @@ public class ZKHelixAdmin implements HelixAdmin {
   public boolean isReadyForPreparingJoiningCluster(String clusterName, String 
instanceName) {
     if (!instanceHasFullAutoCurrentStateOrMessage(clusterName, instanceName)) {
       InstanceConfig config = getInstanceConfig(clusterName, instanceName);
-      return config != null && 
DelayedAutoRebalancer.INSTANCE_OPERATION_TO_EXCLUDE_FROM_ASSIGNMENT.contains(
+      return config != null && 
INSTANCE_OPERATION_TO_EXCLUDE_FROM_ASSIGNMENT.contains(
           config.getInstanceOperation());
     }
     return false;
diff --git 
a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/TestInstanceOperation.java
 
b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/TestInstanceOperation.java
index 713944e98..0019ea83c 100644
--- 
a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/TestInstanceOperation.java
+++ 
b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/TestInstanceOperation.java
@@ -262,7 +262,17 @@ public class TestInstanceOperation extends ZkTestBase {
     // Drop semi-auto DBs
     _gSetupTool.dropResourceFromCluster(CLUSTER_NAME, semiAutoDB);
     Assert.assertTrue(_clusterVerifier.verifyByPolling());
-  }
+
+    // Disable, stop, and drop the instance from the cluster.
+    _gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME, 
instanceToEvacuate, false);
+    _participants.get(0).syncStop();
+    removeOfflineOrDisabledOrSwapInInstances();
+
+    // Compare the current ev with the previous one, it should be exactly the 
same since the baseline should not change
+    // after the instance is dropped.
+    Assert.assertTrue(_clusterVerifier.verifyByPolling());
+    Assert.assertEquals(getEVs(), assignment);
+}
 
   @Test(dependsOnMethods = "testEvacuate")
   public void testRevertEvacuation() throws Exception {
@@ -1248,7 +1258,7 @@ public class TestInstanceOperation extends ZkTestBase {
       
Assert.assertTrue(getParticipantsInEv(assignment.get(resource)).contains(instanceToEvacuate));
     }
 
-    Assert.assertTrue(_clusterVerifier.verifyByPolling());
+    Assert.assertTrue(_bestPossibleClusterVerifier.verifyByPolling());
 
     // exit MM
     _gSetupTool.getClusterManagementTool()
diff --git 
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestPerInstanceAccessor.java
 
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestPerInstanceAccessor.java
index 48343f8d0..355d5d101 100644
--- 
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestPerInstanceAccessor.java
+++ 
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestPerInstanceAccessor.java
@@ -527,18 +527,12 @@ public class TestPerInstanceAccessor extends 
AbstractTestClass {
     Assert.assertFalse((boolean) responseMap.get("successful"));
 
     // test isEvacuateFinished on instance with EVACUATE but has currentState
-    // Enable persist best possible assignment for cluster verifier
-    ConfigAccessor configAccessor = new ConfigAccessor(_gZkClient);
-    ClusterConfig clusterConfig = 
configAccessor.getClusterConfig(CLUSTER_NAME);
-    clusterConfig.setPersistBestPossibleAssignment(true);
-    configAccessor.setClusterConfig(CLUSTER_NAME, clusterConfig);
-    Set<String> resources = _resourcesMap.get(CLUSTER_NAME);
-    ZkHelixClusterVerifier clusterVerifier = new 
StrictMatchExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
-        .setDeactivatedNodeAwareness(true)
-        .setResources(resources)
-        .setWaitTillVerify(TestHelper.DEFAULT_REBALANCE_PROCESSING_WAIT_TIME)
-        .build();
+    // Put the cluster in MM so no assignment is calculated
+    _gSetupTool.getClusterManagementTool()
+        .enableMaintenanceMode(CLUSTER_NAME, true, "Change resource to 
full-auto");
+
     // Make the DBs FULL_AUTO and wait because EVACUATE is only supported for 
FULL_AUTO resources
+    Set<String> resources = _resourcesMap.get(CLUSTER_NAME);
     for (String resource : resources) {
       IdealState idealState =
           
_gSetupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, 
resource);
@@ -548,8 +542,6 @@ public class TestPerInstanceAccessor extends 
AbstractTestClass {
       
_gSetupTool.getClusterManagementTool().setResourceIdealState(CLUSTER_NAME, 
resource, idealState);
     }
 
-    Assert.assertTrue(clusterVerifier.verifyByPolling());
-
     new 
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=setInstanceOperation&instanceOperation=EVACUATE")
         .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
     instanceConfig = _configAccessor.getInstanceConfig(CLUSTER_NAME, 
INSTANCE_NAME);
@@ -558,9 +550,10 @@ public class TestPerInstanceAccessor extends 
AbstractTestClass {
 
     Response response = new 
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=isEvacuateFinished")
         .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
-    Map<String, Boolean> evacuateFinishedresult = 
OBJECT_MAPPER.readValue(response.readEntity(String.class), Map.class);
+    Map<String, Boolean> evacuateFinishedResult = 
OBJECT_MAPPER.readValue(response.readEntity(String.class), Map.class);
     Assert.assertEquals(response.getStatus(), 
Response.Status.OK.getStatusCode());
-    Assert.assertFalse(evacuateFinishedresult.get("successful"));
+    // Returns false because the node still contains full-auto resources
+    Assert.assertFalse(evacuateFinishedResult.get("successful"));
 
     // Make all resources SEMI_AUTO again
     for (String resource : resources) {
@@ -572,8 +565,16 @@ public class TestPerInstanceAccessor extends 
AbstractTestClass {
       
_gSetupTool.getClusterManagementTool().setResourceIdealState(CLUSTER_NAME, 
resource, idealState);
     }
 
-    // Wait for the cluster to be stable again
-    Assert.assertTrue(clusterVerifier.verifyByPolling());
+    // Exit MM
+    _gSetupTool.getClusterManagementTool()
+        .enableMaintenanceMode(CLUSTER_NAME, false, "Change resource to 
full-auto");
+
+    // Because the resources are now all semi-auto, is EvacuateFinished should 
return true
+    response = new 
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=isEvacuateFinished")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+    evacuateFinishedResult = 
OBJECT_MAPPER.readValue(response.readEntity(String.class), Map.class);
+    Assert.assertEquals(response.getStatus(), 
Response.Status.OK.getStatusCode());
+    Assert.assertTrue(evacuateFinishedResult.get("successful"));
 
     // test isEvacuateFinished on instance with EVACUATE and no currentState
     // Create new instance so no currentState or messages assigned to it
@@ -592,9 +593,9 @@ public class TestPerInstanceAccessor extends 
AbstractTestClass {
 
     response = new 
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=isEvacuateFinished")
         .format(CLUSTER_NAME, test_instance_name).post(this, entity);
-    evacuateFinishedresult = 
OBJECT_MAPPER.readValue(response.readEntity(String.class), Map.class);
+    evacuateFinishedResult = 
OBJECT_MAPPER.readValue(response.readEntity(String.class), Map.class);
     Assert.assertEquals(response.getStatus(), 
Response.Status.OK.getStatusCode());
-    Assert.assertTrue(evacuateFinishedresult.get("successful"));
+    Assert.assertTrue(evacuateFinishedResult.get("successful"));
     System.out.println("End test :" + TestHelper.getTestMethodName());
   }
 

Reply via email to