package org.apache.helix.integration; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.helix.BaseDataAccessor; import org.apache.helix.HelixAdmin; import org.apache.helix.HelixDataAccessor; import org.apache.helix.PropertyKey; import org.apache.helix.TestHelper; import org.apache.helix.zookeeper.datamodel.ZNRecord; import org.apache.helix.ZkUnitTestBase; import org.apache.helix.integration.manager.ClusterControllerManager; import org.apache.helix.integration.manager.MockParticipantManager; import org.apache.helix.manager.zk.ZKHelixAdmin; import org.apache.helix.manager.zk.ZKHelixDataAccessor; import org.apache.helix.manager.zk.ZkBaseDataAccessor; import org.apache.helix.model.ExternalView; import org.apache.helix.model.IdealState; import org.apache.helix.model.IdealState.RebalanceMode; import org.apache.helix.tools.ClusterStateVerifier; import org.apache.helix.tools.ClusterVerifiers.BestPossibleExternalViewVerifier; import org.testng.Assert; import org.testng.annotations.Test; public class TestDisableResource extends ZkUnitTestBase { private static final int N = 2; private static final int PARTITION_NUM = 1; @Test public void testDisableResourceInSemiAutoMode() throws Exception { String className = TestHelper.getTestClassName(); String methodName = TestHelper.getTestMethodName(); String clusterName = className + "_" + methodName; System.out.println("START " + clusterName + " at " + new Date(System.currentTimeMillis())); TestHelper.setupCluster(clusterName, ZK_ADDR, 12918, // participant port "localhost", // participant name prefix "TestDB", // resource name prefix 1, // resources PARTITION_NUM, // partitions per resource N, // number of nodes 2, // replicas "MasterSlave", true); // do rebalance ClusterControllerManager controller = new ClusterControllerManager(ZK_ADDR, clusterName, "controller"); controller.syncStart(); // start participants MockParticipantManager[] participants = new MockParticipantManager[N]; for (int i = 0; i < N; i++) { String instanceName = "localhost_" + (12918 + i); participants[i] = new MockParticipantManager(ZK_ADDR, clusterName, instanceName); participants[i].syncStart(); } // Check for connection status HelixDataAccessor accessor = new ZKHelixDataAccessor(clusterName, _baseAccessor); boolean result = TestHelper.verify(() -> { List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (!participants[i].isConnected() || !liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); result = ClusterStateVerifier.verifyByZkCallback( new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, clusterName)); Assert.assertTrue(result); // Disable TestDB0 enableResource(clusterName, false); result = TestHelper.verify( () -> !_gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); result = ClusterStateVerifier.verifyByPolling( new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, clusterName)); Assert.assertTrue(result); checkExternalView(clusterName); // Re-enable TestDB0 enableResource(clusterName, true); result = TestHelper.verify( () -> _gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); result = ClusterStateVerifier.verifyByPolling( new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, clusterName)); Assert.assertTrue(result); // Clean up controller.syncStop(); for (int i = 0; i < N; i++) { participants[i].syncStop(); } result = TestHelper.verify(() -> { if (accessor.getPropertyStat(accessor.keyBuilder().controllerLeader()) != null) { return false; } List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (participants[i].isConnected() || liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); deleteCluster(clusterName); System.out.println("END " + clusterName + " at " + new Date(System.currentTimeMillis())); } @Test public void testDisableResourceInFullAutoMode() throws Exception { String className = TestHelper.getTestClassName(); String methodName = TestHelper.getTestMethodName(); String clusterName = className + "_" + methodName; System.out.println("START " + clusterName + " at " + new Date(System.currentTimeMillis())); TestHelper.setupCluster(clusterName, ZK_ADDR, 12918, // participant port "localhost", // participant name prefix "TestDB", // resource name prefix 1, // resources PARTITION_NUM, // partitions per resource N, // number of nodes 2, // replicas "MasterSlave", RebalanceMode.FULL_AUTO, true); // do rebalance ClusterControllerManager controller = new ClusterControllerManager(ZK_ADDR, clusterName, "controller"); controller.syncStart(); // start participants MockParticipantManager[] participants = new MockParticipantManager[N]; for (int i = 0; i < N; i++) { String instanceName = "localhost_" + (12918 + i); participants[i] = new MockParticipantManager(ZK_ADDR, clusterName, instanceName); participants[i].syncStart(); } // Check for connection status HelixDataAccessor accessor = new ZKHelixDataAccessor(clusterName, _baseAccessor); boolean result = TestHelper.verify(() -> { List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (!participants[i].isConnected() || !liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); // disable TestDB0 enableResource(clusterName, false); result = TestHelper.verify( () -> !_gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); result = ClusterStateVerifier.verifyByPolling( new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, clusterName)); Assert.assertTrue(result); checkExternalView(clusterName); // Re-enable TestDB0 enableResource(clusterName, true); result = TestHelper.verify( () -> _gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); result = ClusterStateVerifier.verifyByPolling( new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, clusterName)); Assert.assertTrue(result); // Clean up controller.syncStop(); for (int i = 0; i < N; i++) { participants[i].syncStop(); } result = TestHelper.verify(() -> { if (accessor.getPropertyStat(accessor.keyBuilder().controllerLeader()) != null) { return false; } List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (participants[i].isConnected() || liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); TestHelper.dropCluster(clusterName, _gZkClient); System.out.println("END " + clusterName + " at " + new Date(System.currentTimeMillis())); } @Test public void testDisableResourceInCustomMode() throws Exception { String className = TestHelper.getTestClassName(); String methodName = TestHelper.getTestMethodName(); String clusterName = className + "_" + methodName; System.out.println("START " + clusterName + " at " + new Date(System.currentTimeMillis())); TestHelper.setupCluster(clusterName, ZK_ADDR, 12918, // participant port "localhost", // participant name prefix "TestDB", // resource name prefix 1, // resources PARTITION_NUM, // partitions per resource N, // number of nodes 2, // replicas "MasterSlave", RebalanceMode.CUSTOMIZED, true); // do rebalance // set up custom ideal-state HelixDataAccessor accessor = new ZKHelixDataAccessor(clusterName, _baseAccessor); PropertyKey.Builder keyBuilder = accessor.keyBuilder(); IdealState idealState = accessor.getProperty(keyBuilder.idealStates("TestDB0")); idealState.setPartitionState("TestDB0_0", "localhost_12918", "SLAVE"); idealState.setPartitionState("TestDB0_0", "localhost_12919", "SLAVE"); accessor.setProperty(keyBuilder.idealStates("TestDB0"), idealState); ClusterControllerManager controller = new ClusterControllerManager(ZK_ADDR, clusterName, "controller"); controller.syncStart(); // start participants MockParticipantManager[] participants = new MockParticipantManager[N]; for (int i = 0; i < N; i++) { String instanceName = "localhost_" + (12918 + i); participants[i] = new MockParticipantManager(ZK_ADDR, clusterName, instanceName); participants[i].syncStart(); } // Check for connection status boolean result = TestHelper.verify(() -> { List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (!participants[i].isConnected() || !liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); BestPossibleExternalViewVerifier verifier = new BestPossibleExternalViewVerifier.Builder(clusterName).setZkAddr(ZK_ADDR) .setZkClient(_gZkClient).build(); // Disable TestDB0 enableResource(clusterName, false); // Check that the resource has been disabled result = TestHelper.verify( () -> !_gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); Assert.assertTrue(verifier.verifyByPolling()); checkExternalView(clusterName); // Re-enable TestDB0 enableResource(clusterName, true); // Check that the resource has been enabled result = TestHelper.verify( () -> _gSetupTool.getClusterManagementTool() .getResourceIdealState(clusterName, "TestDB0").isEnabled(), TestHelper.WAIT_DURATION); Assert.assertTrue(result); Assert.assertTrue(verifier.verifyByPolling()); // Clean up controller.syncStop(); for (int i = 0; i < N; i++) { participants[i].syncStop(); } result = TestHelper.verify(() -> { if (accessor.getPropertyStat(accessor.keyBuilder().controllerLeader()) != null) { return false; } List<String> liveInstances = accessor.getChildNames(accessor.keyBuilder().liveInstances()); for (int i = 0; i < N; i++) { if (participants[i].isConnected() || liveInstances.contains(participants[i].getInstanceName())) { return false; } } return true; }, TestHelper.WAIT_DURATION); Assert.assertTrue(result); TestHelper.dropCluster(clusterName, _gZkClient); System.out.println("END " + clusterName + " at " + new Date(System.currentTimeMillis())); } private void enableResource(String clusterName, boolean enabled) { HelixAdmin admin = new ZKHelixAdmin(_gZkClient); admin.enableResource(clusterName, "TestDB0", enabled); } /** * Check all partitions are in OFFLINE state * @param clusterName * @throws Exception */ private void checkExternalView(String clusterName) throws Exception { BaseDataAccessor<ZNRecord> baseAccessor = new ZkBaseDataAccessor<ZNRecord>(_gZkClient); final HelixDataAccessor accessor = new ZKHelixDataAccessor(clusterName, baseAccessor); // verify that states of TestDB0 are all OFFLINE boolean result = TestHelper.verify(() -> { PropertyKey.Builder keyBuilder = accessor.keyBuilder(); ExternalView extView = accessor.getProperty(keyBuilder.externalView("TestDB0")); if (extView == null) { return false; } Set<String> partitionSet = extView.getPartitionSet(); if (partitionSet == null || partitionSet.size() != PARTITION_NUM) { return false; } for (String partition : partitionSet) { Map<String, String> instanceStates = extView.getStateMap(partition); for (String state : instanceStates.values()) { if (!"OFFLINE".equals(state)) { return false; } } } return true; }, 10 * 1000); Assert.assertTrue(result); } }