ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lpus...@apache.org
Subject ambari git commit: AMBARI-20872 Required properties for services in the blueprint are validated before the cluster provisioning is started when the cluster creation template is posted)
Date Tue, 20 Jun 2017 16:26:58 GMT
Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 0ef583699 -> 3dc1811e1


AMBARI-20872 Required properties for services in the blueprint are validated before the cluster
provisioning is started when the cluster creation template is posted)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/3dc1811e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/3dc1811e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/3dc1811e

Branch: refs/heads/branch-2.5
Commit: 3dc1811e1fb07976c0684e59b11a264244ac9e71
Parents: 0ef5836
Author: lpuskas <lpuskas@apache.org>
Authored: Tue Jun 20 15:23:11 2017 +0200
Committer: lpuskas <lpuskas@apache.org>
Committed: Tue Jun 20 18:26:15 2017 +0200

----------------------------------------------------------------------
 .../server/topology/BlueprintValidatorImpl.java |  88 ++-----
 .../server/topology/TopologyValidator.java      |   2 +-
 .../RequiredConfigPropertiesValidator.java      | 142 +++++++++++
 .../validators/TopologyValidatorFactory.java    |   3 +-
 .../server/topology/BlueprintImplTest.java      |  30 +--
 .../RequiredConfigPropertiesValidatorTest.java  | 234 +++++++++++++++++++
 6 files changed, 411 insertions(+), 88 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintValidatorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintValidatorImpl.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintValidatorImpl.java
index 45a8c5c..1aaa5ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintValidatorImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintValidatorImpl.java
@@ -19,7 +19,6 @@
 package org.apache.ambari.server.topology;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -45,6 +44,7 @@ public class BlueprintValidatorImpl implements BlueprintValidator {
     this.blueprint = blueprint;
     this.stack = blueprint.getStack();
   }
+
   @Override
   public void validateTopology() throws InvalidTopologyException {
     LOGGER.info("Validating topology for blueprint: [{}]", blueprint.getName());
@@ -53,7 +53,7 @@ public class BlueprintValidatorImpl implements BlueprintValidator {
 
     for (HostGroup group : hostGroups) {
       Map<String, Collection<DependencyInfo>> missingGroupDependencies = validateHostGroup(group);
-      if (! missingGroupDependencies.isEmpty()) {
+      if (!missingGroupDependencies.isEmpty()) {
         missingDependencies.put(group.getName(), missingGroupDependencies);
       }
     }
@@ -69,27 +69,24 @@ public class BlueprintValidatorImpl implements BlueprintValidator {
           cardinalityFailures.addAll(verifyComponentInAllHostGroups(component, autoDeploy));
         } else {
           cardinalityFailures.addAll(verifyComponentCardinalityCount(
-              component, cardinality, autoDeploy));
+            component, cardinality, autoDeploy));
         }
       }
     }
 
-    if (! missingDependencies.isEmpty() || ! cardinalityFailures.isEmpty()) {
+    if (!missingDependencies.isEmpty() || !cardinalityFailures.isEmpty()) {
       generateInvalidTopologyException(missingDependencies, cardinalityFailures);
     }
   }
 
   @Override
   public void validateRequiredProperties() throws InvalidTopologyException {
-    //todo: combine with RequiredPasswordValidator
-    Map<String, Map<String, Collection<String>>> missingProperties =
-        new HashMap<String, Map<String, Collection<String>>>();
 
     // we don't want to include default stack properties so we can't just use hostGroup full
properties
     Map<String, Map<String, String>> clusterConfigurations = blueprint.getConfiguration().getProperties();
 
     // we need to have real passwords, not references
-    if(clusterConfigurations != null) {
+    if (clusterConfigurations != null) {
       StringBuilder errorMessage = new StringBuilder();
       boolean containsSecretReferences = false;
       for (Map.Entry<String, Map<String, String>> configEntry : clusterConfigurations.entrySet())
{
@@ -100,16 +97,16 @@ public class BlueprintValidatorImpl implements BlueprintValidator {
             String propertyValue = propertyEntry.getValue();
             if (propertyValue != null) {
               if (SecretReference.isSecret(propertyValue)) {
-                errorMessage.append("  Config:" + configType + " Property:" + propertyName+"\n");
+                errorMessage.append("  Config:" + configType + " Property:" + propertyName
+ "\n");
                 containsSecretReferences = true;
               }
             }
           }
         }
       }
-      if(containsSecretReferences) {
+      if (containsSecretReferences) {
         throw new InvalidTopologyException("Secret references are not allowed in blueprints,
" +
-            "replace following properties with real passwords:\n"+errorMessage.toString());
+          "replace following properties with real passwords:\n" + errorMessage.toString());
       }
     }
 
@@ -125,80 +122,35 @@ public class BlueprintValidatorImpl implements BlueprintValidator {
         if (component.equals("MYSQL_SERVER")) {
           Map<String, String> hiveEnvConfig = clusterConfigurations.get("hive-env");
           if (hiveEnvConfig != null && !hiveEnvConfig.isEmpty() && hiveEnvConfig.get("hive_database")
!= null
-              && hiveEnvConfig.get("hive_database").startsWith("Existing")) {
+            && hiveEnvConfig.get("hive_database").startsWith("Existing")) {
             throw new InvalidTopologyException("Incorrect configuration: MYSQL_SERVER component
is available but hive" +
-                " using existing db!");
+              " using existing db!");
           }
         }
 
         if (component.equals("HIVE_METASTORE")) {
           Map<String, String> hiveEnvConfig = clusterConfigurations.get("hive-env");
-          if (hiveEnvConfig != null && !hiveEnvConfig.isEmpty() && hiveEnvConfig.get("hive_database")
!=null
-              && hiveEnvConfig.get("hive_database").equals("Existing SQL Anywhere
Database")
-              && VersionUtils.compareVersions(stack.getVersion(), "2.3.0.0") <
0
-              && stack.getName().equalsIgnoreCase("HDP")) {
+          if (hiveEnvConfig != null && !hiveEnvConfig.isEmpty() && hiveEnvConfig.get("hive_database")
!= null
+            && hiveEnvConfig.get("hive_database").equals("Existing SQL Anywhere Database")
+            && VersionUtils.compareVersions(stack.getVersion(), "2.3.0.0") < 0
+            && stack.getName().equalsIgnoreCase("HDP")) {
             throw new InvalidTopologyException("Incorrect configuration: SQL Anywhere db
is available only for stack HDP-2.3+ " +
-                "and repo version 2.3.2+!");
+              "and repo version 2.3.2+!");
           }
         }
 
         if (component.equals("OOZIE_SERVER")) {
           Map<String, String> oozieEnvConfig = clusterConfigurations.get("oozie-env");
-          if (oozieEnvConfig != null && !oozieEnvConfig.isEmpty() && oozieEnvConfig.get("oozie_database")
!=null
-              && oozieEnvConfig.get("oozie_database").equals("Existing SQL Anywhere
Database")
-              && VersionUtils.compareVersions(stack.getVersion(), "2.3.0.0") <
0
-              && stack.getName().equalsIgnoreCase("HDP")) {
+          if (oozieEnvConfig != null && !oozieEnvConfig.isEmpty() && oozieEnvConfig.get("oozie_database")
!= null
+            && oozieEnvConfig.get("oozie_database").equals("Existing SQL Anywhere
Database")
+            && VersionUtils.compareVersions(stack.getVersion(), "2.3.0.0") < 0
+            && stack.getName().equalsIgnoreCase("HDP")) {
             throw new InvalidTopologyException("Incorrect configuration: SQL Anywhere db
is available only for stack HDP-2.3+ " +
-                "and repo version 2.3.2+!");
-          }
-        }
-
-        //for now, AMBARI is not recognized as a service in Stacks
-        if (! component.equals("AMBARI_SERVER")) {
-          String serviceName = stack.getServiceForComponent(component);
-          if (processedServices.add(serviceName)) {
-            Collection<Stack.ConfigProperty> requiredServiceConfigs =
-                stack.getRequiredConfigurationProperties(serviceName);
-
-            for (Stack.ConfigProperty requiredConfig : requiredServiceConfigs) {
-              String configCategory = requiredConfig.getType();
-              String propertyName = requiredConfig.getName();
-              if (! stack.isPasswordProperty(serviceName, configCategory, propertyName))
{
-                Collection<String> typeRequirements = allRequiredProperties.get(configCategory);
-                if (typeRequirements == null) {
-                  typeRequirements = new HashSet<String>();
-                  allRequiredProperties.put(configCategory, typeRequirements);
-                }
-                typeRequirements.add(propertyName);
-              }
-            }
-          }
-        }
-      }
-      for (Map.Entry<String, Collection<String>> requiredTypeProperties : allRequiredProperties.entrySet())
{
-        String requiredCategory = requiredTypeProperties.getKey();
-        Collection<String> requiredProperties = requiredTypeProperties.getValue();
-        Collection<String> operationalTypeProps = operationalConfiguration.containsKey(requiredCategory)
?
-            operationalConfiguration.get(requiredCategory).keySet() :
-            Collections.<String>emptyList();
-
-        requiredProperties.removeAll(operationalTypeProps);
-        if (! requiredProperties.isEmpty()) {
-          String hostGroupName = hostGroup.getName();
-          Map<String, Collection<String>> hostGroupMissingProps = missingProperties.get(hostGroupName);
-          if (hostGroupMissingProps == null) {
-            hostGroupMissingProps = new HashMap<String, Collection<String>>();
-            missingProperties.put(hostGroupName, hostGroupMissingProps);
+              "and repo version 2.3.2+!");
           }
-          hostGroupMissingProps.put(requiredCategory, requiredProperties);
         }
       }
     }
-
-    if (! missingProperties.isEmpty()) {
-      throw new InvalidTopologyException("Missing required properties.  Specify a value for
these " +
-          "properties in the blueprint configuration. " + missingProperties);
-    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyValidator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyValidator.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyValidator.java
index 146b424..58e858c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyValidator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyValidator.java
@@ -22,5 +22,5 @@ package org.apache.ambari.server.topology;
  * Performs topology validation.
  */
 public interface TopologyValidator {
-  public void validate(ClusterTopology topology) throws InvalidTopologyException;
+  void validate(ClusterTopology topology) throws InvalidTopologyException;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidator.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidator.java
new file mode 100644
index 0000000..8a64669
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidator.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed 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.
+ */
+
+package org.apache.ambari.server.topology.validators;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.internal.Stack;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.HostGroup;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.apache.ambari.server.topology.TopologyValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Validates the configuration by checking the existence of required properties for the services
listed in the blueprint.
+ * Required properties are specified in the stack and are tied to config types and services.
+ *
+ * The validator ignores password properties that should never be specified in the artifacts
(blueprint / cluster creation template)
+ */
+public class RequiredConfigPropertiesValidator implements TopologyValidator {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(RequiredConfigPropertiesValidator.class);
+
+  /**
+   * Validates the configuration coming from the blueprint and cluster creation template
and ensures that all the required properties are provided.
+   *
+   * @param topology the topology instance holding the configuration for cluster provisioning
+   * @throws InvalidTopologyException when there are missing configuration types or properties
related to services in the blueprint
+   */
+  @Override
+  public void validate(ClusterTopology topology) throws InvalidTopologyException {
+
+    // collect cluster configuration
+    Map<String, Map<String, String>> clusterConfigurations = getClusterConfiguration(topology.getConfiguration(),
topology.getBlueprint().getHostGroups().values());
+
+    // collect required properties
+    Map<String, Collection<String>> requiredPropertiesByType = getRequiredProperties(topology.getBlueprint());
+
+    // find missing properties in the cluster configuration
+    Map<String, Collection<String>> missingProperties = new HashMap<>();
+
+    for (Map.Entry<String, Collection<String>> requiredPropsEntry : requiredPropertiesByType.entrySet())
{
+      String configType = requiredPropsEntry.getKey();
+      Collection<String> requiredProps = requiredPropsEntry.getValue();
+      LOGGER.debug("Checking required properties. Config type: {}, Required properties: {}",
configType, requiredProps);
+
+      if (clusterConfigurations.containsKey(configType)) {
+        Map<String, String> clusterProps = clusterConfigurations.get(configType);
+        requiredProps.removeAll(clusterProps.keySet());
+      }
+
+      if (!requiredProps.isEmpty()) {
+        LOGGER.debug("Found missing properties. Config type: {}, Missing properties: {}",
configType, requiredProps);
+        missingProperties.put(configType, requiredProps);
+      }
+    }
+
+    if (!missingProperties.isEmpty()) {
+      throw new InvalidTopologyException("Missing required properties.  Specify a value for
these " +
+        "properties in the blueprint or cluster creation template configuration. " + missingProperties);
+    }
+
+  }
+
+
+  /**
+   * Collects configuration provided in the blueprint, hostgroups and cluster creation template.
+   */
+  private Map<String, Map<String, String>> getClusterConfiguration(Configuration
topologyConfiguration, Collection<HostGroup> hostGroups) {
+
+    // get the combined configuration (bp + cct), the parent is the bp - the depth is 1 !!
+    Map<String, Map<String, String>> clusterConfigurations = topologyConfiguration.getFullProperties(1);
+
+    // add hostgroup properties
+    for (HostGroup hostGroup : hostGroups) {
+      clusterConfigurations.putAll(hostGroup.getConfiguration().getProperties());
+    }
+
+    return clusterConfigurations;
+  }
+
+
+  /**
+   * Collects required properties for services in the blueprint.
+   *
+   * @param blueprint the blueprint from the cluster topology
+   * @return a map with configuration types mapped to collections of required property names
+   */
+
+  private Map<String, Collection<String>> getRequiredProperties(Blueprint blueprint)
{
+
+    // collect required properties for services in the blueprint
+    Collection<Stack.ConfigProperty> requiredServiceProperties = new HashSet<>();
+
+    for (String bpService : blueprint.getServices()) {
+      LOGGER.debug("Collecting required properties for the service: {}", bpService);
+      requiredServiceProperties.addAll(blueprint.getStack().getRequiredConfigurationProperties(bpService));
+    }
+
+    // transform required properties to the representation of the cluster configs
+    Map<String, Collection<String>> requiredPropertiesByType = new HashMap<>();
+    for (Stack.ConfigProperty requiredProperty : requiredServiceProperties) {
+
+      if (requiredProperty.getPropertyTypes() != null && requiredProperty.getPropertyTypes().contains(PropertyInfo.PropertyType.PASSWORD))
{
+        LOGGER.debug("Skipping required property validation for password type: {}", requiredProperty.getName());
+        // skip password types
+        continue;
+      }
+
+      Collection<String> requiredPropertiesForConfigType = requiredPropertiesByType.get(requiredProperty.getType());
+      if (null == requiredPropertiesForConfigType) {
+        // there's a set of props for each config type
+        requiredPropertiesForConfigType = new HashSet<>();
+        requiredPropertiesByType.put(requiredProperty.getType(), requiredPropertiesForConfigType);
+      }
+      requiredPropertiesForConfigType.add(requiredProperty.getName());
+    }
+
+    return requiredPropertiesByType;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
index 0e77301..5a6f64e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
@@ -24,7 +24,8 @@ public class TopologyValidatorFactory {
   List<TopologyValidator> validators;
 
   public TopologyValidatorFactory() {
-    validators = ImmutableList.of(new RequiredPasswordValidator(), new HiveServiceValidator(),
new StackConfigTypeValidator());
+    validators = ImmutableList.of(new RequiredConfigPropertiesValidator(), new RequiredPasswordValidator(),
new HiveServiceValidator(),
+      new StackConfigTypeValidator());
   }
 
   public TopologyValidator createConfigurationValidatorChain() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplTest.java
index 0608697..fdbc080 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplTest.java
@@ -18,11 +18,13 @@
 
 package org.apache.ambari.server.topology;
 
-import org.apache.ambari.server.controller.internal.Stack;
-import org.apache.ambari.server.orm.entities.BlueprintEntity;
-import org.apache.ambari.server.state.SecurityType;
-import org.junit.Before;
-import org.junit.Test;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -32,9 +34,11 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
+import org.apache.ambari.server.controller.internal.Stack;
+import org.apache.ambari.server.orm.entities.BlueprintEntity;
+import org.apache.ambari.server.state.SecurityType;
+import org.junit.Before;
+import org.junit.Test;
 
 
 /**
@@ -123,16 +127,6 @@ public class BlueprintImplTest {
     assertTrue(entity.getSecurityDescriptorReference().equals("testRef"));
   }
 
-  @Test(expected = InvalidTopologyException.class)
-  public void testValidateConfigurations__basic_negative() throws Exception {
-    expect(group2.getConfiguration()).andReturn(EMPTY_CONFIGURATION).atLeastOnce();
-    replay(stack, group1, group2);
-
-    Blueprint blueprint = new BlueprintImpl("test", hostGroups, stack, configuration, null);
-    blueprint.validateRequiredProperties();
-    verify(stack, group1, group2);
-  }
-
   @Test
   public void testValidateConfigurations__hostGroupConfig() throws Exception {
     Map<String, Map<String, String>> group2Props = new HashMap<>();

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dc1811e/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidatorTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidatorTest.java
new file mode 100644
index 0000000..89c4307
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidatorTest.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed 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.
+ */
+
+package org.apache.ambari.server.topology.validators;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.internal.Stack;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.HostGroup;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.easymock.EasyMock;
+import org.easymock.EasyMockRule;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.easymock.TestSubject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class RequiredConfigPropertiesValidatorTest extends EasyMockSupport {
+
+  @Rule
+  public EasyMockRule mocks = new EasyMockRule(this);
+
+  @Mock
+  private ClusterTopology clusterTopologyMock;
+
+  @Mock
+  private Configuration topologyConfigurationMock;
+
+  @Mock
+  private Blueprint blueprintMock;
+
+  @Mock
+  private Stack stackMock;
+
+  private Map<String, Map<String, String>> topologyConfigurationMap = new HashMap<>();
+  private Collection<String> bpServices = new HashSet<>();
+  private Map<String, HostGroup> hostGroups = new HashMap<>();
+  private Map<String, Collection<String>> missingProps = new HashMap<>();
+
+  @TestSubject
+  private RequiredConfigPropertiesValidator testSubject = new RequiredConfigPropertiesValidator();
+
+  @Before
+  public void setup() {
+    resetAll();
+
+    EasyMock.expect(clusterTopologyMock.getConfiguration()).andReturn(topologyConfigurationMock);
+    EasyMock.expect(topologyConfigurationMock.getFullProperties(1)).andReturn(topologyConfigurationMap);
+
+    EasyMock.expect(clusterTopologyMock.getBlueprint()).andReturn(blueprintMock).anyTimes();
+    EasyMock.expect(blueprintMock.getHostGroups()).andReturn(hostGroups);
+    EasyMock.expect(blueprintMock.getServices()).andReturn(bpServices);
+    EasyMock.expect(blueprintMock.getStack()).andReturn(stackMock).anyTimes();
+  }
+
+  @Test
+  public void testShouldValidationFailWhenRequiredConfigTypesAreMissing() throws Exception
{
+
+    // GIVEN
+
+    // services in the blueprint
+    bpServices.addAll(Arrays.asList("KERBEROS", "OOZIE"));
+
+    // required properties for listed services
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("KERBEROS")).
+      andReturn(Arrays.asList(
+        new Stack.ConfigProperty("kerberos-env", "realm", "value"),
+        new Stack.ConfigProperty("kerberos-env", "kdc_type", "value"),
+        new Stack.ConfigProperty("krb5-conf", "domains", "node.dc1.consul")));
+
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("OOZIE"))
+      .andReturn(Collections.EMPTY_LIST);
+
+
+    // configuration from the blueprint / cluster creation template
+    topologyConfigurationMap.put("kerberos-env", new HashMap<String, String>());
+    topologyConfigurationMap.get("kerberos-env").put("realm", "etwas");
+    topologyConfigurationMap.get("kerberos-env").put("kdc_type", "mit-kdc");
+
+    missingProps.put("krb5-conf", Arrays.asList("domains"));
+
+    replayAll();
+
+    // WHEN
+    String expectedMsg = String.format("Missing required properties.  Specify a value for
these properties in the blueprint or cluster creation template configuration. %s", missingProps);
+    String actualMsg = "";
+    try {
+      testSubject.validate(clusterTopologyMock);
+    } catch (InvalidTopologyException e) {
+      actualMsg = e.getMessage();
+    }
+
+    // THEN
+    // Exception is thrown, as the krb5-conf typee is not provideds
+    Assert.assertEquals("The exception message should be the expected one", expectedMsg,
actualMsg);
+  }
+
+  @Test
+  public void testShouldValidationFailWhenNotAllRequiredPropertiesAreProvided() throws Exception
{
+    // GIVEN
+
+    // services in the blueprint
+    bpServices.addAll(Arrays.asList("KERBEROS", "OOZIE"));
+
+    // required properties for listed services
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("KERBEROS")).
+      andReturn(Arrays.asList(
+        new Stack.ConfigProperty("kerberos-env", "realm", "value"),
+        new Stack.ConfigProperty("kerberos-env", "kdc_type", "value"), // this is missing!
+        new Stack.ConfigProperty("krb5-conf", "domains", "smthg")));
+
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("OOZIE"))
+      .andReturn(Collections.EMPTY_LIST);
+
+
+    // configuration from the blueprint / cluster creation template
+    topologyConfigurationMap.put("kerberos-env", new HashMap<String, String>());
+    topologyConfigurationMap.get("kerberos-env").put("realm", "etwas");
+
+    topologyConfigurationMap.put("krb5-conf", new HashMap<String, String>());
+    topologyConfigurationMap.get("krb5-conf").put("domains", "smthg");
+
+    missingProps.put("kerberos-env", Arrays.asList("kdc_type"));
+
+    replayAll();
+
+    // WHEN
+    String expectedMsg = String.format("Missing required properties.  Specify a value for
these properties in the blueprint or cluster creation template configuration. %s", missingProps);
+    String actualMsg = "";
+    try {
+      testSubject.validate(clusterTopologyMock);
+    } catch (InvalidTopologyException e) {
+      actualMsg = e.getMessage();
+    }
+
+    // THEN
+    // Exception is thrown, as the krb5-conf typee is not provideds
+    Assert.assertEquals("The exception message should be the expected one", expectedMsg,
actualMsg);
+
+  }
+
+  @Test
+  public void testShouldValidationPassWhenAllRequiredPropertiesAreProvided() throws Exception
{
+    // GIVEN
+
+    // services in the blueprint
+    bpServices.addAll(Arrays.asList("KERBEROS"));
+
+    // configuration from the blueprint / cluster creation template
+    topologyConfigurationMap.put("kerberos-env", new HashMap<String, String>());
+    topologyConfigurationMap.get("kerberos-env").put("realm", "etwas");
+    topologyConfigurationMap.get("kerberos-env").put("kdc_type", "value");
+
+    topologyConfigurationMap.put("krb5-conf", new HashMap<String, String>());
+    topologyConfigurationMap.get("krb5-conf").put("domains", "smthg");
+
+    // required properties for listed services
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("KERBEROS")).
+      andReturn(Arrays.asList(
+        new Stack.ConfigProperty("kerberos-env", "realm", "value"),
+        new Stack.ConfigProperty("kerberos-env", "kdc_type", "value"),
+        new Stack.ConfigProperty("krb5-conf", "domains", "smthg")));
+
+    replayAll();
+
+    // WHEN
+
+    testSubject.validate(clusterTopologyMock);
+
+
+    // THEN
+    // no exceptions thrown
+
+  }
+
+  @Test
+  public void testShouldValidationPassWhenPasswordTypeRequiredPropertiesAreMissing() throws
Exception {
+    // GIVEN
+
+    // services in the blueprint
+    bpServices.addAll(Arrays.asList("KNOX"));
+
+    Set<PropertyInfo.PropertyType> passwordTypeSet = new HashSet<>();
+    passwordTypeSet.add(PropertyInfo.PropertyType.PASSWORD);
+
+    Stack.ConfigProperty passworProp = new Stack.ConfigProperty("knox-env", "knox_master_secret",
"pwd");
+    passworProp.setPropertyTypes(passwordTypeSet);
+
+    // required properties for listed services
+    EasyMock.expect(stackMock.getRequiredConfigurationProperties("KNOX")).
+      andReturn(Arrays.asList(
+        passworProp, // this should be ignored
+        new Stack.ConfigProperty("knox-env", "knox_user", "kuser")
+      ));
+
+
+    // configuration from the blueprint / cluster creation template
+    topologyConfigurationMap.put("knox-env", new HashMap<String, String>());
+    topologyConfigurationMap.get("knox-env").put("knox_user", "etwas");
+
+    replayAll();
+
+    // WHEN
+    testSubject.validate(clusterTopologyMock);
+
+    // THEN
+    // validation passes
+
+  }
+}
\ No newline at end of file


Mime
View raw message