This is an automated email from the ASF dual-hosted git repository.
xyuanlu pushed a commit to branch ApplicationClusterManager
in repository https://gitbox.apache.org/repos/asf/helix.git
The following commit(s) were added to refs/heads/ApplicationClusterManager by
this push:
new c023a98be Add API for Instance evacuation (#2588)
c023a98be is described below
commit c023a98be2bfbc969858c9a52a98186bc9db2070
Author: xyuanlu <[email protected]>
AuthorDate: Tue Aug 15 17:18:58 2023 -0700
Add API for Instance evacuation (#2588)
---
.../apache/helix/constants/InstanceConstants.java | 8 +++++
.../src/main/java/org/apache/helix/HelixAdmin.java | 3 ++
.../org/apache/helix/manager/zk/ZKHelixAdmin.java | 34 ++++++++++++++++++++++
.../org/apache/helix/model/InstanceConfig.java | 14 ++++++++-
.../java/org/apache/helix/mock/MockHelixAdmin.java | 10 +++++--
.../rest/server/resources/AbstractResource.java | 3 +-
.../server/resources/helix/InstancesAccessor.java | 1 +
.../resources/helix/PerInstanceAccessor.java | 4 +++
.../helix/rest/server/TestPerInstanceAccessor.java | 11 +++++++
9 files changed, 83 insertions(+), 5 deletions(-)
diff --git
a/helix-common/src/main/java/org/apache/helix/constants/InstanceConstants.java
b/helix-common/src/main/java/org/apache/helix/constants/InstanceConstants.java
index 5bacef7a9..379bbaf02 100644
---
a/helix-common/src/main/java/org/apache/helix/constants/InstanceConstants.java
+++
b/helix-common/src/main/java/org/apache/helix/constants/InstanceConstants.java
@@ -8,4 +8,12 @@ public class InstanceConstants {
USER_OPERATION,
DEFAULT_INSTANCE_DISABLE_TYPE
}
+
+ public enum InstanceOperation {
+ EVACUATE, // Node will be removed after a period of time
+ SWAP_IN, // New node joining for swap operation
+ SWAP_OUT, // Existing Node to be removed for swap operation
+ ENABLE, // Backward compatible field for HELIX_ENABLED. Set when
changing from disabled to enabled.
+ DISABLE // Backward compatible field for HELIX_ENABLED. Set when
changing from enabled to disabled.
+ }
}
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 6c6d4be5c..ab4ba57b6 100644
--- a/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
+++ b/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
@@ -302,6 +302,9 @@ public interface HelixAdmin {
*/
void enableInstance(String clusterName, List<String> instances, boolean
enabled);
+ void setInstanceOperation(String clusterName, String instance,
+ InstanceConstants.InstanceOperation instanceOperation);
+
/**
* Disable or enable a resource
* @param clusterName
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 63986e6b5..d45f8cdb8 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
@@ -374,6 +374,40 @@ public class ZKHelixAdmin implements HelixAdmin {
//enableInstance(clusterName, instances, enabled, null, null);
}
+ @Override
+ // TODO: Name may change in future
+ public void setInstanceOperation(String clusterName, String instanceName,
+ InstanceConstants.InstanceOperation instanceOperation) {
+
+ BaseDataAccessor<ZNRecord> baseAccessor = new
ZkBaseDataAccessor<>(_zkClient);
+ String path = PropertyPathBuilder.instanceConfig(clusterName,
instanceName);
+
+ if (!baseAccessor.exists(path, 0)) {
+ throw new HelixException(
+ "Cluster " + clusterName + ", instance: " + instanceName + ",
instance config does not exist");
+ }
+
+ boolean succeeded = baseAccessor.update(path, new DataUpdater<ZNRecord>() {
+ @Override
+ public ZNRecord update(ZNRecord currentData) {
+ if (currentData == null) {
+ throw new HelixException(
+ "Cluster: " + clusterName + ", instance: " + instanceName + ",
participant config is null");
+ }
+
+ InstanceConfig config = new InstanceConfig(currentData);
+ // TODO: add sanity check in config.setInstanceOperation and throw
exception when needed.
+ // TODO: Also instance enabled in instance config
+ config.setInstanceOperation(instanceOperation);
+ return config.getRecord();
+ }
+ }, AccessOption.PERSISTENT);
+
+ if (!succeeded) {
+ throw new HelixException("Failed to update instance operation. Please
check if instance is disabled.");
+ }
+ }
+
@Override
public void enableResource(final String clusterName, final String
resourceName,
final boolean enabled) {
diff --git
a/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
b/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
index 01c1f682f..bdd49cafb 100644
--- a/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
@@ -61,7 +61,8 @@ public class InstanceConfig extends HelixProperty {
DELAY_REBALANCE_ENABLED,
MAX_CONCURRENT_TASK,
INSTANCE_CAPACITY_MAP,
- TARGET_TASK_THREAD_POOL_SIZE
+ TARGET_TASK_THREAD_POOL_SIZE,
+ INSTANCE_OPERATION
}
public static final int WEIGHT_NOT_SET = -1;
@@ -329,6 +330,17 @@ public class InstanceConfig extends HelixProperty {
return
_record.getLongField(InstanceConfigProperty.HELIX_ENABLED_TIMESTAMP.name(), -1);
}
+ public void setInstanceOperation(InstanceConstants.InstanceOperation
operation) {
+ // TODO: also setInstanceEnabled after sanity check.
+
+ _record.setSimpleField(InstanceConfigProperty.INSTANCE_OPERATION.name(),
+ operation.name());
+ }
+
+ public String getInstanceOperation() {
+ return
_record.getStringField(InstanceConfigProperty.INSTANCE_OPERATION.name(), "");
+ }
+
/**
* Check if this instance is enabled for a given partition
* This API is deprecated, and will be removed in next major release.
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 ec25d42be..0069deac8 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,8 +23,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.TreeMap;
+import org.apache.helix.AccessOption;
import org.apache.helix.BaseDataAccessor;
import org.apache.helix.HelixAdmin;
import org.apache.helix.HelixDataAccessor;
@@ -50,8 +50,7 @@ import org.apache.helix.model.MaintenanceSignal;
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;
+import org.apache.helix.zookeeper.zkclient.DataUpdater;
public class MockHelixAdmin implements HelixAdmin {
@@ -306,6 +305,11 @@ public class MockHelixAdmin implements HelixAdmin {
}
+ @Override
+ public void setInstanceOperation(String clusterName, String instanceName,
+ InstanceConstants.InstanceOperation instanceOperation) {
+ }
+
@Override
public void enableResource(String clusterName, String resourceName, boolean
enabled) {
diff --git
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/AbstractResource.java
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/AbstractResource.java
index b3ca029c5..76733b92a 100644
---
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/AbstractResource.java
+++
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/AbstractResource.java
@@ -84,7 +84,8 @@ public class AbstractResource {
enableWagedRebalanceForAllResources,
purgeOfflineParticipants,
getInstance,
- getAllInstances
+ getAllInstances,
+ setInstanceOperation // TODO: Name is just a place holder, may change in
future
}
@Context
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 d4f8f90af..d397ada0f 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;
diff --git
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
index d77e74355..8fcd2ab35 100644
---
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
+++
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
@@ -370,6 +370,7 @@ public class PerInstanceAccessor extends
AbstractHelixResource {
@POST
public Response updateInstance(@PathParam("clusterId") String clusterId,
@PathParam("instanceName") String instanceName, @QueryParam("command")
String command,
+ @QueryParam("instanceOperation") InstanceConstants.InstanceOperation
state,
@QueryParam("instanceDisabledType") String disabledType,
@QueryParam("instanceDisabledReason") String disabledReason, String
content) {
Command cmd;
@@ -414,6 +415,9 @@ public class PerInstanceAccessor extends
AbstractHelixResource {
OBJECT_MAPPER.getTypeFactory()
.constructCollectionType(List.class, String.class)));
break;
+ case setInstanceOperation:
+ admin.setInstanceOperation(clusterId, instanceName, state);
+ break;
case addInstanceTag:
if (!validInstance(node, instanceName)) {
return badRequest("Instance names are not match!");
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 5d2fc7082..fe4e19906 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
@@ -486,6 +486,17 @@ public class TestPerInstanceAccessor extends
AbstractTestClass {
Assert.assertEquals(new HashSet<>(instanceConfig.getDisabledPartitionsMap()
.get(CLUSTER_NAME + dbName.substring(0, dbName.length() - 1))),
new HashSet<>(Arrays.asList(CLUSTER_NAME + dbName + "0", CLUSTER_NAME
+ dbName + "3")));
+
+ // test set instance operation
+ new
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=setInstanceOperation&instanceOperation=EVACUATE")
+ .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+ instanceConfig = _configAccessor.getInstanceConfig(CLUSTER_NAME,
INSTANCE_NAME);
+ Assert.assertEquals(
+ instanceConfig.getInstanceOperation(),
InstanceConstants.InstanceOperation.EVACUATE.toString());
+ new
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=setInstanceOperation&instanceOperation=INVALIDOP")
+
.expectedReturnStatusCode(Response.Status.NOT_FOUND.getStatusCode()).format(CLUSTER_NAME,
INSTANCE_NAME).post(this, entity);
+ new
JerseyUriRequestBuilder("clusters/{}/instances/{}?command=setInstanceOperation")
+
.expectedReturnStatusCode(Response.Status.BAD_REQUEST.getStatusCode()).format(CLUSTER_NAME,
INSTANCE_NAME).post(this, entity);
System.out.println("End test :" + TestHelper.getTestMethodName());
}