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 eecc5d438 Add support for pluggable external CloudInfoProcessor and 
CustomizedCloudProperties (#2497)
eecc5d438 is described below

commit eecc5d438fc312491aacea82cd653fe551ff7e52
Author: Zachary Pinto <[email protected]>
AuthorDate: Tue Jun 13 15:48:35 2023 -0700

    Add support for pluggable external CloudInfoProcessor and 
CustomizedCloudProperties (#2497)
    
    Add support for CloudInstanceInfoProcessor and CloudInstanceInfo from an 
external package when using CUSTOMIZED cloud provider.
---
 1                                                  |  0
 .../java/org/apache/helix/HelixCloudProperty.java  | 41 ++++++++-
 .../helix/manager/zk/ParticipantManager.java       | 23 ++----
 .../java/org/apache/helix/model/CloudConfig.java   | 27 +++++-
 .../helix/integration/TestHelixCloudProperty.java  | 96 ++++++++++++++++++++++
 .../paticipant/CustomCloudInstanceInformation.java | 42 ++++++++++
 .../CustomCloudInstanceInformationProcessor.java   | 46 +++++++++++
 .../paticipant/TestInstanceAutoJoin.java           | 54 +++++++++++-
 .../apache/helix/model/cloud/TestCloudConfig.java  |  7 +-
 9 files changed, 313 insertions(+), 23 deletions(-)

diff --git a/1 b/1
new file mode 100644
index 000000000..e69de29bb
diff --git a/helix-core/src/main/java/org/apache/helix/HelixCloudProperty.java 
b/helix-core/src/main/java/org/apache/helix/HelixCloudProperty.java
index db255b1a0..a5ea1fa7a 100644
--- a/helix-core/src/main/java/org/apache/helix/HelixCloudProperty.java
+++ b/helix-core/src/main/java/org/apache/helix/HelixCloudProperty.java
@@ -39,6 +39,7 @@ import org.slf4j.LoggerFactory;
 public class HelixCloudProperty {
   private static final Logger LOG = 
LoggerFactory.getLogger(HelixCloudProperty.class.getName());
   private static final String AZURE_CLOUD_PROPERTY_FILE = 
SystemPropertyKeys.AZURE_CLOUD_PROPERTIES;
+  private static final String DEFAULT_CLOUD_PROCESSOR_PACKAGE_PREFIX = 
"org.apache.helix.cloud.";
   private static final String CLOUD_INFO_SOURCE = "cloud_info_source";
   private static final String CLOUD_INFO_PROCESSOR_NAME = 
"cloud_info_processor_name";
   private static final String CLOUD_MAX_RETRY = "cloud_max_retry";
@@ -60,6 +61,10 @@ public class HelixCloudProperty {
   // The name of the function that will fetch and parse cloud instance 
information.
   private String _cloudInfoProcessorName;
 
+  // The package for the class which contains implementation to fetch
+  // and parse cloud instance information.
+  private String _cloudInfoProcessorPackage;
+
   // Http max retry times when querying the cloud instance information from 
cloud environment.
   private int _cloudMaxRetry;
 
@@ -70,7 +75,7 @@ public class HelixCloudProperty {
   private long _cloudRequestTimeout;
 
   // Other customized properties that may be used.
-  private Properties _customizedCloudProperties = new Properties();
+  private final Properties _customizedCloudProperties = new Properties();
 
   private boolean _isCloudEventCallbackEnabled;
 
@@ -93,6 +98,7 @@ public class HelixCloudProperty {
     String cloudProviderStr = cloudConfig.getCloudProvider();
     setCloudProvider(cloudProviderStr);
     if (cloudProviderStr != null) {
+      String cloudInfoProcessorName = null;
       switch (CloudProvider.valueOf(cloudProviderStr)) {
         case AZURE:
           Properties azureProperties = new Properties();
@@ -108,6 +114,8 @@ public class HelixCloudProperty {
           LOG.info("Successfully loaded Helix Azure cloud properties: {}", 
azureProperties);
           setCloudInfoSources(
               
Collections.singletonList(azureProperties.getProperty(CLOUD_INFO_SOURCE)));
+          setCloudInfoProcessorPackage(
+              DEFAULT_CLOUD_PROCESSOR_PACKAGE_PREFIX + 
cloudProviderStr.toLowerCase());
           
setCloudInfoProcessorName(azureProperties.getProperty(CLOUD_INFO_PROCESSOR_NAME));
           
setCloudMaxRetry(Integer.valueOf(azureProperties.getProperty(CLOUD_MAX_RETRY)));
           setCloudConnectionTimeout(
@@ -116,6 +124,12 @@ public class HelixCloudProperty {
           break;
         case CUSTOMIZED:
           setCloudInfoSources(cloudConfig.getCloudInfoSources());
+          // Although it is unlikely that cloudInfoProcessorPackage is null, 
when using the CUSTOMIZED
+          // cloud provider, we will set the processor package to helix cloud 
package to preserves the
+          // backwards compatibility.
+          
setCloudInfoProcessorPackage(cloudConfig.getCloudInfoProcessorPackage() != null
+              ? cloudConfig.getCloudInfoProcessorPackage()
+              : DEFAULT_CLOUD_PROCESSOR_PACKAGE_PREFIX + 
cloudProviderStr.toLowerCase());
           setCloudInfoProcessorName(cloudConfig.getCloudInfoProcessorName());
           break;
         default:
@@ -141,10 +155,27 @@ public class HelixCloudProperty {
     return _cloudInfoSources;
   }
 
+  /**
+   * Get the package containing the CloudInfoProcessor class.
+   * @return A package.
+   */
+  public String getCloudInfoProcessorPackage() {
+    return _cloudInfoProcessorPackage;
+  }
+
   public String getCloudInfoProcessorName() {
     return _cloudInfoProcessorName;
   }
 
+  /**
+   * Get the fully qualified class name for the class which contains 
implementation to fetch
+   * and parse cloud instance information.
+   * @return A fully qualified class name.
+   */
+  public String getCloudInfoProcessorFullyQualifiedClassName() {
+    return _cloudInfoProcessorPackage + "." + _cloudInfoProcessorName;
+  }
+
   public int getCloudMaxRetry() {
     return _cloudMaxRetry;
   }
@@ -185,6 +216,14 @@ public class HelixCloudProperty {
     _cloudInfoSources = sources;
   }
 
+  /**
+   * Set the package containing the class name of the cloud info processor.
+   * @param cloudInfoProcessorPackage
+   */
+  private void setCloudInfoProcessorPackage(String cloudInfoProcessorPackage) {
+    _cloudInfoProcessorPackage = cloudInfoProcessorPackage;
+  }
+
   public void setCloudInfoProcessorName(String cloudInfoProcessorName) {
     _cloudInfoProcessorName = cloudInfoProcessorName;
   }
diff --git 
a/helix-core/src/main/java/org/apache/helix/manager/zk/ParticipantManager.java 
b/helix-core/src/main/java/org/apache/helix/manager/zk/ParticipantManager.java
index 741e5c4d8..f6fffd640 100644
--- 
a/helix-core/src/main/java/org/apache/helix/manager/zk/ParticipantManager.java
+++ 
b/helix-core/src/main/java/org/apache/helix/manager/zk/ParticipantManager.java
@@ -75,8 +75,6 @@ import org.slf4j.LoggerFactory;
  */
 public class ParticipantManager {
   private static Logger LOG = 
LoggerFactory.getLogger(ParticipantManager.class);
-  private static final String CLOUD_PROCESSOR_PATH_PREFIX = 
"org.apache.helix.cloud.";
-
   final RealmAwareZkClient _zkclient;
   final HelixManager _manager;
   final PropertyKey.Builder _keyBuilder;
@@ -238,17 +236,14 @@ public class ParticipantManager {
   }
 
   private CloudInstanceInformation getCloudInstanceInformation() {
-    String cloudInstanceInformationProcessorName =
-        
_helixManagerProperty.getHelixCloudProperty().getCloudInfoProcessorName();
     try {
-      // fetch cloud instance information for the instance
-      String cloudInstanceInformationProcessorClassName = 
CLOUD_PROCESSOR_PATH_PREFIX
-          + 
_helixManagerProperty.getHelixCloudProperty().getCloudProvider().toLowerCase() 
+ "."
-          + cloudInstanceInformationProcessorName;
-      Class processorClass = 
Class.forName(cloudInstanceInformationProcessorClassName);
+      // fetch and parse cloud instance information for the instance
+      Class processorClass = 
Class.forName(_helixManagerProperty.getHelixCloudProperty()
+          .getCloudInfoProcessorFullyQualifiedClassName());
       Constructor constructor = 
processorClass.getConstructor(HelixCloudProperty.class);
-      CloudInstanceInformationProcessor processor = 
(CloudInstanceInformationProcessor) constructor
-          .newInstance(_helixManagerProperty.getHelixCloudProperty());
+      CloudInstanceInformationProcessor processor =
+          (CloudInstanceInformationProcessor) constructor.newInstance(
+              _helixManagerProperty.getHelixCloudProperty());
       List<String> responses = processor.fetchCloudInstanceInformation();
 
       // parse cloud instance information for the participant
@@ -257,9 +252,9 @@ public class ParticipantManager {
       return cloudInstanceInformation;
     } catch (ClassNotFoundException | NoSuchMethodException | 
InstantiationException
         | IllegalAccessException | InvocationTargetException ex) {
-      throw new HelixException(
-          "Failed to create a new instance for the class: " + 
cloudInstanceInformationProcessorName,
-          ex);
+      throw new HelixException("Failed to create a new instance for the class: 
"
+          + _helixManagerProperty.getHelixCloudProperty()
+          .getCloudInfoProcessorFullyQualifiedClassName(), ex);
     }
   }
 
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
index 3119fbd24..250b49e49 100644
--- a/helix-core/src/main/java/org/apache/helix/model/CloudConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/model/CloudConfig.java
@@ -48,8 +48,9 @@ public class CloudConfig extends HelixProperty {
     // 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.
+    CLOUD_INFO_PROCESSOR_NAME, // the name of the function that processes the 
fetching and parsing of
+    // cloud information.
+    CLOUD_INFO_PROCESSOR_PACKAGE // the package of for the 
CLOUD_INFO_PROCESSOR_NAME Class
   }
 
   /* Default values */
@@ -151,6 +152,15 @@ public class CloudConfig extends HelixProperty {
     return 
_record.getSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_NAME.name());
   }
 
+  /**
+   * Get the CLOUD_INFO_PROCESSOR_PACKAGE field. This could be null
+   * if the user is using a supported cloud provider.
+   * @return CLOUD_INFO_PROCESSOR_PACKAGE field.
+   */
+  public String getCloudInfoProcessorPackage() {
+    return 
_record.getSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_PACKAGE.name());
+  }
+
   /**
    * Get the CLOUD_PROVIDER field.
    * @return CLOUD_PROVIDER field.
@@ -159,7 +169,6 @@ public class CloudConfig extends HelixProperty {
     return _record.getSimpleField(CloudConfigProperty.CLOUD_PROVIDER.name());
   }
 
-
   public static class Builder {
     private ZNRecord _record;
 
@@ -227,6 +236,18 @@ public class CloudConfig extends HelixProperty {
       return this;
     }
 
+    /**
+     * Set the CLOUD_INFO_PROCESSOR_PACKAGE field. This is primarily used when 
the user
+     * is using a customized cloud provider.
+     * @param cloudInfoProcessorPackage
+     * @return Builder
+     */
+    public Builder setCloudInfoProcessorPackageName(String 
cloudInfoProcessorPackage) {
+      
_record.setSimpleField(CloudConfigProperty.CLOUD_INFO_PROCESSOR_PACKAGE.name(),
+          cloudInfoProcessorPackage);
+      return this;
+    }
+
     public String getCloudProvider() {
       return _record.getSimpleField(CloudConfigProperty.CLOUD_PROVIDER.name());
     }
diff --git 
a/helix-core/src/test/java/org/apache/helix/integration/TestHelixCloudProperty.java
 
b/helix-core/src/test/java/org/apache/helix/integration/TestHelixCloudProperty.java
new file mode 100644
index 000000000..16314544d
--- /dev/null
+++ 
b/helix-core/src/test/java/org/apache/helix/integration/TestHelixCloudProperty.java
@@ -0,0 +1,96 @@
+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.Collections;
+
+import org.apache.helix.HelixCloudProperty;
+import org.apache.helix.cloud.constants.CloudProvider;
+import org.apache.helix.model.CloudConfig;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestHelixCloudProperty {
+  @Test
+  public void testHelixCloudPropertyAzure() {
+    CloudConfig azureCloudConfig =
+        new 
CloudConfig.Builder().setCloudEnabled(true).setCloudID("AzureTestId1")
+            .setCloudProvider(CloudProvider.AZURE).build();
+
+    HelixCloudProperty azureCloudProperty = new 
HelixCloudProperty(azureCloudConfig);
+
+    Assert.assertTrue(azureCloudProperty.getCloudEnabled());
+    Assert.assertEquals(azureCloudProperty.getCloudId(), "AzureTestId1");
+    Assert.assertEquals(azureCloudProperty.getCloudProvider(), 
CloudProvider.AZURE.name());
+    Assert.assertEquals(azureCloudProperty.getCloudInfoSources(), 
Collections.singletonList(
+        "http://169.254.169.254/metadata/instance?api-version=2019-06-04";));
+    Assert.assertEquals(azureCloudProperty.getCloudMaxRetry(), 5);
+    Assert.assertEquals(azureCloudProperty.getCloudConnectionTimeout(), 5000);
+    Assert.assertEquals(azureCloudProperty.getCloudRequestTimeout(), 5000);
+    Assert.assertEquals(azureCloudProperty.getCloudInfoProcessorPackage(),
+        "org.apache.helix.cloud.azure");
+    Assert.assertEquals(azureCloudProperty.getCloudInfoProcessorName(),
+        "AzureCloudInstanceInformationProcessor");
+    
Assert.assertEquals(azureCloudProperty.getCloudInfoProcessorFullyQualifiedClassName(),
+        "org.apache.helix.cloud.azure.AzureCloudInstanceInformationProcessor");
+  }
+
+  @Test
+  public void testHelixCloudPropertyCustomizedFullyQualified() {
+    CloudConfig customCloudConfig =
+        new 
CloudConfig.Builder().setCloudEnabled(true).setCloudProvider(CloudProvider.CUSTOMIZED)
+            .setCloudInfoProcessorPackageName("org.apache.foo.bar")
+            .setCloudInfoProcessorName("CustomCloudInstanceInfoProcessor")
+            
.setCloudInfoSources(Collections.singletonList("https://custom-cloud.com";)).build();
+
+    HelixCloudProperty customCloudProperty = new 
HelixCloudProperty(customCloudConfig);
+
+    Assert.assertTrue(customCloudProperty.getCloudEnabled());
+    Assert.assertEquals(customCloudProperty.getCloudProvider(), 
CloudProvider.CUSTOMIZED.name());
+    Assert.assertEquals(customCloudProperty.getCloudInfoSources(),
+        Collections.singletonList("https://custom-cloud.com";));
+    Assert.assertEquals(customCloudProperty.getCloudInfoProcessorPackage(), 
"org.apache.foo.bar");
+    Assert.assertEquals(customCloudProperty.getCloudInfoProcessorName(),
+        "CustomCloudInstanceInfoProcessor");
+    
Assert.assertEquals(customCloudProperty.getCloudInfoProcessorFullyQualifiedClassName(),
+        "org.apache.foo.bar.CustomCloudInstanceInfoProcessor");
+  }
+
+  @Test
+  public void testHelixCloudPropertyClassNameOnly() {
+    CloudConfig customCloudConfig =
+        new 
CloudConfig.Builder().setCloudEnabled(true).setCloudProvider(CloudProvider.CUSTOMIZED)
+            .setCloudInfoProcessorName("CustomCloudInstanceInfoProcessor")
+            
.setCloudInfoSources(Collections.singletonList("https://custom-cloud.com";)).build();
+
+    HelixCloudProperty customCloudProperty = new 
HelixCloudProperty(customCloudConfig);
+
+    Assert.assertTrue(customCloudProperty.getCloudEnabled());
+    Assert.assertEquals(customCloudProperty.getCloudProvider(), 
CloudProvider.CUSTOMIZED.name());
+    Assert.assertEquals(customCloudProperty.getCloudInfoSources(),
+        Collections.singletonList("https://custom-cloud.com";));
+    Assert.assertEquals(customCloudProperty.getCloudInfoProcessorPackage(),
+        "org.apache.helix.cloud.customized");
+    Assert.assertEquals(customCloudProperty.getCloudInfoProcessorName(),
+        "CustomCloudInstanceInfoProcessor");
+    
Assert.assertEquals(customCloudProperty.getCloudInfoProcessorFullyQualifiedClassName(),
+        "org.apache.helix.cloud.customized.CustomCloudInstanceInfoProcessor");
+  }
+}
diff --git 
a/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformation.java
 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformation.java
new file mode 100644
index 000000000..02f6bc2c0
--- /dev/null
+++ 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformation.java
@@ -0,0 +1,42 @@
+package org.apache.helix.integration.paticipant;
+
+/*
+ * 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 org.apache.helix.api.cloud.CloudInstanceInformation;
+
+/**
+ * This is a custom implementation of CloudInstanceInformation. It is used to 
test the functionality
+ * of Helix node auto-registration.
+ */
+public class CustomCloudInstanceInformation implements 
CloudInstanceInformation {
+  private final String _faultDomain;
+
+  public CustomCloudInstanceInformation(String faultDomain) {
+    _faultDomain = faultDomain;
+  }
+
+  @Override
+  public String get(String key) {
+    if (key.equals(CloudInstanceField.FAULT_DOMAIN.name())) {
+      return _faultDomain;
+    }
+    return null;
+  }
+}
diff --git 
a/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformationProcessor.java
 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformationProcessor.java
new file mode 100644
index 000000000..2db41db2e
--- /dev/null
+++ 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/CustomCloudInstanceInformationProcessor.java
@@ -0,0 +1,46 @@
+package org.apache.helix.integration.paticipant;
+
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.apache.helix.HelixCloudProperty;
+import org.apache.helix.api.cloud.CloudInstanceInformation;
+import org.apache.helix.api.cloud.CloudInstanceInformationProcessor;
+
+/**
+ * This is a custom implementation of CloudInstanceInformationProcessor.
+ * It is used to test the functionality of Helix node auto-registration.
+ */
+public class CustomCloudInstanceInformationProcessor implements 
CloudInstanceInformationProcessor<String> {
+  public CustomCloudInstanceInformationProcessor(HelixCloudProperty 
helixCloudProperty) {
+  }
+
+  @Override
+  public List<String> fetchCloudInstanceInformation() {
+    return Collections.singletonList("response");
+  }
+
+  @Override
+  public CloudInstanceInformation parseCloudInstanceInformation(List<String> 
responses) {
+    return new CustomCloudInstanceInformation("rack=A:123, host=");
+  }
+}
\ No newline at end of file
diff --git 
a/helix-core/src/test/java/org/apache/helix/integration/paticipant/TestInstanceAutoJoin.java
 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/TestInstanceAutoJoin.java
index 0dd96e0ac..5d424e227 100644
--- 
a/helix-core/src/test/java/org/apache/helix/integration/paticipant/TestInstanceAutoJoin.java
+++ 
b/helix-core/src/test/java/org/apache/helix/integration/paticipant/TestInstanceAutoJoin.java
@@ -1,5 +1,7 @@
 package org.apache.helix.integration.paticipant;
 
+import java.util.Collections;
+
 import org.apache.helix.HelixDataAccessor;
 import org.apache.helix.HelixException;
 import org.apache.helix.HelixManager;
@@ -12,8 +14,10 @@ import 
org.apache.helix.integration.manager.MockParticipantManager;
 import org.apache.helix.manager.zk.ZKHelixManager;
 import org.apache.helix.model.CloudConfig;
 import org.apache.helix.model.ConfigScope;
+import org.apache.helix.model.HelixConfigScope;
 import org.apache.helix.model.IdealState.RebalanceMode;
 import org.apache.helix.model.builder.ConfigScopeBuilder;
+import org.apache.helix.model.builder.HelixConfigScopeBuilder;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -91,8 +95,7 @@ public class TestInstanceAutoJoin extends 
ZkStandAloneCMTestBase {
     HelixManager manager = _participants[0];
     HelixDataAccessor accessor = manager.getHelixDataAccessor();
 
-    _gSetupTool.addResourceToCluster(CLUSTER_NAME, db3, 60, "OnlineOffline",
-        RebalanceMode.FULL_AUTO.name(), 
CrushEdRebalanceStrategy.class.getName());
+    _gSetupTool.addResourceToCluster(CLUSTER_NAME, db3, 60, "OnlineOffline", 
RebalanceMode.FULL_AUTO.name(), CrushEdRebalanceStrategy.class.getName());
     _gSetupTool.rebalanceStorageCluster(CLUSTER_NAME, db3, 1);
     String instance3 = "localhost_279700";
 
@@ -120,9 +123,54 @@ public class TestInstanceAutoJoin extends 
ZkStandAloneCMTestBase {
         return true;
       }, 2000));
     } catch (HelixException e) {
-      
Assert.assertNull(manager.getHelixDataAccessor().getProperty(accessor.keyBuilder().liveInstance(instance3)));
+      Assert.assertNull(manager.getHelixDataAccessor()
+          .getProperty(accessor.keyBuilder().liveInstance(instance3)));
     }
 
     autoParticipant.syncStop();
   }
+
+  /**
+   * Test auto registration with customized cloud info processor specified 
with fully qualified
+   * class name.
+   * @throws Exception
+   */
+  @Test
+  public void testAutoRegistrationCustomizedFullyQualifiedInfoProcessorPath() 
throws Exception {
+    HelixManager manager = _participants[0];
+    HelixDataAccessor accessor = manager.getHelixDataAccessor();
+    String instance4 = "localhost_279707";
+
+    // Enable cluster auto join.
+    HelixConfigScope scope =
+        new 
HelixConfigScopeBuilder(HelixConfigScope.ConfigScopeProperty.CLUSTER).forCluster(
+            CLUSTER_NAME).build();
+    manager.getConfigAccessor().set(scope, 
ZKHelixManager.ALLOW_PARTICIPANT_AUTO_JOIN, "true");
+
+    // Create CloudConfig object for CUSTOM cloud provider.
+    CloudConfig cloudConfig =
+        new 
CloudConfig.Builder().setCloudEnabled(true).setCloudProvider(CloudProvider.CUSTOMIZED)
+            
.setCloudInfoProcessorPackageName("org.apache.helix.integration.paticipant")
+            
.setCloudInfoProcessorName("CustomCloudInstanceInformationProcessor")
+            
.setCloudInfoSources(Collections.singletonList("https://cloud.com";)).build();
+
+    // Update CloudConfig to Zookeeper.
+    PropertyKey.Builder keyBuilder = accessor.keyBuilder();
+    accessor.setProperty(keyBuilder.cloudConfig(), cloudConfig);
+
+    // Create and start a new participant.
+    MockParticipantManager autoParticipant =
+        new MockParticipantManager(ZK_ADDR, CLUSTER_NAME, instance4);
+    autoParticipant.syncStart();
+
+    Assert.assertTrue(TestHelper.verify(() -> {
+      // Check that live instance is added and instance config is populated 
with correct domain.
+      return null != manager.getHelixDataAccessor()
+          .getProperty(accessor.keyBuilder().liveInstance(instance4)) && 
manager.getConfigAccessor()
+          .getInstanceConfig(CLUSTER_NAME, instance4).getDomainAsString()
+          .equals("rack=A:123, host=" + instance4);
+    }, 2000));
+
+    autoParticipant.syncStop();
+  }
 }
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
index f401d006e..bb6050614 100644
--- 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
@@ -20,16 +20,17 @@ package org.apache.helix.model.cloud;
  */
 
 import java.util.ArrayList;
+import java.util.List;
+
 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.cloud.constants.CloudProvider;
 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;
 
@@ -139,6 +140,7 @@ public class TestCloudConfig extends ZkUnitTestBase {
     builder.addCloudInfoSource("TestURL0");
     builder.addCloudInfoSource("TestURL1");
     builder.setCloudInfoProcessorName("TestProcessor");
+    builder.setCloudInfoProcessorPackageName("org.apache.foo.bar");
 
     // Check builder getter methods
     Assert.assertTrue(builder.getCloudEnabled());
@@ -167,6 +169,7 @@ public class TestCloudConfig extends ZkUnitTestBase {
     Assert.assertEquals(listUrlFromZk.get(0), "TestURL0");
     Assert.assertEquals(listUrlFromZk.get(1), "TestURL1");
     Assert.assertEquals(cloudConfigFromZk.getCloudInfoProcessorName(), 
"TestProcessor");
+    Assert.assertEquals(cloudConfigFromZk.getCloudInfoProcessorPackage(), 
"org.apache.foo.bar");
   }
 
   @Test(dependsOnMethods = "testCloudConfigBuilder")

Reply via email to