This is an automated email from the ASF dual-hosted git repository. hulee pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/helix.git
commit 2d712e14f35d379af717b7e213853e0c98ae73c3 Author: Junkai Xue <[email protected]> AuthorDate: Tue Mar 12 12:40:41 2019 -0700 Dummy check for customized API For this change, it build the dummy check for customized API. It contains following changes: 1. RESTConfig can setup the customized URL 2. Define the end point of per participant and per partition. 3. Add dummy logic that return true for all the check status of customized checks. RB=1596427 BUG=HELIX-1678 G=helix-reviewers A=jjwang Signed-off-by: Hunter Lee <[email protected]> --- .../main/java/org/apache/helix/ConfigAccessor.java | 21 ++++++++ .../main/java/org/apache/helix/PropertyKey.java | 9 ++++ .../main/java/org/apache/helix/PropertyType.java | 9 +++- .../org/apache/helix/model/HelixConfigScope.java | 4 +- .../java/org/apache/helix/model/RESTConfig.java | 51 ++++++++++++++++++ .../apache/helix/util/InstanceValidationUtil.java | 60 +++++++++++++++++++++- .../helix/rest/server/TestInstanceAccessor.java | 14 +++++ 7 files changed, 164 insertions(+), 4 deletions(-) diff --git a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java index 53f42fb..1d4c5e8 100644 --- a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java +++ b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java @@ -34,6 +34,7 @@ import org.apache.helix.model.HelixConfigScope; import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty; import org.apache.helix.manager.zk.ZKUtil; import org.apache.helix.model.InstanceConfig; +import org.apache.helix.model.RESTConfig; import org.apache.helix.model.ResourceConfig; import org.apache.helix.model.builder.HelixConfigScopeBuilder; import org.apache.helix.util.StringTemplate; @@ -562,6 +563,26 @@ public class ConfigAccessor { } /** + * Get ClusterConfig of the given cluster. + * + * @param clusterName + * + * @return + */ + public RESTConfig getRESTConfig(String clusterName) { + HelixConfigScope scope = + new HelixConfigScopeBuilder(ConfigScopeProperty.REST).forCluster(clusterName).build(); + ZNRecord record = getConfigZnRecord(scope); + + if (record == null) { + LOG.warn("No config found at " + scope.getZkPath()); + return null; + } + + return new RESTConfig(record); + } + + /** * Set ClusterConfig of the given cluster. * The current Cluster config will be replaced with the given clusterConfig. * WARNING: This is not thread-safe or concurrent updates safe. diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java index 03d369b..6350b3c 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java @@ -39,6 +39,7 @@ import org.apache.helix.model.MaintenanceSignal; import org.apache.helix.model.Message; import org.apache.helix.model.ParticipantHistory; import org.apache.helix.model.PauseSignal; +import org.apache.helix.model.RESTConfig; import org.apache.helix.model.ResourceConfig; import org.apache.helix.model.StateModelDefinition; import org.apache.helix.model.StatusUpdate; @@ -779,6 +780,14 @@ public class PropertyKey { return new PropertyKey(PropertyType.WORKFLOWCONTEXT, WorkflowContext.class, _clusterName, workflowName); } + + /** + * Get a property key associated with {@link ResourceConfig} + * @return {@link PropertyKey} + */ + public PropertyKey restConfig() { + return new PropertyKey(RESTCONFIGS, RESTConfig.class, _clusterName); + } } /** diff --git a/helix-core/src/main/java/org/apache/helix/PropertyType.java b/helix-core/src/main/java/org/apache/helix/PropertyType.java index 2381acc..e234a3b 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyType.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyType.java @@ -27,7 +27,8 @@ enum Type { INSTANCE, CONTROLLER, RESOURCE, - TASK + TASK, + REST } /** @@ -73,7 +74,11 @@ public enum PropertyType { WORKFLOW_CONFIG(Type.TASK, true, false, false, false, false), WORKFLOW_CONTEXT(Type.TASK, true, false, false, false, false), JOB_CONFIG(Type.TASK, true, false, false, false, false), - JOB_CONTEXT(Type.TASK, true, false, false, false, false); + JOB_CONTEXT(Type.TASK, true, false, false, false, false), + + // REST PROPERTIES + RESTCONFIGS(Type.REST, true, false, false, false, true); + // @formatter:on diff --git a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java index 9d3b41a..7c5c91d 100644 --- a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java +++ b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java @@ -35,7 +35,8 @@ public class HelixConfigScope { PARTICIPANT(2, 0), RESOURCE(2, 0), PARTITION(2, 1), - CONSTRAINT(2, 0); + CONSTRAINT(2, 0), + REST(2, 0); final int _zkPathArgNum; final int _mapKeyArgNum; @@ -82,6 +83,7 @@ public class HelixConfigScope { template.addEntry(ConfigScopeProperty.CLUSTER, 1, "/{clusterName}/CONFIGS/CLUSTER"); template.addEntry(ConfigScopeProperty.PARTICIPANT, 1, "/{clusterName}/CONFIGS/PARTICIPANT"); template.addEntry(ConfigScopeProperty.RESOURCE, 1, "/{clusterName}/CONFIGS/RESOURCE"); + template.addEntry(ConfigScopeProperty.REST, 2, "/{clusterName}/CONFIGS/REST/{clusterName}"); } final ConfigScopeProperty _type; diff --git a/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java b/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java new file mode 100644 index 0000000..a47226c --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java @@ -0,0 +1,51 @@ +package org.apache.helix.model; + +import org.apache.helix.HelixProperty; +import org.apache.helix.ZNRecord; + +public class RESTConfig extends HelixProperty { + public enum RESTConfigProperty { + CUSTOMIZED_HEALTH_URL // User customized URL for getting participant health status or partition + // health status. + } + + /** + * Instantiate REST config for a specific cluster + * @param cluster the cluster identifier + */ + public RESTConfig(String cluster) { + super(cluster); + } + + /** + * Instantiate REST config with a pre-populated record + * + * @param record a ZNRecord corresponding to a cluster configuration + */ + public RESTConfig(ZNRecord record) { + super(record); + } + + /** + * Set up the user defined URL for check per participant health / per partition health by combine + * URL and final endpoint. It must ended without "/" + * + * eg: http://*:12345/customized/path/check + * + * @param customizedHealthURL + */ + public void setCustomizedHealthURL(String customizedHealthURL) { + _record.setSimpleField(RESTConfigProperty.CUSTOMIZED_HEALTH_URL.name(), customizedHealthURL); + } + + /** + * Get user defined URL to construct per participant health / partition health + * Return null if it does not exist. + * + * @return + */ + public String getCustomizedHealthURL() { + return _record.getSimpleField(RESTConfigProperty.CUSTOMIZED_HEALTH_URL.name()); + } + +} 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 b701864..81266c2 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 @@ -21,7 +21,6 @@ package org.apache.helix.util; import java.util.List; import java.util.Map; - import org.apache.helix.AccessOption; import org.apache.helix.ConfigAccessor; import org.apache.helix.HelixDataAccessor; @@ -32,6 +31,7 @@ import org.apache.helix.model.ClusterConfig; import org.apache.helix.model.CurrentState; import org.apache.helix.model.InstanceConfig; import org.apache.helix.model.LiveInstance; +import org.apache.helix.model.RESTConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,6 +44,11 @@ import org.slf4j.LoggerFactory; public class InstanceValidationUtil { private static final Logger _logger = LoggerFactory.getLogger(InstanceValidationUtil.class); + public enum HealthStatusType { + instanceHealthStatus, + partitionHealthStatus + } + private InstanceValidationUtil() { } @@ -188,4 +193,57 @@ public class InstanceValidationUtil { _logger.warn(String.format("The instance %s is not active", instanceName)); return false; } + + /** + * Check the overall health status for instance including: + * 1. Per instance health status with application customized key-value entries + * 2. Sibling partitions (replicas for same partition holding on different node + * health status for the entire cluster. + * + * @param configAccessor + * @param clustername + * @param hostName + * @param customizedInputs + * @param partitionHealthMap + * @return + */ + public static boolean checkCustomizedHealthStatusForInstance(ConfigAccessor configAccessor, + String clustername, String hostName, Map<String, String> customizedInputs, + Map<String, Map<String, String>> partitionHealthMap, Map<String, String> instanceHealthMap) { + boolean isHealthy = true; + RESTConfig restConfig = configAccessor.getRESTConfig(clustername); + // If user customized URL is not ready, return true as the check + if (restConfig == null || restConfig.getCustomizedHealthURL() == null) { + return isHealthy; + } + // TODO : 1. Call REST with customized URL + // 2. Parse mapping result with string -> boolean value and return out for per instance + // 3. Check sibling nodes for partition health + isHealthy = + perInstanceHealthCheck(instanceHealthMap) || perPartitionHealthCheck(partitionHealthMap); + + return isHealthy; + } + + /** + * Fetch the health map based on health type: per instance or per partition + * Accessor can used for fetching data from ZK for per partition level. + * @param URL + * @param accessor + * @param healthStatusType + * @return + */ + public static Map<String, Map<String, String>> getHealthMapBasedOnType(String URL, + HelixDataAccessor accessor, HealthStatusType healthStatusType) { + return null; + } + + protected static boolean perInstanceHealthCheck(Map<String, String> statusMap) { + return true; + } + + protected static boolean perPartitionHealthCheck( + Map<String, Map<String, String>> partitionHealthMap) { + return true; + } } diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java index 858ea89..be47cab 100644 --- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java +++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java @@ -22,6 +22,7 @@ package org.apache.helix.rest.server; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -40,6 +41,7 @@ import org.apache.helix.model.Message; import org.apache.helix.rest.server.resources.AbstractResource; import org.apache.helix.rest.server.resources.helix.InstanceAccessor; import org.apache.helix.rest.server.util.JerseyUriRequestBuilder; +import org.apache.helix.util.InstanceValidationUtil; import org.codehaus.jackson.JsonNode; import org.testng.Assert; import org.testng.annotations.Test; @@ -400,4 +402,16 @@ public class TestInstanceAccessor extends AbstractTestClass { .expectedReturnStatusCode(Response.Status.NOT_FOUND.getStatusCode()) .format(CLUSTER_NAME, instanceName).post(this, entity); } + + public void testCustomizedChecks() { + // TODO: This is fake testing. Only validate it returns true value of this function. + // For future, we need test: 1. mock the input of per participant API result to test validate logic + // 2. mock the input of per partition API result to test the sibling + // check logic + System.out.println("Start test :" + TestHelper.getTestMethodName()); + String instanceName = "TestInstance"; + Assert.assertTrue(InstanceValidationUtil + .checkCustomizedHealthStatusForInstance(_configAccessor, CLUSTER_NAME, instanceName, + Collections.EMPTY_MAP, Collections.EMPTY_MAP, Collections.EMPTY_MAP)); + } }
