This is an automated email from the ASF dual-hosted git repository. jiajunwang pushed a commit to branch helix-0.9.x in repository https://gitbox.apache.org/repos/asf/helix.git
commit 6800dc352ae36aa07c0b320f2ce861223b05697d Author: Ali Reza Zamani Zadeh Najari <[email protected]> AuthorDate: Mon Nov 11 11:28:32 2019 -0800 Add CloudConfig code In order to move toward supporting cloud environments and autoregisterations, we need to add CloudConfig to Zookeeper. The code regarding CloudConfig is added. A new test has been added to check the correctness of the code. --- .../main/java/org/apache/helix/ConfigAccessor.java | 23 ++ .../main/java/org/apache/helix/PropertyKey.java | 11 + .../helix/cloud/constants/CloudProvider.java | 25 ++ .../java/org/apache/helix/model/CloudConfig.java | 290 +++++++++++++++++++++ .../org/apache/helix/model/HelixConfigScope.java | 6 +- .../model/builder/HelixConfigScopeBuilder.java | 3 + .../apache/helix/model/cloud/TestCloudConfig.java | 204 +++++++++++++++ 7 files changed, 561 insertions(+), 1 deletion(-) 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 15ea4a0..9bd84d1 100644 --- a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java +++ b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java @@ -30,6 +30,7 @@ import java.util.TreeMap; import org.apache.helix.manager.zk.ZKUtil; import org.apache.helix.manager.zk.client.HelixZkClient; import org.apache.helix.model.ClusterConfig; +import org.apache.helix.model.CloudConfig; import org.apache.helix.model.ConfigScope; import org.apache.helix.model.HelixConfigScope; import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty; @@ -563,6 +564,28 @@ public class ConfigAccessor { } /** + * Get CloudConfig of the given cluster. + * @param clusterName + * @return The instance of {@link CloudConfig} + */ + public CloudConfig getCloudConfig(String clusterName) { + if (!ZKUtil.isClusterSetup(clusterName, zkClient)) { + throw new HelixException( + String.format("Failed to get config. cluster: %s is not setup.", clusterName)); + } + HelixConfigScope scope = + new HelixConfigScopeBuilder(ConfigScopeProperty.CLOUD).forCluster(clusterName).build(); + ZNRecord record = getConfigZnRecord(scope); + + if (record == null) { + LOG.warn("No cloud config found at {}.", scope.getZkPath()); + return null; + } + + return new CloudConfig(record); + } + + /** * Get RestConfig of the given cluster. * * @param clusterName The cluster 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 369e48e..533cfc1 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java @@ -24,6 +24,7 @@ import static org.apache.helix.PropertyType.*; import java.util.Arrays; import java.util.Objects; +import org.apache.helix.model.CloudConfig; import org.apache.helix.model.ClusterConfig; import org.apache.helix.model.ClusterConstraints; import org.apache.helix.model.ControllerHistory; @@ -214,6 +215,16 @@ public class PropertyKey { _clusterName, ConfigScopeProperty.CLUSTER.toString(), _clusterName); } + + /** + * Get a property key associated with this Cloud configuration + * @return {@link PropertyKey} + */ + public PropertyKey cloudConfig() { + return new PropertyKey(CONFIGS, ConfigScopeProperty.CLOUD, CloudConfig.class, + _clusterName, ConfigScopeProperty.CLOUD.name(), _clusterName); + } + /** * Get a property key associated with {@link InstanceConfig} * @return {@link PropertyKey} diff --git a/helix-core/src/main/java/org/apache/helix/cloud/constants/CloudProvider.java b/helix-core/src/main/java/org/apache/helix/cloud/constants/CloudProvider.java new file mode 100644 index 0000000..1cb836f --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/cloud/constants/CloudProvider.java @@ -0,0 +1,25 @@ +package org.apache.helix.cloud.constants; + +/* + * 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. + */ + +public enum CloudProvider { + AZURE, + CUSTOMIZED +} diff --git a/helix-core/src/main/java/org/apache/helix/model/CloudConfig.java b/helix-core/src/main/java/org/apache/helix/model/CloudConfig.java new file mode 100644 index 0000000..c8ab6eb --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/model/CloudConfig.java @@ -0,0 +1,290 @@ +package org.apache.helix.model; + +/* + * 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.ArrayList; +import java.util.List; +import org.apache.helix.HelixException; +import org.apache.helix.HelixProperty; +import org.apache.helix.ZNRecord; +import org.apache.helix.cloud.constants.CloudProvider; + +/** + * Cloud configurations + */ +public class CloudConfig extends HelixProperty { + /** + * Configurable characteristics of a cloud. + * NOTE: Do NOT use this field name directly, use its corresponding getter/setter in the + * CloudConfig. + */ + public enum CloudConfigProperty { + CLOUD_ENABLED, // determine whether the cluster is inside cloud environment. + CLOUD_PROVIDER, // the environment the cluster is in, e.g. Azure, AWS, or Customized + CLOUD_ID, // the cloud Id that belongs to this cluster. + + // If user uses Helix supported default provider, the below entries will not be shown in + // CloudConfig. + CLOUD_INFO_SOURCE, // the source for retrieving the cloud information. + CLOUD_INFO_PROCESSOR_NAME // the name of the function that processes the fetching and parsing of + // cloud information. + } + + /* Default values */ + private static final boolean DEFAULT_CLOUD_ENABLED = false; + + /** + * Instantiate the CloudConfig for the cloud + * @param cluster + */ + public CloudConfig(String cluster) { + super(cluster); + } + + /** + * Instantiate with a pre-populated record + * @param record a ZNRecord corresponding to a cloud configuration + */ + public CloudConfig(ZNRecord record) { + super(record); + } + + /** + * Instantiate the config using each field individually. + * Users should use CloudConfig.Builder to create CloudConfig. + * @param cluster + * @param enabled + * @param cloudID + */ + public CloudConfig(String cluster, boolean enabled, CloudProvider cloudProvider, String cloudID, + List<String> cloudInfoSource, String cloudProcessorName) { + super(cluster); + _record.setBooleanField(CloudConfigProperty.CLOUD_ENABLED.name(), enabled); + _record.setSimpleField(CloudConfigProperty.CLOUD_PROVIDER.name(), cloudProvider.name()); + _record.setSimpleField(CloudConfigProperty.CLOUD_ID.name(), cloudID); + if (cloudProvider.equals(CloudProvider.CUSTOMIZED)) { + _record + .setSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_NAME.name(), cloudProcessorName); + _record.setListField(CloudConfigProperty.CLOUD_INFO_SOURCE.name(), cloudInfoSource); + } + } + + /** + * Enable/Disable the CLOUD_ENABLED field. + * @param enabled + */ + public void setCloudEnabled(boolean enabled) { + _record.setBooleanField(CloudConfigProperty.CLOUD_ENABLED.name(), enabled); + } + + /** + * Whether CLOUD_ENABLED field is enabled or not. + * @return + */ + public boolean isCloudEnabled() { + return _record.getBooleanField(CloudConfigProperty.CLOUD_ENABLED.name(), false); + } + + /** + * Set the cloudID field. + * @param cloudID + */ + public void setCloudID(String cloudID) { + _record.setSimpleField(CloudConfigProperty.CLOUD_ID.name(), cloudID); + } + + /** + * Get the CloudID field. + * @return CloudID + */ + public String getCloudID() { + return _record.getSimpleField(CloudConfigProperty.CLOUD_ID.name()); + } + + /** + * Set the CLOUD_INFO_SOURCE field. + * @param cloudInfoSources + */ + public void setCloudInfoSource(List<String> cloudInfoSources) { + _record.setListField(CloudConfigProperty.CLOUD_INFO_SOURCE.name(), cloudInfoSources); + } + + /** + * Get the CLOUD_INFO_SOURCE field. + * @return CLOUD_INFO_SOURCE field. + */ + public List<String> getCloudInfoSources() { + return _record.getListField(CloudConfigProperty.CLOUD_INFO_SOURCE.name()); + } + + /** + * Set the CLOUD_INFO_PROCESSOR_NAME field. + * @param cloudInfoProcessorName + */ + public void setCloudInfoFProcessorName(String cloudInfoProcessorName) { + _record.setSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_NAME.name(), + cloudInfoProcessorName); + } + + /** + * Get the CLOUD_INFO_PROCESSOR_NAME field. + * @return CLOUD_INFO_PROCESSOR_NAME field. + */ + public String getCloudInfoProcessorName() { + return _record.getSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_NAME.name()); + } + + /** + * Set the CLOUD_PROVIDER field. + * @param cloudProvider + */ + public void setCloudProvider(CloudProvider cloudProvider) { + _record.setSimpleField(CloudConfigProperty.CLOUD_PROVIDER.name(), cloudProvider.name()); + } + + /** + * Get the CLOUD_PROVIDER field. + * @return CLOUD_PROVIDER field. + */ + public String getCloudProvider() { + return _record.getSimpleField(CloudConfigProperty.CLOUD_PROVIDER.name()); + } + + public static class Builder { + private String _clusterName = null; + private CloudProvider _cloudProvider; + private boolean _cloudEnabled = DEFAULT_CLOUD_ENABLED; + private String _cloudID; + private List<String> _cloudInfoSources; + private String _cloudInfoProcessorName; + + public CloudConfig build() { + validate(); + return new CloudConfig(_clusterName, _cloudEnabled, _cloudProvider, _cloudID, + _cloudInfoSources, _cloudInfoProcessorName); + } + + /** + * Default constructor + */ + public Builder() { + } + + /** + * Constructor with Cluster Name as input + * @param clusterName + */ + public Builder(String clusterName) { + _clusterName = clusterName; + } + + /** + * Constructor with CloudConfig as input + * @param cloudConfig + */ + public Builder(CloudConfig cloudConfig) { + _cloudEnabled = cloudConfig.isCloudEnabled(); + _cloudProvider = CloudProvider.valueOf(cloudConfig.getCloudProvider()); + _cloudID = cloudConfig.getCloudID(); + _cloudInfoSources = cloudConfig.getCloudInfoSources(); + _cloudInfoProcessorName = cloudConfig.getCloudInfoProcessorName(); + } + + public Builder setClusterName(String v) { + _clusterName = v; + return this; + } + + public Builder setCloudEnabled(boolean isEnabled) { + _cloudEnabled = isEnabled; + return this; + } + + public Builder setCloudProvider(CloudProvider cloudProvider) { + _cloudProvider = cloudProvider; + return this; + } + + public Builder setCloudID(String v) { + _cloudID = v; + return this; + } + + public Builder setCloudInfoSources(List<String> v) { + _cloudInfoSources = v; + return this; + } + + public Builder addCloudInfoSource(String v) { + if (_cloudInfoSources == null) { + _cloudInfoSources = new ArrayList<String>(); + } + _cloudInfoSources.add(v); + return this; + } + + public Builder setCloudInfoProcessorName(String v) { + _cloudInfoProcessorName = v; + return this; + } + + public String getClusterName() { + return _clusterName; + } + + public CloudProvider getCloudProvider() { + return _cloudProvider; + } + + public boolean getCloudEnabled() { + return _cloudEnabled; + } + + public String getCloudID() { + return _cloudID; + } + + public List<String> getCloudInfoSources() { + return _cloudInfoSources; + } + + public String getCloudInfoProcessorName() { + return _cloudInfoProcessorName; + } + + private void validate() { + if (_cloudEnabled) { + if (_cloudID == null) { + throw new HelixException( + "This Cloud Configuration is Invalid. The CloudID is missing from the config."); + } + if (_cloudProvider == null) { + throw new HelixException( + "This Cloud Configuration is Invalid. The Cloud Provider is missing from the config."); + } else if (_cloudProvider == CloudProvider.CUSTOMIZED) { + if (_cloudInfoProcessorName == null || _cloudInfoSources == null || _cloudInfoSources.size() == 0) { + throw new HelixException( + "This Cloud Configuration is Invalid. CUSTOMIZED provider has been chosen without defining CloudInfoProcessorName or CloudInfoSources"); + } + } + } + } + } +} 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 7c5c91d..8d814c5 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 @@ -36,7 +36,8 @@ public class HelixConfigScope { RESOURCE(2, 0), PARTITION(2, 1), CONSTRAINT(2, 0), - REST(2, 0); + REST(2, 0), + CLOUD(2, 0); final int _zkPathArgNum; final int _mapKeyArgNum; @@ -78,12 +79,15 @@ public class HelixConfigScope { "/{clusterName}/CONFIGS/RESOURCE/{resourceName}"); template.addEntry(ConfigScopeProperty.PARTITION, 2, "/{clusterName}/CONFIGS/RESOURCE/{resourceName}"); + template.addEntry(ConfigScopeProperty.CLOUD, 2, + "/{clusterName}/CONFIGS/CLOUD/{clusterName}"); // get children 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}"); + template.addEntry(ConfigScopeProperty.CLOUD, 1, "/{clusterName}/CONFIGS/CLOUD"); } final ConfigScopeProperty _type; diff --git a/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java b/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java index b1a7cf6..78ed074 100644 --- a/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java +++ b/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java @@ -126,6 +126,9 @@ public class HelixConfigScopeBuilder { case REST: scope = new HelixConfigScope(_type, Arrays.asList(_clusterName, _clusterName), null); break; + case CLOUD: + scope = new HelixConfigScope(_type, Arrays.asList(_clusterName, _clusterName), null); + break; default: break; } diff --git a/helix-core/src/test/java/org/apache/helix/model/cloud/TestCloudConfig.java b/helix-core/src/test/java/org/apache/helix/model/cloud/TestCloudConfig.java new file mode 100644 index 0000000..ee83011 --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/model/cloud/TestCloudConfig.java @@ -0,0 +1,204 @@ +package org.apache.helix.model.cloud; + +/* + * 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.ArrayList; +import org.apache.helix.ConfigAccessor; +import org.apache.helix.HelixException; +import org.apache.helix.PropertyKey.Builder; +import org.apache.helix.TestHelper; +import org.apache.helix.ZkUnitTestBase; +import org.apache.helix.manager.zk.ZKHelixDataAccessor; +import org.apache.helix.manager.zk.ZkBaseDataAccessor; +import org.apache.helix.model.CloudConfig; +import org.apache.helix.cloud.constants.CloudProvider; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class TestCloudConfig extends ZkUnitTestBase { + + @Test(expectedExceptions = HelixException.class) + public void testCloudConfigNonExistentCluster() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + // Read CloudConfig from Zookeeper and get exception since cluster in not setup yet + ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient); + CloudConfig cloudConfigFromZk = _configAccessor.getCloudConfig(clusterName); + } + + @Test(dependsOnMethods = "testCloudConfigNonExistentCluster") + public void testCloudConfigNull() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + TestHelper.setupEmptyCluster(_gZkClient, clusterName); + // Read CloudConfig from Zookeeper + ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient); + CloudConfig cloudConfigFromZk = _configAccessor.getCloudConfig(clusterName); + // since CloudConfig is not written to ZooKeeper, the output should be null + Assert.assertNull(cloudConfigFromZk); + } + + @Test(dependsOnMethods = "testCloudConfigNull") + public void testCloudConfig() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + TestHelper.setupEmptyCluster(_gZkClient, clusterName); + + // Create dummy CloudConfig object + CloudConfig cloudConfig = new CloudConfig(clusterName); + cloudConfig.setCloudEnabled(true); + cloudConfig.setCloudProvider(CloudProvider.AZURE); + cloudConfig.setCloudID("TestID"); + List<String> infoURL = new ArrayList<String>(); + infoURL.add("TestURL"); + cloudConfig.setCloudInfoSource(infoURL); + cloudConfig.setCloudInfoFProcessorName("TestProcessor"); + + // Write the CloudConfig to Zookeeper + ZKHelixDataAccessor accessor = + new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor(_gZkClient)); + Builder keyBuilder = accessor.keyBuilder(); + accessor.setProperty(keyBuilder.cloudConfig(), cloudConfig); + + // Read CloudConfig from Zookeeper and check the content + ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient); + CloudConfig cloudConfigFromZk = _configAccessor.getCloudConfig(clusterName); + Assert.assertTrue(cloudConfigFromZk.isCloudEnabled()); + Assert.assertEquals(cloudConfigFromZk.getCloudProvider(), CloudProvider.AZURE.name()); + Assert.assertEquals(cloudConfigFromZk.getCloudID(), "TestID"); + Assert.assertEquals(cloudConfigFromZk.getCloudInfoSources().size(), 1); + Assert.assertEquals(cloudConfigFromZk.getCloudInfoSources().get(0), "TestURL"); + Assert.assertEquals(cloudConfigFromZk.getCloudInfoProcessorName(), "TestProcessor"); + } + + @Test(expectedExceptions = HelixException.class) + public void testUnverifiedCloudConfigBuilder() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + CloudConfig.Builder builder = new CloudConfig.Builder(clusterName); + builder.setCloudEnabled(true); + // Verify will fail because cloudID has net been defined. + CloudConfig cloudConfig = builder.build(); + } + + @Test(expectedExceptions = HelixException.class) + public void testUnverifiedCloudConfigBuilderEmptySources() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + CloudConfig.Builder builder = new CloudConfig.Builder(clusterName); + builder.setCloudEnabled(true); + builder.setCloudProvider(CloudProvider.CUSTOMIZED); + builder.setCloudID("TestID"); + List<String> emptyList = new ArrayList<String>(); + builder.setCloudInfoSources(emptyList); + builder.setCloudInfoProcessorName("TestProcessor"); + CloudConfig cloudConfig = builder.build(); + } + + @Test(expectedExceptions = HelixException.class) + public void testUnverifiedCloudConfigBuilderWithoutProcessor() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + CloudConfig.Builder builder = new CloudConfig.Builder(clusterName); + builder.setCloudEnabled(true); + builder.setCloudProvider(CloudProvider.CUSTOMIZED); + builder.setCloudID("TestID"); + List<String> testList = new ArrayList<String>(); + builder.setCloudInfoSources(testList); + builder.addCloudInfoSource("TestURL"); + CloudConfig cloudConfig = builder.build(); + } + + @Test(dependsOnMethods = "testCloudConfig") + public void testCloudConfigBuilder() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + TestHelper.setupEmptyCluster(_gZkClient, clusterName); + CloudConfig.Builder builder = new CloudConfig.Builder(clusterName); + builder.setCloudEnabled(true); + builder.setCloudProvider(CloudProvider.CUSTOMIZED); + builder.setCloudID("TestID"); + builder.addCloudInfoSource("TestURL0"); + builder.addCloudInfoSource("TestURL1"); + builder.setCloudInfoProcessorName("TestProcessor"); + + // Check builder getter methods + Assert.assertTrue(builder.getCloudEnabled()); + Assert.assertEquals(builder.getCloudProvider(), CloudProvider.CUSTOMIZED); + Assert.assertEquals(builder.getClusterName(), clusterName); + Assert.assertEquals(builder.getCloudID(), "TestID"); + List<String> listUrlFromBuilder = builder.getCloudInfoSources(); + Assert.assertEquals(listUrlFromBuilder.size(), 2); + Assert.assertEquals(listUrlFromBuilder.get(0), "TestURL0"); + Assert.assertEquals(listUrlFromBuilder.get(1), "TestURL1"); + Assert.assertEquals(builder.getCloudInfoProcessorName(), "TestProcessor"); + + CloudConfig cloudConfig = builder.build(); + + ZKHelixDataAccessor accessor = + new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor(_gZkClient)); + Builder keyBuilder = accessor.keyBuilder(); + accessor.setProperty(keyBuilder.cloudConfig(), cloudConfig); + + // Read CloudConfig from Zookeeper and check the content + ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient); + CloudConfig cloudConfigFromZk = _configAccessor.getCloudConfig(clusterName); + Assert.assertTrue(cloudConfigFromZk.isCloudEnabled()); + Assert.assertEquals(cloudConfigFromZk.getCloudProvider(), CloudProvider.CUSTOMIZED.name()); + Assert.assertEquals(cloudConfigFromZk.getCloudID(), "TestID"); + List<String> listUrlFromZk = cloudConfigFromZk.getCloudInfoSources(); + Assert.assertEquals(listUrlFromZk.get(0), "TestURL0"); + Assert.assertEquals(listUrlFromZk.get(1), "TestURL1"); + Assert.assertEquals(cloudConfigFromZk.getCloudInfoProcessorName(), "TestProcessor"); + } + + @Test(dependsOnMethods = "testCloudConfigBuilder") + public void testCloudConfigBuilderAzureProvider() { + String className = getShortClassName(); + String clusterName = "CLUSTER_" + className; + TestHelper.setupEmptyCluster(_gZkClient, clusterName); + CloudConfig.Builder builder = new CloudConfig.Builder(clusterName); + builder.setCloudEnabled(true); + builder.setCloudProvider(CloudProvider.AZURE); + builder.setCloudID("TestID"); + builder.setCloudInfoProcessorName("TestProcessor"); + + // Check builder getter methods + Assert.assertTrue(builder.getCloudEnabled()); + Assert.assertEquals(builder.getCloudProvider(), CloudProvider.AZURE); + + CloudConfig cloudConfig = builder.build(); + + ZKHelixDataAccessor accessor = + new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor(_gZkClient)); + Builder keyBuilder = accessor.keyBuilder(); + accessor.setProperty(keyBuilder.cloudConfig(), cloudConfig); + + // Read CloudConfig from Zookeeper and check the content + ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient); + CloudConfig cloudConfigFromZk = _configAccessor.getCloudConfig(clusterName); + Assert.assertTrue(cloudConfigFromZk.isCloudEnabled()); + Assert.assertEquals(cloudConfigFromZk.getCloudProvider(), CloudProvider.AZURE.name()); + + // Since CloudProvider is not CUSTOMIZED, CloudInfoProcessor will be null. + Assert.assertNull(cloudConfigFromZk.getCloudInfoProcessorName()); + } +}
