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()); }