This is an automated email from the ASF dual-hosted git repository.
jxue 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 858038a0d add type and reason to cluster config (#2006)
858038a0d is described below
commit 858038a0d4393109f3dfbb63c2f442b0f95fa50e
Author: xyuanlu <[email protected]>
AuthorDate: Tue Apr 5 18:34:49 2022 -0700
add type and reason to cluster config (#2006)
Add type and reason for batch disable/enable instance
---
.../src/main/java/org/apache/helix/HelixAdmin.java | 18 ++++++-
.../rebalancer/util/DelayedRebalanceUtil.java | 5 +-
.../org/apache/helix/manager/zk/ZKHelixAdmin.java | 60 ++++++++++++++--------
.../java/org/apache/helix/model/ClusterConfig.java | 34 +++++++++++-
.../apache/helix/util/InstanceValidationUtil.java | 42 ++++++++++++++-
.../integration/TestBatchEnableInstances.java | 48 ++++++++++++++---
.../java/org/apache/helix/mock/MockHelixAdmin.java | 43 ++++++++++++++--
.../server/resources/helix/InstancesAccessor.java | 13 ++++-
.../helix/rest/server/TestInstancesAccessor.java | 42 +++++++++------
9 files changed, 251 insertions(+), 54 deletions(-)
diff --git a/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
b/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
index 32158d541..837cd2cb0 100644
--- a/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
+++ b/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
@@ -285,8 +285,10 @@ public interface HelixAdmin {
* @param clusterName
* @param instanceName
* @param enabled
+ * @param disabledType disabledType for disable operation. It is ignored
when enabled is true.
+ * Existing disabledType will be over write if instance
is in disabled state.
* @param reason set additional string description on why the instance is
disabled when
- * <code>enabled</code> is false.
+ * <code>enabled</code> is false. Existing disabled reason will be
over write if instance is in disabled state.
*/
void enableInstance(String clusterName, String instanceName, boolean enabled,
InstanceConstants.InstanceDisabledType disabledType, String reason);
@@ -300,6 +302,20 @@ public interface HelixAdmin {
*/
void enableInstance(String clusterName, List<String> instances, boolean
enabled);
+ /**
+ * Batch enable/disable instances in a cluster
+ * By default, all the instances are enabled
+ * @param clusterName
+ * @param instances
+ * @param enabled
+ * @param disabledType disabledType for disable operation. It is ignored
when enabled is true.
+ * Existing disabledType will be over write if instance
is in disabled state.
+ * @param reason human readable string explaining disabled reason. Ignored
when enabled is true.
+ * Existing disabled reason will be over write if instance is
in disabled state.
+ */
+ void enableInstance(String clusterName, List<String> instances, boolean
enabled,
+ InstanceConstants.InstanceDisabledType disabledType, String reason);
+
/**
* Disable or enable a resource
* @param clusterName
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 8de1f4385..43fcf4c5a 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
@@ -31,6 +31,7 @@ import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.IdealState;
import org.apache.helix.model.InstanceConfig;
import org.apache.helix.model.ResourceConfig;
+import org.apache.helix.util.ConfigStringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -142,7 +143,9 @@ public class DelayedRebalanceUtil {
if (clusterConfig.getDisabledInstances() != null &&
clusterConfig.getDisabledInstances()
.containsKey(instance)) {
// Update batch disable time
- long batchDisableTime =
Long.parseLong(clusterConfig.getDisabledInstances().get(instance));
+ long batchDisableTime = Long.parseLong(ConfigStringUtil
+
.parseConcatenatedConfig(clusterConfig.getDisabledInstances().get(instance))
+
.get(ClusterConfig.ClusterConfigProperty.HELIX_ENABLED_DISABLE_TIMESTAMP.toString()));
if (disabledTime == -1 || disabledTime > batchDisableTime) {
disabledTime = batchDisableTime;
}
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 a3bcfc45c..0d05d05b2 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
@@ -86,6 +86,7 @@ import org.apache.helix.model.ResourceConfig;
import org.apache.helix.model.StateModelDefinition;
import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.tools.DefaultIdealStateCalculator;
+import org.apache.helix.util.ConfigStringUtil;
import org.apache.helix.util.HelixUtil;
import org.apache.helix.util.RebalanceUtil;
import org.apache.helix.zookeeper.api.client.HelixZkClient;
@@ -351,28 +352,33 @@ public class ZKHelixAdmin implements HelixAdmin {
logger.info("{} instance {} in cluster {}.", enabled ? "Enable" :
"Disable", instanceName,
clusterName);
BaseDataAccessor<ZNRecord> baseAccessor = new
ZkBaseDataAccessor<>(_zkClient);
+ // Eventually we will have all instances' enable/disable information in
clusterConfig. Now we
+ // update both instanceConfig and clusterConfig in transition period.
enableSingleInstance(clusterName, instanceName, enabled, baseAccessor,
disabledType, reason);
- // TODO: Reenable this after storage node bug fixed.
- // enableBatchInstances(clusterName,
Collections.singletonList(instanceName), enabled, baseAccessor);
+ enableBatchInstances(clusterName, Collections.singletonList(instanceName),
enabled,
+ baseAccessor, disabledType, reason);
}
@Override
- public void enableInstance(String clusterName, List<String> instances,
boolean enabled) {
- // TODO: Considering adding another batched API with disabled type and
reason.
- // TODO: Reenable this after storage node bug fixed.
- if (true) {
- throw new HelixException("Current batch enable/disable instances are
temporarily disabled!");
- }
+ public void enableInstance(String clusterName, List<String> instances,
boolean enabled,
+ InstanceConstants.InstanceDisabledType disabledType, String reason) {
logger.info("Batch {} instances {} in cluster {}.", enabled ? "enable" :
"disable",
HelixUtil.serializeByComma(instances), clusterName);
BaseDataAccessor<ZNRecord> baseAccessor = new
ZkBaseDataAccessor<>(_zkClient);
+ // Eventually we will have all instances' enable/disable information in
clusterConfig. Now we
+ // update both instanceConfig and clusterConfig in transition period.
if (enabled) {
for (String instance : instances) {
- enableSingleInstance(clusterName, instance, enabled, baseAccessor,
null, null);
+ enableSingleInstance(clusterName, instance, enabled, baseAccessor,
disabledType, reason);
}
}
- enableBatchInstances(clusterName, instances, enabled, baseAccessor);
+ enableBatchInstances(clusterName, instances, enabled, baseAccessor,
disabledType, reason);
+ }
+
+ @Override
+ public void enableInstance(String clusterName, List<String> instances,
boolean enabled) {
+ enableInstance(clusterName, instances, enabled, null, null);
}
@Override
@@ -1889,6 +1895,8 @@ public class ZKHelixAdmin implements HelixAdmin {
InstanceConfig config = new InstanceConfig(currentData);
config.setInstanceEnabled(enabled);
if (!enabled) {
+ // new disabled type and reason will over write existing ones.
+ config.resetInstanceDisabledTypeAndReason();
if (reason != null) {
config.setInstanceDisabledReason(reason);
}
@@ -1901,13 +1909,10 @@ public class ZKHelixAdmin implements HelixAdmin {
}, AccessOption.PERSISTENT);
}
+ // TODO: Add history ZNode for all batched enabling/disabling histories with
metadata.
private void enableBatchInstances(final String clusterName, final
List<String> instances,
- final boolean enabled, BaseDataAccessor<ZNRecord> baseAccessor) {
- // TODO : Due to Espresso storage node depends on map field. Current
disable the feature now
- // include tests.
- if (true) {
- throw new HelixException("Current batch enable/disable instances are
temporarily disabled!");
- }
+ final boolean enabled, BaseDataAccessor<ZNRecord> baseAccessor,
+ InstanceConstants.InstanceDisabledType disabledType, String reason) {
String path = PropertyPathBuilder.clusterConfig(clusterName);
@@ -1927,14 +1932,14 @@ public class ZKHelixAdmin implements HelixAdmin {
if (clusterConfig.getDisabledInstances() != null) {
disabledInstances.putAll(clusterConfig.getDisabledInstances());
}
-
if (enabled) {
disabledInstances.keySet().removeAll(instances);
} else {
for (String disabledInstance : instances) {
- if (!disabledInstances.containsKey(disabledInstance)) {
- disabledInstances.put(disabledInstance,
String.valueOf(System.currentTimeMillis()));
- }
+ // We allow user to override disabledType and reason for an
already disabled instance.
+ // TODO: update the history ZNode
+ disabledInstances
+ .put(disabledInstance,
assembleInstanceBatchedDisabledInfo(disabledType, reason));
}
}
clusterConfig.setDisabledInstances(disabledInstances);
@@ -1944,6 +1949,21 @@ public class ZKHelixAdmin implements HelixAdmin {
}, AccessOption.PERSISTENT);
}
+ public static String assembleInstanceBatchedDisabledInfo(
+ InstanceConstants.InstanceDisabledType disabledType, String reason) {
+ Map<String, String> disableInfo = new TreeMap<>();
+
disableInfo.put(ClusterConfig.ClusterConfigProperty.HELIX_ENABLED_DISABLE_TIMESTAMP.toString(),
+ String.valueOf(System.currentTimeMillis()));
+ if (disabledType != null) {
+
disableInfo.put(ClusterConfig.ClusterConfigProperty.HELIX_DISABLED_TYPE.toString(),
+ disabledType.toString());
+ }
+ if (reason != null) {
+
disableInfo.put(ClusterConfig.ClusterConfigProperty.HELIX_DISABLED_REASON.toString(),
reason);
+ }
+ return ConfigStringUtil.concatenateMapping(disableInfo);
+ }
+
@Override
public Map<String, String> getBatchDisabledInstances(String clusterName) {
ConfigAccessor accessor = new ConfigAccessor(_zkClient);
diff --git a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java
b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java
index 68c1d4ddd..72bc5dcb5 100644
--- a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java
@@ -33,6 +33,8 @@ import org.apache.helix.HelixProperty;
import org.apache.helix.api.config.HelixConfigProperty;
import org.apache.helix.api.config.StateTransitionThrottleConfig;
import org.apache.helix.api.config.StateTransitionTimeoutConfig;
+import org.apache.helix.constants.InstanceConstants;
+import org.apache.helix.util.ConfigStringUtil;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
/**
@@ -134,7 +136,13 @@ public class ClusterConfig extends HelixProperty {
// offline for more than this specified time period, and users call purge
participant API,
// then the node will be removed.
// The unit is milliseconds.
- OFFLINE_DURATION_FOR_PURGE_MS
+ OFFLINE_DURATION_FOR_PURGE_MS,
+
+ // The following 3 keywords are for metadata in batch disabled instance
+ HELIX_ENABLED_DISABLE_TIMESTAMP,
+ HELIX_DISABLED_REASON,
+ // disabled type should be a enum of
org.apache.helix.constants.InstanceConstants.InstanceDisabledType
+ HELIX_DISABLED_TYPE
}
public enum GlobalRebalancePreferenceKey {
@@ -1045,4 +1053,28 @@ public class ClusterConfig extends HelixProperty {
public String getClusterName() {
return _record.getId();
}
+
+ public String getPlainInstanceHelixDisabledType(String instanceName) {
+ return
ConfigStringUtil.parseConcatenatedConfig(getDisabledInstances().get(instanceName))
+ .get(ClusterConfigProperty.HELIX_DISABLED_TYPE.toString());
+ }
+
+ public String getInstanceHelixDisabledType(String instanceName) {
+ if (!getDisabledInstances().containsKey(instanceName)) {
+ return InstanceConstants.INSTANCE_NOT_DISABLED;
+ }
+ return
ConfigStringUtil.parseConcatenatedConfig(getDisabledInstances().get(instanceName))
+ .getOrDefault(ClusterConfigProperty.HELIX_DISABLED_TYPE.toString(),
+
InstanceConstants.InstanceDisabledType.DEFAULT_INSTANCE_DISABLE_TYPE.toString());
+ }
+
+ public String getInstanceHelixDisabledReason(String instanceName) {
+ return
ConfigStringUtil.parseConcatenatedConfig(getDisabledInstances().get(instanceName))
+ .get(ClusterConfigProperty.HELIX_DISABLED_REASON.toString());
+ }
+
+ public String getInstanceHelixDisabledTimeStamp(String instanceName) {
+ return
ConfigStringUtil.parseConcatenatedConfig(getDisabledInstances().get(instanceName))
+ .get(ClusterConfigProperty.HELIX_ENABLED_DISABLE_TIMESTAMP.toString());
+ }
}
diff --git
a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
index 7c6383195..48ff86b95 100644
--- a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
@@ -31,6 +31,7 @@ import org.apache.helix.HelixDataAccessor;
import org.apache.helix.HelixDefinedState;
import org.apache.helix.HelixException;
import org.apache.helix.PropertyKey;
+import org.apache.helix.constants.InstanceConstants;
import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.CurrentState;
import org.apache.helix.model.ExternalView;
@@ -78,10 +79,46 @@ public class InstanceValidationUtil {
throw new HelixException("InstanceConfig or ClusterConfig is NULL");
}
+ return isInstanceEnabled(instanceConfig, clusterConfig);
+
+ }
+
+ public static String getInstanceHelixDisabledType(HelixDataAccessor
dataAccessor,
+ String instanceName) {
+ PropertyKey.Builder propertyKeyBuilder = dataAccessor.keyBuilder();
+ ClusterConfig clusterConfig =
dataAccessor.getProperty(propertyKeyBuilder.clusterConfig());
+ if (clusterConfig == null) {
+ throw new HelixException("ClusterConfig is NULL");
+ }
+
+ String instanceDisabledTypeBatchedMode =
+ clusterConfig.getPlainInstanceHelixDisabledType(instanceName);
+ if (instanceDisabledTypeBatchedMode != null) {
+ return
InstanceConstants.InstanceDisabledType.valueOf(instanceDisabledTypeBatchedMode)
+ .toString();
+ }
+ // TODO deprecate reading instance level config once migrated the enable
status to cluster config only
+ InstanceConfig instanceConfig =
+
dataAccessor.getProperty(propertyKeyBuilder.instanceConfig(instanceName));
+ if (instanceConfig == null) {
+ throw new HelixException("InstanceConfig is NULL");
+ }
+
+ if (isInstanceEnabled(instanceConfig, clusterConfig)) {
+ return InstanceConstants.INSTANCE_NOT_DISABLED;
+ }
+ // It is possible that an instance is set disabled in cluster config but
not in instance config.
+ // This instance is considered disabled. We should return a default
disabled type.
+ return instanceConfig.getInstanceEnabled()
+ ?
InstanceConstants.InstanceDisabledType.DEFAULT_INSTANCE_DISABLE_TYPE.toString()
+ : instanceConfig.getInstanceDisabledType();
+ }
+
+ private static boolean isInstanceEnabled(InstanceConfig instanceConfig,
ClusterConfig clusterConfig) {
boolean enabledInInstanceConfig = instanceConfig.getInstanceEnabled();
Map<String, String> disabledInstances =
clusterConfig.getDisabledInstances();
boolean enabledInClusterConfig =
- disabledInstances == null ||
!disabledInstances.keySet().contains(instanceName);
+ disabledInstances == null ||
!disabledInstances.keySet().contains(instanceConfig.getInstanceName());
return enabledInClusterConfig && enabledInInstanceConfig;
}
@@ -92,7 +129,8 @@ public class InstanceValidationUtil {
* @return
*/
public static boolean isAlive(HelixDataAccessor dataAccessor, String
instanceName) {
- LiveInstance liveInstance =
dataAccessor.getProperty(dataAccessor.keyBuilder().liveInstance(instanceName));
+ LiveInstance liveInstance =
+
dataAccessor.getProperty(dataAccessor.keyBuilder().liveInstance(instanceName));
return liveInstance != null;
}
diff --git
a/helix-core/src/test/java/org/apache/helix/integration/TestBatchEnableInstances.java
b/helix-core/src/test/java/org/apache/helix/integration/TestBatchEnableInstances.java
index b7b060064..6dfd0037f 100644
---
a/helix-core/src/test/java/org/apache/helix/integration/TestBatchEnableInstances.java
+++
b/helix-core/src/test/java/org/apache/helix/integration/TestBatchEnableInstances.java
@@ -23,9 +23,15 @@ import java.util.Arrays;
import java.util.Map;
import org.apache.helix.ConfigAccessor;
+import org.apache.helix.HelixDataAccessor;
+import org.apache.helix.constants.InstanceConstants;
import org.apache.helix.integration.task.TaskTestBase;
import org.apache.helix.integration.task.WorkflowGenerator;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
+import org.apache.helix.manager.zk.ZkBaseDataAccessor;
+import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.ExternalView;
+import org.apache.helix.util.InstanceValidationUtil;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -43,7 +49,7 @@ public class TestBatchEnableInstances extends TaskTestBase {
_accessor = new ConfigAccessor(_gZkClient);
}
- @Test(enabled = false)
+ @Test
public void testOldEnableDisable() throws InterruptedException {
_gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME,
_participants[0].getInstanceName(), false);
@@ -59,7 +65,7 @@ public class TestBatchEnableInstances extends TaskTestBase {
_participants[0].getInstanceName(), true);
}
- @Test(enabled = false)
+ @Test
public void testBatchEnableDisable() throws InterruptedException {
_gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME,
Arrays.asList(_participants[0].getInstanceName(),
_participants[1].getInstanceName()),
@@ -78,7 +84,7 @@ public class TestBatchEnableInstances extends TaskTestBase {
true);
}
- @Test(enabled = false)
+ @Test
public void testOldDisableBatchEnable() throws InterruptedException {
_gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME,
_participants[0].getInstanceName(), false);
@@ -101,13 +107,40 @@ public class TestBatchEnableInstances extends
TaskTestBase {
_participants[0].getInstanceName(), true);
}
- @Test(enabled = false)
+ @Test
public void testBatchDisableOldEnable() throws InterruptedException {
+ // disable 2 instances
_gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME,
Arrays.asList(_participants[0].getInstanceName(),
_participants[1].getInstanceName()),
- false);
- _gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME,
- _participants[0].getInstanceName(), true);
+ false, InstanceConstants.InstanceDisabledType.USER_OPERATION,
"reason_1");
+ // check disabled type from InstanceValidationUtil
+ HelixDataAccessor dataAccessor =
+ new ZKHelixDataAccessor(CLUSTER_NAME, new
ZkBaseDataAccessor<>(_gZkClient));
+ Assert.assertEquals(InstanceValidationUtil
+ .getInstanceHelixDisabledType(dataAccessor,
_participants[1].getInstanceName()),
+ InstanceConstants.InstanceDisabledType.USER_OPERATION.toString());
+ // check disabled reason from getter in clusterConfig
+ ClusterConfig clusterConfig =
+ dataAccessor.getProperty(dataAccessor.keyBuilder().clusterConfig());
+ Assert.assertEquals(
+
clusterConfig.getInstanceHelixDisabledReason(_participants[1].getInstanceName()),
+ "reason_1");
+ Assert.assertNotNull(
+
clusterConfig.getInstanceHelixDisabledTimeStamp(_participants[0].getInstanceName()));
+ // enable the second instance
+ _gSetupTool.getClusterManagementTool()
+ .enableInstance(CLUSTER_NAME, _participants[0].getInstanceName(),
true);
+ // check disabled type for second instance from InstanceValidationUtil and
clusterConfig
+ Assert.assertEquals(InstanceValidationUtil
+ .getInstanceHelixDisabledType(dataAccessor,
_participants[0].getInstanceName()),
+ InstanceConstants.INSTANCE_NOT_DISABLED);
+ clusterConfig =
dataAccessor.getProperty(dataAccessor.keyBuilder().clusterConfig());
+ Assert.assertEquals(
+
clusterConfig.getInstanceHelixDisabledType(_participants[0].getInstanceName()),
+ InstanceConstants.INSTANCE_NOT_DISABLED);
+ Assert.assertNull(
+
clusterConfig.getInstanceHelixDisabledTimeStamp(_participants[0].getInstanceName()));
+
Thread.sleep(2000);
ExternalView externalView = _gSetupTool.getClusterManagementTool()
@@ -125,4 +158,5 @@ public class TestBatchEnableInstances extends TaskTestBase {
Arrays.asList(_participants[0].getInstanceName(),
_participants[1].getInstanceName()),
true);
}
+
}
diff --git a/helix-core/src/test/java/org/apache/helix/mock/MockHelixAdmin.java
b/helix-core/src/test/java/org/apache/helix/mock/MockHelixAdmin.java
index 6390edf73..87231d5d7 100644
--- a/helix-core/src/test/java/org/apache/helix/mock/MockHelixAdmin.java
+++ b/helix-core/src/test/java/org/apache/helix/mock/MockHelixAdmin.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import org.apache.helix.BaseDataAccessor;
import org.apache.helix.HelixAdmin;
@@ -49,6 +50,9 @@ import org.apache.helix.model.ResourceConfig;
import org.apache.helix.model.StateModelDefinition;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
+import static
org.apache.helix.manager.zk.ZKHelixAdmin.assembleInstanceBatchedDisabledInfo;
+
+
public class MockHelixAdmin implements HelixAdmin {
private HelixDataAccessor _dataAccessor;
@@ -285,6 +289,7 @@ public class MockHelixAdmin implements HelixAdmin {
InstanceConfig instanceConfig = new InstanceConfig(record);
instanceConfig.setInstanceEnabled(enabled);
if (!enabled) {
+ instanceConfig.resetInstanceDisabledTypeAndReason();
if (reason != null) {
instanceConfig.setInstanceDisabledReason(reason);
}
@@ -295,16 +300,46 @@ public class MockHelixAdmin implements HelixAdmin {
_baseDataAccessor.set(instanceConfigPath, instanceConfig.getRecord(), 0);
}
- @Override public void enableInstance(String clusterName, List<String>
instances,
- boolean enabled) {
+ @Override
+ public void enableInstance(String clusterName, List<String> instances,
boolean enabled) {
+ enableInstance(clusterName, instances, enabled, null, null);
+ }
+
+ @Override
+ public void enableInstance(String clusterName, List<String> instances,
boolean enabled,
+ InstanceConstants.InstanceDisabledType disabledType, String reason) {
+
+ String path = PropertyPathBuilder.clusterConfig(clusterName);
+ if (!_baseDataAccessor.exists(path, 0)) {
+ _baseDataAccessor.create(path, new ZNRecord(clusterName), 0);
+ }
+
+ ZNRecord record = (ZNRecord) _baseDataAccessor.get(path, null, 0);
+ ClusterConfig clusterConfig = new ClusterConfig(record);
+
+ Map<String, String> disabledInstances = new TreeMap<>();
+ if (clusterConfig.getDisabledInstances() != null) {
+ disabledInstances.putAll(clusterConfig.getDisabledInstances());
+ }
+ if (enabled) {
+ disabledInstances.keySet().removeAll(instances);
+ } else {
+ for (String disabledInstance : instances) {
+ disabledInstances
+ .put(disabledInstance,
assembleInstanceBatchedDisabledInfo(disabledType, reason));
+ }
+ }
+ clusterConfig.setDisabledInstances(disabledInstances);
}
- @Override public void enableResource(String clusterName, String
resourceName, boolean enabled) {
+ @Override
+ public void enableResource(String clusterName, String resourceName, boolean
enabled) {
}
- @Override public void enablePartition(boolean enabled, String clusterName,
String instanceName,
+ @Override
+ public void enablePartition(boolean enabled, String clusterName, String
instanceName,
String resourceName, List<String> partitionNames) {
}
diff --git
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
index fefe5c3cf..724a8ec44 100644
---
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
+++
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
@@ -44,6 +44,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.helix.HelixAdmin;
import org.apache.helix.HelixDataAccessor;
import org.apache.helix.HelixException;
+import org.apache.helix.constants.InstanceConstants;
import org.apache.helix.manager.zk.ZKHelixDataAccessor;
import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.InstanceConfig;
@@ -154,6 +155,8 @@ public class InstancesAccessor extends
AbstractHelixResource {
@QueryParam("command") String command,
@QueryParam("continueOnFailures") boolean continueOnFailures,
@QueryParam("skipZKRead") boolean skipZKRead,
+ @QueryParam("instanceDisabledType") String disabledType,
+ @QueryParam("instanceDisabledReason") String disabledReason,
String content) {
Command cmd;
try {
@@ -179,7 +182,15 @@ public class InstancesAccessor extends
AbstractHelixResource {
admin.enableInstance(clusterId, enableInstances, true);
break;
case disable:
- admin.enableInstance(clusterId, enableInstances, false);
+ InstanceConstants.InstanceDisabledType disabledTypeEnum = null;
+ if (disabledType != null) {
+ try {
+ disabledTypeEnum =
InstanceConstants.InstanceDisabledType.valueOf(disabledType);
+ } catch (IllegalArgumentException ex) {
+ return badRequest("Invalid instanceDisabledType!");
+ }
+ }
+ admin.enableInstance(clusterId, enableInstances, false,
disabledTypeEnum, disabledReason);
break;
case stoppable:
return batchGetStoppableInstances(clusterId, node, skipZKRead,
continueOnFailures);
diff --git
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstancesAccessor.java
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstancesAccessor.java
index 7f046e49f..7e9058ff8 100644
---
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstancesAccessor.java
+++
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstancesAccessor.java
@@ -137,37 +137,45 @@ public class TestInstancesAccessor extends
AbstractTestClass {
System.out.println("End test :" + TestHelper.getTestMethodName());
}
- @Test(enabled = false)
+ @Test
public void testUpdateInstances() throws IOException {
// TODO: Reenable the test after storage node fix the problem
// Batch disable instances
- List<String> instancesToDisable = Arrays.asList(new String[] {
- CLUSTER_NAME + "localhost_12918", CLUSTER_NAME + "localhost_12919",
- CLUSTER_NAME + "localhost_12920"
- });
- Entity entity = Entity.entity(
- OBJECT_MAPPER.writeValueAsString(ImmutableMap
+ List<String> instancesToDisable = Arrays.asList(new String[]{
+ CLUSTER_NAME + "localhost_12918",
+ CLUSTER_NAME + "localhost_12919", CLUSTER_NAME + "localhost_12920"});
+ Entity entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
.of(InstancesAccessor.InstancesProperties.instances.name(),
instancesToDisable)),
MediaType.APPLICATION_JSON_TYPE);
- post("clusters/" + CLUSTER_NAME + "/instances", ImmutableMap.of("command",
"disable"), entity,
- Response.Status.OK.getStatusCode());
+ post("clusters/" + CLUSTER_NAME + "/instances", ImmutableMap
+ .of("command", "disable", "instanceDisabledType", "USER_OPERATION",
+ "instanceDisabledReason", "reason_1"), entity,
Response.Status.OK.getStatusCode());
ClusterConfig clusterConfig =
_configAccessor.getClusterConfig(CLUSTER_NAME);
Assert.assertEquals(clusterConfig.getDisabledInstances().keySet(),
new HashSet<>(instancesToDisable));
-
- instancesToDisable = Arrays.asList(new String[] {
- CLUSTER_NAME + "localhost_12918", CLUSTER_NAME + "localhost_12920"
- });
- entity = Entity.entity(
- OBJECT_MAPPER.writeValueAsString(ImmutableMap
+ Assert
+ .assertEquals(clusterConfig.getInstanceHelixDisabledType(CLUSTER_NAME
+ "localhost_12918"),
+ "USER_OPERATION");
+ Assert.assertEquals(
+ clusterConfig.getInstanceHelixDisabledReason(CLUSTER_NAME +
"localhost_12918"), "reason_1");
+
+ instancesToDisable = Arrays
+ .asList(new String[]{CLUSTER_NAME + "localhost_12918", CLUSTER_NAME +
"localhost_12920"});
+ entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
.of(InstancesAccessor.InstancesProperties.instances.name(),
instancesToDisable)),
MediaType.APPLICATION_JSON_TYPE);
- post("clusters/" + CLUSTER_NAME + "/instances", ImmutableMap.of("command",
"enable"), entity,
- Response.Status.OK.getStatusCode());
+ post("clusters/" + CLUSTER_NAME + "/instances", ImmutableMap
+ .of("command", "enable", "instanceDisabledType", "USER_OPERATION",
"instanceDisabledReason",
+ "reason_1"), entity, Response.Status.OK.getStatusCode());
clusterConfig = _configAccessor.getClusterConfig(CLUSTER_NAME);
Assert.assertEquals(clusterConfig.getDisabledInstances().keySet(),
new HashSet<>(Arrays.asList(CLUSTER_NAME + "localhost_12919")));
+ Assert
+ .assertEquals(clusterConfig.getInstanceHelixDisabledType(CLUSTER_NAME
+ "localhost_12918"),
+ "INSTANCE_NOT_DISABLED");
+ Assert
+ .assertNull(clusterConfig.getInstanceHelixDisabledReason(CLUSTER_NAME
+ "localhost_12918"));
System.out.println("End test :" + TestHelper.getTestMethodName());
}