You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by js...@apache.org on 2014/05/07 16:17:00 UTC

git commit: AMBARI-5690. Add blueprint validation for required properties.

Repository: ambari
Updated Branches:
  refs/heads/branch-1.6.0 369e0d369 -> 4651447c2


AMBARI-5690.  Add blueprint validation for required properties.


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

Branch: refs/heads/branch-1.6.0
Commit: 4651447c2d74e30b26445bc57b84a4f65a74d2b8
Parents: 369e0d3
Author: John Speidel <js...@hortonworks.com>
Authored: Tue May 6 16:35:43 2014 -0400
Committer: John Speidel <js...@hortonworks.com>
Committed: Wed May 7 09:56:01 2014 -0400

----------------------------------------------------------------------
 .../server/api/services/AmbariMetaInfo.java     |  53 +-
 .../server/api/util/StackExtensionHelper.java   |  18 -
 .../ambari/server/controller/AmbariServer.java  |   2 +-
 .../internal/BlueprintResourceProvider.java     |  26 +-
 .../internal/ClusterResourceProvider.java       | 161 +++++-
 .../server/orm/entities/BlueprintEntity.java    | 110 ++++
 .../internal/BlueprintResourceProviderTest.java |  20 +-
 .../internal/ClusterResourceProviderTest.java   | 569 ++++++++++++++++++-
 .../orm/entities/BlueprintEntityTest.java       | 188 ++++++
 9 files changed, 1096 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 1d2e5cc..e896b52 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -126,8 +127,8 @@ public class AmbariMetaInfo {
   @Inject
   private MetainfoDAO metainfoDAO;
   // Required properties by stack version
-  private final Map<StackId, Map<String, PropertyInfo>> requiredProperties =
-    new HashMap<StackId, Map<String, PropertyInfo>>();
+  private final Map<StackId, Map<String, Map<String, PropertyInfo>>> requiredProperties =
+    new HashMap<StackId, Map<String, Map<String, PropertyInfo>>>();
 
   /**
    * Ambari Meta Info Object
@@ -814,13 +815,16 @@ public class AmbariMetaInfo {
       List<ServiceInfo> services = stackExtensionHelper.getAllApplicableServices(stack);
       stack.setServices(services);
 
+      Map<String, Map<String, PropertyInfo>> stackRequiredProps = new HashMap<String, Map<String, PropertyInfo>>();
+      requiredProperties.put(new StackId(stack.getName(), stack.getVersion()), stackRequiredProps);
+      for (ServiceInfo service : services) {
+        // Set required config properties
+        stackRequiredProps.put(service.getName(), getAllRequiredProperties(service));
+      }
+
       // Resolve hooks folder
       String stackHooksToUse = stackExtensionHelper.resolveHooksFolder(stack);
       stack.setStackHooksFolder(stackHooksToUse);
-
-      // Set required config properties
-      requiredProperties.put(new StackId(stack.getName(), stack.getVersion()),
-        stackExtensionHelper.getAllRequiredPropertiesForStack(stack));
     }
 
     es.invokeAll(lookupList);
@@ -830,12 +834,22 @@ public class AmbariMetaInfo {
 
   /**
    * Get properties with require_input attribute set to true.
-   * @param stackName Name of the stack, e.g.: HDP
-   * @param stackVersion Version of the stack
-   * @return Map of config type to Properties
+   *
+   * @param stackName     name of the stack, e.g.: HDP
+   * @param stackVersion  version of the stack
+   * @return Map of property name to PropertyInfo
    */
-  public Map<String, PropertyInfo> getRequiredPropertiesForStack(String stackName, String stackVersion) {
-    return requiredProperties.get(new StackId(stackName, stackVersion));
+  public Map<String, PropertyInfo> getRequiredProperties(String stackName, String stackVersion, String service) {
+
+    Map<String, Map<String, PropertyInfo>> requiredStackProps =
+        requiredProperties.get(new StackId(stackName, stackVersion));
+
+    if (requiredStackProps != null) {
+      Map<String, PropertyInfo> requiredServiceProperties = requiredStackProps.get(service);
+      return requiredServiceProperties == null ? Collections.<String, PropertyInfo>emptyMap() :
+                                                 requiredServiceProperties;
+    }
+    return Collections.emptyMap();
   }
 
   public String getServerVersion() {
@@ -1001,4 +1015,21 @@ public class AmbariMetaInfo {
 	  return null;
   }
 
+  /**
+   * Get all required properties for the given service.
+   *
+   * @param service  associated service
+   * @return map of property name to PropertyInfo containing all required properties for service
+   */
+  private Map<String, PropertyInfo> getAllRequiredProperties(ServiceInfo service) {
+    Map<String, PropertyInfo> requiredProperties = new HashMap<String, PropertyInfo>();
+    List<PropertyInfo> properties = service.getProperties();
+    for (PropertyInfo propertyInfo : properties) {
+      if (propertyInfo.isRequireInput()) {
+        requiredProperties.put(propertyInfo.getName(), propertyInfo);
+      }
+    }
+    return requiredProperties;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
index 89afb14..18e8659 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
@@ -631,24 +631,6 @@ public class StackExtensionHelper {
       }
     }
   }
-
-  /**
-   * Get all properties with require-input attribute set to true.
-   * @param stackInfo StackInfo object.
-   */
-  public Map<String, PropertyInfo> getAllRequiredPropertiesForStack(StackInfo stackInfo) {
-    Map<String, PropertyInfo> requiredProperties = new HashMap<String, PropertyInfo>();
-    for (ServiceInfo serviceInfo : stackInfo.getServices()) {
-      List<PropertyInfo> properties = serviceInfo.getProperties();
-      for (PropertyInfo propertyInfo : properties) {
-        if (propertyInfo.isRequireInput()) {
-          requiredProperties.put(propertyInfo.getName(), propertyInfo);
-        }
-      }
-    }
-    return requiredProperties;
-  }
-
   
   public static <T> T unmarshal(Class<T> clz, File file) throws JAXBException {
     Unmarshaller u = _jaxbContexts.get(clz).createUnmarshaller();

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 6c072db..12c92a9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -512,7 +512,7 @@ public class AmbariServer {
     BlueprintResourceProvider.init(injector.getInstance(BlueprintDAO.class),
         injector.getInstance(Gson.class), ambariMetaInfo);
     StackDependencyResourceProvider.init(ambariMetaInfo);
-    ClusterResourceProvider.injectBlueprintDAO(injector.getInstance(BlueprintDAO.class));
+    ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo);
     ViewRegistry.init(injector.getInstance(ViewDAO.class), injector.getInstance(ViewInstanceDAO.class));
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
index 353b58f..003590f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
@@ -42,6 +42,7 @@ import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupEntity;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.PropertyInfo;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -53,6 +54,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+
 /**
  * Resource Provider for Blueprint resources.
  */
@@ -342,8 +344,8 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
     createHostGroupEntities(blueprint,
         (HashSet<HashMap<String, Object>>) properties.get(HOST_GROUP_PROPERTY_ID));
 
-    createBlueprintConfigEntities((Collection<Map<String,
-        String>>) properties.get(CONFIGURATION_PROPERTY_ID), blueprint);
+    createBlueprintConfigEntities((Collection<Map<String, String>>)
+        properties.get(CONFIGURATION_PROPERTY_ID), blueprint);
 
     return blueprint;
   }
@@ -554,8 +556,8 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
    * @param configuration  property map
    * @param configEntity   config entity to populate
    */
-  private void  populateConfigurationEntity(String blueprintName, Map<String, String> configuration,
-                                            BlueprintConfiguration configEntity) {
+  private void populateConfigurationEntity(String blueprintName, Map<String, String> configuration,
+                                           BlueprintConfiguration configEntity) {
 
     configEntity.setBlueprintName(blueprintName);
     Map<String, String> configData = new HashMap<String, String>();
@@ -585,15 +587,23 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
       public Void invoke() throws AmbariException {
         BlueprintEntity blueprint = toBlueprintEntity(properties);
 
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Creating Blueprint, name=" + blueprint.getBlueprintName());
-        }
-
         if (dao.findByName(blueprint.getBlueprintName()) != null) {
           throw new DuplicateResourceException(
               "Attempted to create a Blueprint which already exists, blueprint_name=" +
               blueprint.getBlueprintName());
         }
+
+        Map<String, Map<String, Collection<String>>> missingProperties = blueprint.validateConfigurations(
+            stackInfo, PropertyInfo.PropertyType.DEFAULT);
+
+        if (! missingProperties.isEmpty()) {
+          throw new IllegalArgumentException("Required configurations are missing from the specified host groups: " +
+                                             missingProperties);
+        }
+
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Creating Blueprint, name=" + blueprint.getBlueprintName());
+        }
         dao.create(blueprint);
         return null;
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
index e884e97..f459f3c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 import com.google.gson.Gson;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ClusterRequest;
@@ -52,11 +53,14 @@ import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupEntity;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigImpl;
+import org.apache.ambari.server.state.PropertyInfo;
+
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -84,6 +88,11 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   private static BlueprintDAO blueprintDAO;
 
   /**
+   * Stack related information.
+   */
+  private static AmbariMetaInfo stackInfo;
+
+  /**
    * Maps properties to updaters which update the property when provisioning a cluster via a blueprint
    */
   private Map<String, PropertyUpdater> propertyUpdaters =
@@ -114,12 +123,13 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * Inject the blueprint data access object which is used to obtain blueprint entities
+   * Inject the blueprint data access object which is used to obtain blueprint entities.
    *
    * @param dao  blueprint data access object
    */
-  public static void injectBlueprintDAO(BlueprintDAO dao) {
+  public static void init(BlueprintDAO dao, AmbariMetaInfo metaInfo) {
     blueprintDAO = dao;
+    stackInfo    = metaInfo;
   }
 
 
@@ -247,6 +257,8 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
     // extract to own method
     baseUnsupported.remove("blueprint");
     baseUnsupported.remove("host_groups");
+    baseUnsupported.remove("default_password");
+    baseUnsupported.remove("configurations");
 
     return checkConfigPropertyIds(baseUnsupported, "Clusters");
   }
@@ -316,7 +328,9 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
 
     Map<String, HostGroup> blueprintHostGroups = parseBlueprintHostGroups(blueprint, stack);
     applyRequestInfoToHostGroups(properties, blueprintHostGroups);
-    processConfigurations(processBlueprintConfigurations(blueprint), stack, blueprintHostGroups);
+    processConfigurations(processBlueprintConfigurations(blueprint, (Collection<Map<String, String>>)
+        properties.get("configurations")), stack, blueprintHostGroups);
+    validatePasswordProperties(blueprint, blueprintHostGroups, (String) properties.get("default_password"));
 
     String clusterName = (String) properties.get(CLUSTER_NAME_PROPERTY_ID);
     createClusterResource(buildClusterResourceProperties(stack, clusterName));
@@ -335,6 +349,131 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
+   * Validate that all required password properties have been set or that 'default_password' is specified.
+   *
+   * @param blueprint        associated blueprint entity
+   * @param hostGroups       host groups in blueprint
+   * @param defaultPassword  specified default password, may be null
+   *
+   * @throws IllegalArgumentException if required password properties are missing and no
+   *                                  default is specified via 'default_password'
+   */
+  private void validatePasswordProperties(BlueprintEntity blueprint, Map<String, HostGroup> hostGroups,
+                                          String defaultPassword) {
+
+    Map<String, Map<String, Collection<String>>> missingPasswords = blueprint.validateConfigurations(
+        stackInfo, PropertyInfo.PropertyType.PASSWORD);
+
+    Iterator<Map.Entry<String, Map<String, Collection<String>>>> iter;
+    for(iter = missingPasswords.entrySet().iterator(); iter.hasNext(); ) {
+      Map.Entry<String, Map<String, Collection<String>>> entry = iter.next();
+      Map<String, Collection<String>> missingProps = entry.getValue();
+      Iterator<Map.Entry<String, Collection<String>>> propIter;
+      for (propIter = missingProps.entrySet().iterator(); propIter.hasNext(); ) {
+        Map.Entry<String, Collection<String>> propEntry = propIter.next();
+        String configType = propEntry.getKey();
+        Collection<String> propertySet = propEntry.getValue();
+
+        for (String property : propertySet) {
+          if (setDefaultPassword(defaultPassword, configType, property)) {
+            propIter.remove();
+          } else if (isPropertyInConfiguration(mapClusterConfigurations.get(configType), property)){
+              propIter.remove();
+          } else {
+            HostGroup hostgroup = hostGroups.get(entry.getKey());
+            if (hostgroup != null) {
+              if (isPropertyInConfiguration(hostgroup.getConfigurations().get(configType), property)) {
+                propIter.remove();
+              }
+            }
+          }
+        }
+      }
+      if (entry.getValue().isEmpty()) {
+        iter.remove();
+      }
+    }
+
+    if (! missingPasswords.isEmpty()) {
+      throw new IllegalArgumentException("Missing required password properties.  Specify a value for these " +
+          "properties in the cluster or host group configurations or include 'default_password' field in request. " +
+          missingPasswords);
+    }
+  }
+
+  /**
+   * Attempt to set the default password in cluster configuration for missing password property.
+   *
+   * @param defaultPassword  default password specified in request, may be null
+   * @param configType       configuration type
+   * @param property         password property name
+   *
+   * @return true if password was set, otherwise false.  Currently the password will always be set
+   *         unless it is null
+   */
+  private boolean setDefaultPassword(String defaultPassword, String configType, String property) {
+    boolean setDefaultPassword = false;
+    Map<String, String> typeProps = mapClusterConfigurations.get(configType);
+    if (defaultPassword != null && ! defaultPassword.trim().isEmpty()) {
+      // set default password in cluster config
+      if (typeProps == null) {
+        typeProps = new HashMap<String, String>();
+        mapClusterConfigurations.put(configType, typeProps);
+      }
+      typeProps.put(property, defaultPassword);
+      setDefaultPassword = true;
+    }
+    return setDefaultPassword;
+  }
+
+  /**
+   * Determine if a specific property is in a configuration.
+   *
+   * @param props     property map to check
+   * @param property  property to check for
+   *
+   * @return true if the property is contained in the configuration, otherwise false
+   */
+  private boolean isPropertyInConfiguration(Map<String, String> props, String property) {
+    boolean foundProperty = false;
+    if (props != null) {
+      String val = props.get(property);
+      foundProperty = (val != null && ! val.trim().isEmpty());
+    }
+    return foundProperty;
+  }
+
+  /**
+   * Override existing properties or add new.
+   *
+   * @param existingProperties  property overrides
+   * @param configOverrides     current property values
+   */
+  private void overrideExistingProperties(Map<String, Map<String, String>> existingProperties,
+                                          Collection<Map<String, String>> configOverrides) {
+    if (configOverrides != null) {
+      for (Map<String, String> properties : configOverrides) {
+        String category = null;
+        int propertyOffset = -1;
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+          String absolutePropName = entry.getKey();
+          if (category == null) {
+            propertyOffset =  absolutePropName.indexOf('/');
+            category = absolutePropName.substring(0, propertyOffset);
+          }
+          Map<String, String> existingCategoryProperties = existingProperties.get(category);
+          if (existingCategoryProperties == null) {
+            existingCategoryProperties = new HashMap<String, String>();
+            existingProperties.put(category, existingCategoryProperties);
+          }
+          //override existing property or add new
+          existingCategoryProperties.put(absolutePropName.substring(propertyOffset + 1), entry.getValue());
+        }
+      }
+    }
+  }
+
+  /**
    * Obtain a blueprint entity based on name.
    *
    * @param blueprintName  name of blueprint to obtain
@@ -534,8 +673,8 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
    *
    * @throws IllegalArgumentException a host-group in the request doesn't match a host-group in the blueprint
    */
-  private void applyRequestInfoToHostGroups(Map<String, Object> properties, Map<String,
-                                            HostGroup> blueprintHostGroups)
+  private void applyRequestInfoToHostGroups(Map<String, Object> properties,
+                                            Map<String, HostGroup> blueprintHostGroups)
                                             throws IllegalArgumentException {
 
     @SuppressWarnings("unchecked")
@@ -548,7 +687,7 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
       HostGroup hostGroup = blueprintHostGroups.get(name);
 
       if (hostGroup == null) {
-        throw new IllegalArgumentException("Invalid host-group specified: " + name +
+        throw new IllegalArgumentException("Invalid host_group specified: " + name +
           ".  All request host groups must have a corresponding host group in the specified blueprint");
       }
 
@@ -559,6 +698,10 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
         //add host information to host group
         hostGroup.addHostInfo(mapHostProperties.get("fqdn"));
       }
+      Map<String, Map<String, String>> existingConfigurations = hostGroup.getConfigurations();
+      overrideExistingProperties(existingConfigurations, (Collection<Map<String, String>>)
+          hostGroupProperties.get("configurations"));
+
     }
     validateHostMappings(blueprintHostGroups);
   }
@@ -648,14 +791,18 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
    *
    * @return configuration properties contained within in blueprint
    */
-  private Map<String, Map<String, String>> processBlueprintConfigurations(BlueprintEntity blueprint) {
+  private Map<String, Map<String, String>> processBlueprintConfigurations(BlueprintEntity blueprint,
+                                                                          Collection<Map<String, String>> configOverrides) {
     Map<String, Map<String, String>> mapConfigurations = new HashMap<String, Map<String, String>>();
     Collection<BlueprintConfigEntity> configs = blueprint.getConfigurations();
     Gson jsonSerializer = new Gson();
+
     for (BlueprintConfigEntity config : configs) {
       mapConfigurations.put(config.getType(), jsonSerializer.<Map<String, String>> fromJson(
           config.getConfigData(), Map.class));
     }
+    overrideExistingProperties(mapConfigurations, configOverrides);
+
     return mapConfigurations;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintEntity.java
index b02c723..cd764ec 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintEntity.java
@@ -18,6 +18,11 @@
 
 package org.apache.ambari.server.orm.entities;
 
+import com.google.gson.Gson;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.state.PropertyInfo;
+
 import javax.persistence.Basic;
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
@@ -26,7 +31,12 @@ import javax.persistence.Id;
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
+import javax.persistence.Transient;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
 
 /**
  * Entity representing a Blueprint.
@@ -56,6 +66,9 @@ public class BlueprintEntity {
   @OneToMany(cascade = CascadeType.ALL, mappedBy = "blueprint")
   private Collection<BlueprintConfigEntity> configurations;
 
+  @Transient
+  private Gson jsonSerializer = new Gson();
+
 
   /**
    * Get the blueprint name.
@@ -146,4 +159,101 @@ public class BlueprintEntity {
   public void setConfigurations(Collection<BlueprintConfigEntity> configurations) {
     this.configurations = configurations;
   }
+
+  /**
+   * Validate all configurations.  Validation is done on the operational configuration of each
+   * host group.  An operational configuration is achieved by overlaying host group configuration
+   * on top of cluster configuration which overlays the default stack configurations.
+   *
+   * @param stackInfo  stack information
+   * @param type       type of required property to check (PASSWORD|DEFAULT)
+   * @return map of required properties which are missing.  Empty map if none are missing.
+   *
+   * @throws IllegalArgumentException if blueprint contains invalid information
+   */
+  public Map<String, Map<String, Collection<String>>> validateConfigurations(
+      AmbariMetaInfo stackInfo, PropertyInfo.PropertyType type) {
+
+    String stackName = getStackName();
+    String stackVersion = getStackVersion();
+
+    Map<String, Map<String, Collection<String>>> missingProperties =
+        new HashMap<String, Map<String, Collection<String>>>();
+    Map<String, Map<String, String>> clusterConfigurations = getConfigurationAsMap(getConfigurations());
+
+    for (HostGroupEntity hostGroup : getHostGroups()) {
+      Collection<String> processedServices = new HashSet<String>();
+      Map<String, Collection<String>> allRequiredProperties = new HashMap<String, Collection<String>>();
+      Map<String, Map<String, String>> operationalConfiguration =
+          new HashMap<String, Map<String, String>>(clusterConfigurations);
+
+      operationalConfiguration.putAll(getConfigurationAsMap(hostGroup.getConfigurations()));
+      for (HostGroupComponentEntity component : hostGroup.getComponents()) {
+        //for now, AMBARI is not recognized as a service in Stacks
+        if (! component.getName().equals("AMBARI_SERVER")) {
+          String service;
+          try {
+            service = stackInfo.getComponentToService(stackName, stackVersion, component.getName());
+          } catch (AmbariException e) {
+            throw new IllegalArgumentException("Unable to determine the service associated with the" +
+                " component: " + component.getName());
+          }
+          if (processedServices.add(service)) {
+            Map<String, PropertyInfo> serviceRequirements = stackInfo.getRequiredProperties(
+                stackName, stackVersion, service);
+
+            for (PropertyInfo propertyInfo : serviceRequirements.values()) {
+              if (propertyInfo.getType() == type) {
+                String configCategory = propertyInfo.getFilename();
+                if (configCategory.endsWith(".xml")) {
+                  configCategory = configCategory.substring(0, configCategory.indexOf(".xml"));
+                }
+                Collection<String> typeRequirements = allRequiredProperties.get(configCategory);
+                if (typeRequirements == null) {
+                  typeRequirements = new HashSet<String>();
+                  allRequiredProperties.put(configCategory, typeRequirements);
+                }
+                typeRequirements.add(propertyInfo.getName());
+              }
+            }
+          }
+        }
+      }
+      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()) {
+          Map<String, Collection<String>> hostGroupMissingProps = new HashMap<String, Collection<String>>();
+          hostGroupMissingProps.put(requiredCategory, requiredProperties);
+          missingProperties.put(hostGroup.getName(), hostGroupMissingProps);
+        }
+      }
+    }
+    return missingProperties;
+  }
+
+  /**
+   * Obtain configuration as a map of config type to corresponding properties.
+   *
+   * @param configurations  configuration to include in map
+   *
+   * @return map of config type to map of properties
+   */
+  private Map<String, Map<String, String>> getConfigurationAsMap(
+      Collection<? extends BlueprintConfiguration> configurations) {
+
+    Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
+    for (BlueprintConfiguration config : configurations) {
+      String type = config.getType();
+      Map<String, String> typeProperties = jsonSerializer.<Map<String, String>>fromJson(
+          config.getConfigData(), Map.class);
+      properties.put(type, typeProperties);
+    }
+    return properties;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
index f046b00..b611551 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
@@ -83,7 +83,7 @@ public class BlueprintResourceProviderTest {
 
   private final static BlueprintDAO dao = createStrictMock(BlueprintDAO.class);
   private final static Gson gson = new Gson();
-  private final static AmbariMetaInfo metaInfo = createStrictMock(AmbariMetaInfo.class);
+  private final static AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
 
   @BeforeClass
   public static void initClass() {
@@ -125,6 +125,12 @@ public class BlueprintResourceProviderTest {
     expect(metaInfo.getServices("test-stack-name", "test-stack-version")).andReturn(services).anyTimes();
     expect(metaInfo.getComponentsByService("test-stack-name", "test-stack-version", "test-service")).
         andReturn(serviceComponents).anyTimes();
+    expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component1")).
+        andReturn("test-service").anyTimes();
+    expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component2")).
+        andReturn("test-service").anyTimes();
+    expect(metaInfo.getRequiredProperties("test-stack-name", "test-stack-version", "test-service")).andReturn(
+        Collections.<String, org.apache.ambari.server.state.PropertyInfo>emptyMap()).anyTimes();
     dao.create(capture(entityCapture));
 
     replay(dao, metaInfo, request);
@@ -177,6 +183,12 @@ public class BlueprintResourceProviderTest {
     expect(metaInfo.getServices("test-stack-name", "test-stack-version")).andReturn(services).anyTimes();
     expect(metaInfo.getComponentsByService("test-stack-name", "test-stack-version", "test-service")).
         andReturn(serviceComponents).anyTimes();
+    expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component1")).
+        andReturn("test-service").anyTimes();
+    expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component2")).
+        andReturn("test-service").anyTimes();
+    expect(metaInfo.getRequiredProperties("test-stack-name", "test-stack-version", "test-service")).andReturn(
+        Collections.<String, org.apache.ambari.server.state.PropertyInfo>emptyMap()).anyTimes();
     dao.create(capture(entityCapture));
 
     replay(dao, metaInfo, request);
@@ -500,7 +512,6 @@ public class BlueprintResourceProviderTest {
         BlueprintResourceProvider.HOST_GROUP_PROPERTY_ID)).iterator().next().get("components")).
         iterator().next().put("name", "AMBARI_SERVER");
 
-
     Capture<BlueprintEntity> entityCapture = new Capture<BlueprintEntity>();
 
     // set expectations
@@ -509,6 +520,11 @@ public class BlueprintResourceProviderTest {
     expect(metaInfo.getServices("test-stack-name", "test-stack-version")).andReturn(services).anyTimes();
     expect(metaInfo.getComponentsByService("test-stack-name", "test-stack-version", "test-service")).
         andReturn(serviceComponents).anyTimes();
+    expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component1")).
+        andReturn("test-service").anyTimes();
+    expect(metaInfo.getRequiredProperties("test-stack-name", "test-stack-version", "test-service")).andReturn(
+        Collections.<String, org.apache.ambari.server.state.PropertyInfo>emptyMap()).anyTimes();
+
     dao.create(capture(entityCapture));
 
     replay(dao, metaInfo, request);

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
index fe5734a..e644b08 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.controller.internal;
 
 import com.google.gson.Gson;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.PersistKeyValueImpl;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
 import org.apache.ambari.server.controller.AmbariManagementController;
@@ -47,6 +48,7 @@ import org.apache.ambari.server.orm.entities.HostGroupComponentEntity;
 import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupEntity;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.junit.Assert;
@@ -156,6 +158,7 @@ public class ClusterResourceProviderTest {
     String clusterName = "c1";
 
     BlueprintDAO blueprintDAO = createStrictMock(BlueprintDAO.class);
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
     AmbariManagementController managementController = createStrictMock(AmbariManagementController.class);
     Request request = createNiceMock(Request.class);
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
@@ -269,6 +272,8 @@ public class ClusterResourceProviderTest {
     expect(blueprint.getStackName()).andReturn(stackName);
     expect(blueprint.getStackVersion()).andReturn(stackVersion);
     expect(blueprint.getConfigurations()).andReturn(Collections.<BlueprintConfigEntity>singletonList(blueprintConfig));
+    expect(blueprint.validateConfigurations(metaInfo, PropertyInfo.PropertyType.PASSWORD)).andReturn(
+        Collections.<String, Map<String, Collection<String>>>emptyMap());
 
     expect(managementController.getStackServices(capture(stackServiceRequestCapture))).andReturn(stackServiceResponses);
     expect(stackServiceResponse1.getServiceName()).andReturn("service1");
@@ -345,10 +350,10 @@ public class ClusterResourceProviderTest {
            stackConfigurationResponse1, stackConfigurationResponse2, stackConfigurationResponse3, stackConfigurationResponse4,
            blueprintConfig, hostGroup, hostGroupComponent1, hostGroupComponent2, hostGroupComponent3, hostGroupConfig,
            serviceResourceProvider, componentResourceProvider, hostResourceProvider, hostComponentResourceProvider,
-           configGroupResourceProvider, persistKeyValue);
+           configGroupResourceProvider, persistKeyValue, metaInfo);
 
     // test
-    ClusterResourceProvider.injectBlueprintDAO(blueprintDAO);
+    ClusterResourceProvider.init(blueprintDAO, metaInfo);
     PersistKeyValueService.init(persistKeyValue);
     ResourceProvider provider = new TestClusterResourceProvider(
         managementController, serviceResourceProvider, componentResourceProvider,
@@ -500,6 +505,561 @@ public class ClusterResourceProviderTest {
   }
 
   @Test
+  public void testCreateResource_blueprint__missingPasswords() throws Exception {
+    String blueprintName = "test-blueprint";
+    String stackName = "test";
+    String stackVersion = "1.23";
+    String clusterName = "c1";
+
+    BlueprintDAO blueprintDAO = createStrictMock(BlueprintDAO.class);
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+    AmbariManagementController managementController = createStrictMock(AmbariManagementController.class);
+    Request request = createNiceMock(Request.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+    BlueprintEntity blueprint = createNiceMock(BlueprintEntity.class);
+    StackServiceResponse stackServiceResponse1 = createNiceMock(StackServiceResponse.class);
+    StackServiceResponse stackServiceResponse2 = createNiceMock(StackServiceResponse.class);
+    Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>();
+
+    StackServiceComponentResponse stackServiceComponentResponse1 = createNiceMock(StackServiceComponentResponse.class);
+    StackServiceComponentResponse stackServiceComponentResponse2 = createNiceMock(StackServiceComponentResponse.class);
+    StackServiceComponentResponse stackServiceComponentResponse3 = createNiceMock(StackServiceComponentResponse.class);
+    Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture1 = new Capture<Set<StackServiceComponentRequest>>();
+    Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture2 = new Capture<Set<StackServiceComponentRequest>>();
+
+    StackConfigurationResponse stackConfigurationResponse1 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse2 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse3 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse4 = createNiceMock(StackConfigurationResponse.class);
+    Capture<Set<StackConfigurationRequest>> serviceConfigurationRequestCapture1 = new Capture<Set<StackConfigurationRequest>>();
+    Capture<Set<StackConfigurationRequest>> serviceConfigurationRequestCapture2 = new Capture<Set<StackConfigurationRequest>>();
+
+    BlueprintConfigEntity blueprintConfig = createNiceMock(BlueprintConfigEntity.class);
+
+    HostGroupEntity hostGroup = createNiceMock(HostGroupEntity.class);
+    HostGroupComponentEntity hostGroupComponent1 = createNiceMock(HostGroupComponentEntity.class);
+    HostGroupComponentEntity hostGroupComponent2 = createNiceMock(HostGroupComponentEntity.class);
+    HostGroupComponentEntity hostGroupComponent3 = createNiceMock(HostGroupComponentEntity.class);
+
+    HostGroupConfigEntity hostGroupConfig = createNiceMock(HostGroupConfigEntity.class);
+
+    ServiceResourceProvider serviceResourceProvider = createStrictMock(ServiceResourceProvider.class);
+    ResourceProvider componentResourceProvider = createStrictMock(ResourceProvider.class);
+    ResourceProvider hostResourceProvider = createStrictMock(ResourceProvider.class);
+    ResourceProvider hostComponentResourceProvider = createStrictMock(ResourceProvider.class);
+    ConfigGroupResourceProvider configGroupResourceProvider = createStrictMock(ConfigGroupResourceProvider.class);
+    PersistKeyValueImpl persistKeyValue = createNiceMock(PersistKeyValueImpl.class);
+
+    Set<StackServiceResponse> stackServiceResponses = new LinkedHashSet<StackServiceResponse>();
+    stackServiceResponses.add(stackServiceResponse1);
+    stackServiceResponses.add(stackServiceResponse2);
+
+    // service1 has 2 components
+    Set<StackServiceComponentResponse> stackServiceComponentResponses1 = new LinkedHashSet<StackServiceComponentResponse>();
+    stackServiceComponentResponses1.add(stackServiceComponentResponse1);
+    stackServiceComponentResponses1.add(stackServiceComponentResponse2);
+
+    // service2 has 1 components
+    Set<StackServiceComponentResponse> stackServiceComponentResponses2 = new LinkedHashSet<StackServiceComponentResponse>();
+    stackServiceComponentResponses2.add(stackServiceComponentResponse3);
+
+    // service1 has 1 config
+    Set<StackConfigurationResponse> stackConfigurationResponses1 = new LinkedHashSet<StackConfigurationResponse>();
+    stackConfigurationResponses1.add(stackConfigurationResponse1);
+
+    // service2 has 3 config
+    Set<StackConfigurationResponse> stackConfigurationResponses2 = new LinkedHashSet<StackConfigurationResponse>();
+    stackConfigurationResponses2.add(stackConfigurationResponse2);
+    stackConfigurationResponses2.add(stackConfigurationResponse3);
+    stackConfigurationResponses2.add(stackConfigurationResponse4);
+
+    Collection<HostGroupComponentEntity> hostGroupComponents = new LinkedHashSet<HostGroupComponentEntity>();
+    hostGroupComponents.add(hostGroupComponent1);
+    hostGroupComponents.add(hostGroupComponent2);
+    hostGroupComponents.add(hostGroupComponent3);
+
+    // request properties
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    properties.put(ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID, clusterName);
+    properties.put(ClusterResourceProvider.BLUEPRINT_PROPERTY_ID, blueprintName);
+    propertySet.add(properties);
+
+    Collection<Map<String, Object>> hostGroups = new ArrayList<Map<String, Object>>();
+    Map<String, Object> hostGroupProperties = new HashMap<String, Object>();
+    hostGroups.add(hostGroupProperties);
+    hostGroupProperties.put("name", "group1");
+    Collection<Map<String, String>> hostGroupHosts = new ArrayList<Map<String, String>>();
+    hostGroupProperties.put("hosts", hostGroupHosts);
+    Map<String, String> hostGroupHostProperties = new HashMap<String, String>();
+    hostGroupHostProperties.put("fqdn", "host.domain");
+    hostGroupHosts.add(hostGroupHostProperties);
+    properties.put("host_groups", hostGroups);
+
+    Map<String, String> mapGroupConfigProperties = new HashMap<String, String>();
+    mapGroupConfigProperties.put("myGroupProp", "awesomeValue");
+
+    // blueprint cluster configuration properties
+    Map<String, String> blueprintConfigProperties = new HashMap<String, String>();
+    blueprintConfigProperties.put("property1", "value2");
+    blueprintConfigProperties.put("new.property", "new.property.value");
+
+    Map<String, Map<String, Collection<String>>> allMissingPasswords = new HashMap<String, Map<String, Collection<String>>>();
+    Map<String, Collection<String>> missingHGPasswords = new HashMap<String, Collection<String>>();
+    Collection<String> missingPasswords = new ArrayList<String>();
+    missingPasswords.add("my.missing.password");
+    missingHGPasswords.put("core-site", missingPasswords);
+    allMissingPasswords.put("group1", missingHGPasswords);
+
+    // expectations
+    expect(request.getProperties()).andReturn(propertySet).anyTimes();
+    expect(blueprintDAO.findByName(blueprintName)).andReturn(blueprint);
+    expect(blueprint.getStackName()).andReturn(stackName);
+    expect(blueprint.getStackVersion()).andReturn(stackVersion);
+    expect(blueprint.getConfigurations()).andReturn(Collections.<BlueprintConfigEntity>singletonList(blueprintConfig));
+    expect(blueprint.validateConfigurations(metaInfo, PropertyInfo.PropertyType.PASSWORD)).andReturn(allMissingPasswords);
+
+    expect(managementController.getStackServices(capture(stackServiceRequestCapture))).andReturn(stackServiceResponses);
+    expect(stackServiceResponse1.getServiceName()).andReturn("service1");
+    expect(stackServiceResponse2.getServiceName()).andReturn("service2");
+
+    expect(managementController.getStackComponents(capture(serviceComponentRequestCapture1))).
+        andReturn(stackServiceComponentResponses1);
+    expect(stackServiceComponentResponse1.getComponentName()).andReturn("component1");
+    expect(stackServiceComponentResponse2.getComponentName()).andReturn("component2");
+
+    expect(managementController.getStackConfigurations(capture(serviceConfigurationRequestCapture1))).
+        andReturn(stackConfigurationResponses1);
+    expect(stackConfigurationResponse1.getType()).andReturn("core-site.xml");
+    expect(stackConfigurationResponse1.getPropertyName()).andReturn("property1");
+    expect(stackConfigurationResponse1.getPropertyValue()).andReturn("value1");
+
+    expect(managementController.getStackComponents(capture(serviceComponentRequestCapture2))).
+        andReturn(stackServiceComponentResponses2);
+    expect(stackServiceComponentResponse3.getComponentName()).andReturn("component3");
+
+    expect(managementController.getStackConfigurations(capture(serviceConfigurationRequestCapture2))).
+        andReturn(stackConfigurationResponses2);
+    expect(stackConfigurationResponse2.getType()).andReturn("hdfs-site.xml");
+    expect(stackConfigurationResponse2.getPropertyName()).andReturn("property2");
+    expect(stackConfigurationResponse2.getPropertyValue()).andReturn("value2");
+
+    expect(stackConfigurationResponse3.getType()).andReturn("global.xml");
+    expect(stackConfigurationResponse3.getPropertyName()).andReturn("oozie_user");
+    expect(stackConfigurationResponse3.getPropertyValue()).andReturn("oozie");
+
+    expect(stackConfigurationResponse4.getType()).andReturn("core-site.xml");
+    expect(stackConfigurationResponse4.getPropertyName()).andReturn("property3");
+    expect(stackConfigurationResponse4.getPropertyValue()).andReturn("value3");
+
+    expect(blueprintConfig.getBlueprintName()).andReturn("test-blueprint").anyTimes();
+    expect(blueprintConfig.getType()).andReturn("core-site").anyTimes();
+    expect(blueprintConfig.getConfigData()).andReturn(new Gson().toJson(blueprintConfigProperties));
+
+    expect(blueprint.getHostGroups()).andReturn(Collections.singleton(hostGroup)).anyTimes();
+    expect(hostGroup.getName()).andReturn("group1").anyTimes();
+    expect(hostGroup.getComponents()).andReturn(hostGroupComponents).anyTimes();
+    expect(hostGroupComponent1.getName()).andReturn("component1").anyTimes();
+    expect(hostGroupComponent2.getName()).andReturn("component2").anyTimes();
+    expect(hostGroupComponent3.getName()).andReturn("component3").anyTimes();
+    expect(hostGroup.getConfigurations()).andReturn(
+        Collections.<HostGroupConfigEntity>singleton(hostGroupConfig)).anyTimes();
+
+    expect(hostGroupConfig.getType()).andReturn("core-site").anyTimes();
+    expect(hostGroupConfig.getConfigData()).andReturn(new Gson().toJson(mapGroupConfigProperties)).anyTimes();
+
+    replay(blueprintDAO, managementController, request, response, blueprint, stackServiceResponse1, stackServiceResponse2,
+        stackServiceComponentResponse1, stackServiceComponentResponse2, stackServiceComponentResponse3,
+        stackConfigurationResponse1, stackConfigurationResponse2, stackConfigurationResponse3, stackConfigurationResponse4,
+        blueprintConfig, hostGroup, hostGroupComponent1, hostGroupComponent2, hostGroupComponent3, hostGroupConfig,
+        serviceResourceProvider, componentResourceProvider, hostResourceProvider, hostComponentResourceProvider,
+        configGroupResourceProvider, persistKeyValue, metaInfo);
+
+    // test
+    ClusterResourceProvider.init(blueprintDAO, metaInfo);
+    ResourceProvider provider = new TestClusterResourceProvider(
+        managementController, serviceResourceProvider, componentResourceProvider,
+        hostResourceProvider, hostComponentResourceProvider, configGroupResourceProvider);
+
+    try {
+      provider.createResources(request);
+      fail("Expected exception for missing password property");
+    } catch (IllegalArgumentException e) {
+      //expected
+    }
+
+    verify(blueprintDAO, managementController, request, response, blueprint, stackServiceResponse1, stackServiceResponse2,
+        stackServiceComponentResponse1, stackServiceComponentResponse2, stackServiceComponentResponse3,
+        stackConfigurationResponse1, stackConfigurationResponse2, stackConfigurationResponse3, stackConfigurationResponse4,
+        blueprintConfig, hostGroup, hostGroupComponent1, hostGroupComponent2, hostGroupComponent3, hostGroupConfig,
+        serviceResourceProvider, componentResourceProvider, hostResourceProvider, hostComponentResourceProvider,
+        configGroupResourceProvider, persistKeyValue);
+  }
+
+  @Test
+  public void testCreateResource_blueprint__defaultPassword() throws Exception {
+    String blueprintName = "test-blueprint";
+    String stackName = "test";
+    String stackVersion = "1.23";
+    String clusterName = "c1";
+
+    BlueprintDAO blueprintDAO = createStrictMock(BlueprintDAO.class);
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+    AmbariManagementController managementController = createStrictMock(AmbariManagementController.class);
+    Request request = createNiceMock(Request.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+    BlueprintEntity blueprint = createNiceMock(BlueprintEntity.class);
+    StackServiceResponse stackServiceResponse1 = createNiceMock(StackServiceResponse.class);
+    StackServiceResponse stackServiceResponse2 = createNiceMock(StackServiceResponse.class);
+    Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>();
+
+    StackServiceComponentResponse stackServiceComponentResponse1 = createNiceMock(StackServiceComponentResponse.class);
+    StackServiceComponentResponse stackServiceComponentResponse2 = createNiceMock(StackServiceComponentResponse.class);
+    StackServiceComponentResponse stackServiceComponentResponse3 = createNiceMock(StackServiceComponentResponse.class);
+    Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture1 = new Capture<Set<StackServiceComponentRequest>>();
+    Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture2 = new Capture<Set<StackServiceComponentRequest>>();
+
+    StackConfigurationResponse stackConfigurationResponse1 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse2 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse3 = createNiceMock(StackConfigurationResponse.class);
+    StackConfigurationResponse stackConfigurationResponse4 = createNiceMock(StackConfigurationResponse.class);
+    Capture<Set<StackConfigurationRequest>> serviceConfigurationRequestCapture1 = new Capture<Set<StackConfigurationRequest>>();
+    Capture<Set<StackConfigurationRequest>> serviceConfigurationRequestCapture2 = new Capture<Set<StackConfigurationRequest>>();
+
+    BlueprintConfigEntity blueprintConfig = createNiceMock(BlueprintConfigEntity.class);
+
+    HostGroupEntity hostGroup = createNiceMock(HostGroupEntity.class);
+    HostGroupComponentEntity hostGroupComponent1 = createNiceMock(HostGroupComponentEntity.class);
+    HostGroupComponentEntity hostGroupComponent2 = createNiceMock(HostGroupComponentEntity.class);
+    HostGroupComponentEntity hostGroupComponent3 = createNiceMock(HostGroupComponentEntity.class);
+
+    HostGroupConfigEntity hostGroupConfig = createNiceMock(HostGroupConfigEntity.class);
+
+    ServiceResourceProvider serviceResourceProvider = createStrictMock(ServiceResourceProvider.class);
+    ResourceProvider componentResourceProvider = createStrictMock(ResourceProvider.class);
+    ResourceProvider hostResourceProvider = createStrictMock(ResourceProvider.class);
+    ResourceProvider hostComponentResourceProvider = createStrictMock(ResourceProvider.class);
+    ConfigGroupResourceProvider configGroupResourceProvider = createStrictMock(ConfigGroupResourceProvider.class);
+    PersistKeyValueImpl persistKeyValue = createNiceMock(PersistKeyValueImpl.class);
+
+    Capture<ClusterRequest> createClusterRequestCapture = new Capture<ClusterRequest>();
+    Capture<Set<ClusterRequest>> updateClusterRequestCapture = new Capture<Set<ClusterRequest>>();
+    Capture<Map<String, String>> updateClusterPropertyMapCapture = new Capture<Map<String, String>>();
+    Capture<Set<ClusterRequest>> updateClusterRequestCapture2 = new Capture<Set<ClusterRequest>>();
+    Capture<Map<String, String>> updateClusterPropertyMapCapture2 = new Capture<Map<String, String>>();
+    Capture<Set<ClusterRequest>> updateClusterRequestCapture3 = new Capture<Set<ClusterRequest>>();
+    Capture<Map<String, String>> updateClusterPropertyMapCapture3 = new Capture<Map<String, String>>();
+
+    Capture<Request> serviceRequestCapture = new Capture<Request>();
+    Capture<Request> componentRequestCapture = new Capture<Request>();
+    Capture<Request> componentRequestCapture2 = new Capture<Request>();
+    Capture<Request> hostRequestCapture = new Capture<Request>();
+    Capture<Request> hostComponentRequestCapture = new Capture<Request>();
+    Capture<Set<ConfigGroupRequest>> configGroupRequestCapture = new Capture<Set<ConfigGroupRequest>>();
+
+    Set<StackServiceResponse> stackServiceResponses = new LinkedHashSet<StackServiceResponse>();
+    stackServiceResponses.add(stackServiceResponse1);
+    stackServiceResponses.add(stackServiceResponse2);
+
+    // service1 has 2 components
+    Set<StackServiceComponentResponse> stackServiceComponentResponses1 = new LinkedHashSet<StackServiceComponentResponse>();
+    stackServiceComponentResponses1.add(stackServiceComponentResponse1);
+    stackServiceComponentResponses1.add(stackServiceComponentResponse2);
+
+    // service2 has 1 components
+    Set<StackServiceComponentResponse> stackServiceComponentResponses2 = new LinkedHashSet<StackServiceComponentResponse>();
+    stackServiceComponentResponses2.add(stackServiceComponentResponse3);
+
+    // service1 has 1 config
+    Set<StackConfigurationResponse> stackConfigurationResponses1 = new LinkedHashSet<StackConfigurationResponse>();
+    stackConfigurationResponses1.add(stackConfigurationResponse1);
+
+    // service2 has 3 config
+    Set<StackConfigurationResponse> stackConfigurationResponses2 = new LinkedHashSet<StackConfigurationResponse>();
+    stackConfigurationResponses2.add(stackConfigurationResponse2);
+    stackConfigurationResponses2.add(stackConfigurationResponse3);
+    stackConfigurationResponses2.add(stackConfigurationResponse4);
+
+    Collection<HostGroupComponentEntity> hostGroupComponents = new LinkedHashSet<HostGroupComponentEntity>();
+    hostGroupComponents.add(hostGroupComponent1);
+    hostGroupComponents.add(hostGroupComponent2);
+    hostGroupComponents.add(hostGroupComponent3);
+
+    // request properties
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    properties.put(ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID, clusterName);
+    properties.put(ClusterResourceProvider.BLUEPRINT_PROPERTY_ID, blueprintName);
+    properties.put("default_password", "foo");
+    propertySet.add(properties);
+
+    Collection<Map<String, Object>> hostGroups = new ArrayList<Map<String, Object>>();
+    Map<String, Object> hostGroupProperties = new HashMap<String, Object>();
+    hostGroups.add(hostGroupProperties);
+    hostGroupProperties.put("name", "group1");
+    Collection<Map<String, String>> hostGroupHosts = new ArrayList<Map<String, String>>();
+    hostGroupProperties.put("hosts", hostGroupHosts);
+    Map<String, String> hostGroupHostProperties = new HashMap<String, String>();
+    hostGroupHostProperties.put("fqdn", "host.domain");
+    hostGroupHosts.add(hostGroupHostProperties);
+    properties.put("host_groups", hostGroups);
+
+    Map<String, String> mapGroupConfigProperties = new HashMap<String, String>();
+    mapGroupConfigProperties.put("myGroupProp", "awesomeValue");
+
+    // blueprint cluster configuration properties
+    Map<String, String> blueprintConfigProperties = new HashMap<String, String>();
+    blueprintConfigProperties.put("property1", "value2");
+    blueprintConfigProperties.put("new.property", "new.property.value");
+
+    Map<String, Map<String, Collection<String>>> allMissingPasswords = new HashMap<String, Map<String, Collection<String>>>();
+    Map<String, Collection<String>> missingHGPasswords = new HashMap<String, Collection<String>>();
+    Collection<String> missingPasswords = new ArrayList<String>();
+    missingPasswords.add("my.missing.password");
+    missingHGPasswords.put("core-site", missingPasswords);
+    allMissingPasswords.put("group1", missingHGPasswords);
+
+    // expectations
+    expect(request.getProperties()).andReturn(propertySet).anyTimes();
+    expect(blueprintDAO.findByName(blueprintName)).andReturn(blueprint);
+    expect(blueprint.getStackName()).andReturn(stackName);
+    expect(blueprint.getStackVersion()).andReturn(stackVersion);
+    expect(blueprint.getConfigurations()).andReturn(Collections.<BlueprintConfigEntity>singletonList(blueprintConfig));
+    expect(blueprint.validateConfigurations(metaInfo, PropertyInfo.PropertyType.PASSWORD)).andReturn(allMissingPasswords);
+
+    expect(managementController.getStackServices(capture(stackServiceRequestCapture))).andReturn(stackServiceResponses);
+    expect(stackServiceResponse1.getServiceName()).andReturn("service1");
+    expect(stackServiceResponse2.getServiceName()).andReturn("service2");
+
+    expect(managementController.getStackComponents(capture(serviceComponentRequestCapture1))).
+        andReturn(stackServiceComponentResponses1);
+    expect(stackServiceComponentResponse1.getComponentName()).andReturn("component1");
+    expect(stackServiceComponentResponse2.getComponentName()).andReturn("component2");
+
+    expect(managementController.getStackConfigurations(capture(serviceConfigurationRequestCapture1))).
+        andReturn(stackConfigurationResponses1);
+    expect(stackConfigurationResponse1.getType()).andReturn("core-site.xml");
+    expect(stackConfigurationResponse1.getPropertyName()).andReturn("property1");
+    expect(stackConfigurationResponse1.getPropertyValue()).andReturn("value1");
+
+    expect(managementController.getStackComponents(capture(serviceComponentRequestCapture2))).
+        andReturn(stackServiceComponentResponses2);
+    expect(stackServiceComponentResponse3.getComponentName()).andReturn("component3");
+
+    expect(managementController.getStackConfigurations(capture(serviceConfigurationRequestCapture2))).
+        andReturn(stackConfigurationResponses2);
+    expect(stackConfigurationResponse2.getType()).andReturn("hdfs-site.xml");
+    expect(stackConfigurationResponse2.getPropertyName()).andReturn("property2");
+    expect(stackConfigurationResponse2.getPropertyValue()).andReturn("value2");
+
+    expect(stackConfigurationResponse3.getType()).andReturn("global.xml");
+    expect(stackConfigurationResponse3.getPropertyName()).andReturn("oozie_user");
+    expect(stackConfigurationResponse3.getPropertyValue()).andReturn("oozie");
+
+    expect(stackConfigurationResponse4.getType()).andReturn("core-site.xml");
+    expect(stackConfigurationResponse4.getPropertyName()).andReturn("property3");
+    expect(stackConfigurationResponse4.getPropertyValue()).andReturn("value3");
+
+    expect(blueprintConfig.getBlueprintName()).andReturn("test-blueprint").anyTimes();
+    expect(blueprintConfig.getType()).andReturn("core-site").anyTimes();
+    expect(blueprintConfig.getConfigData()).andReturn(new Gson().toJson(blueprintConfigProperties));
+
+    expect(blueprint.getHostGroups()).andReturn(Collections.singleton(hostGroup)).anyTimes();
+    expect(hostGroup.getName()).andReturn("group1").anyTimes();
+    expect(hostGroup.getComponents()).andReturn(hostGroupComponents).anyTimes();
+    expect(hostGroupComponent1.getName()).andReturn("component1").anyTimes();
+    expect(hostGroupComponent2.getName()).andReturn("component2").anyTimes();
+    expect(hostGroupComponent3.getName()).andReturn("component3").anyTimes();
+    expect(hostGroup.getConfigurations()).andReturn(
+        Collections.<HostGroupConfigEntity>singleton(hostGroupConfig)).anyTimes();
+
+    expect(hostGroupConfig.getType()).andReturn("core-site").anyTimes();
+    expect(hostGroupConfig.getConfigData()).andReturn(new Gson().toJson(mapGroupConfigProperties)).anyTimes();
+
+    managementController.createCluster(capture(createClusterRequestCapture));
+    expect(managementController.updateClusters(capture(updateClusterRequestCapture),
+        capture(updateClusterPropertyMapCapture))).andReturn(null);
+    expect(managementController.updateClusters(capture(updateClusterRequestCapture2),
+        capture(updateClusterPropertyMapCapture2))).andReturn(null);
+    expect(managementController.updateClusters(capture(updateClusterRequestCapture3),
+        capture(updateClusterPropertyMapCapture3))).andReturn(null);
+
+    expect(serviceResourceProvider.createResources(capture(serviceRequestCapture))).andReturn(null);
+    expect(componentResourceProvider.createResources(capture(componentRequestCapture))).andReturn(null);
+    expect(componentResourceProvider.createResources(capture(componentRequestCapture2))).andReturn(null);
+    expect(hostResourceProvider.createResources(capture(hostRequestCapture))).andReturn(null);
+    expect(hostComponentResourceProvider.createResources(capture(hostComponentRequestCapture))).andReturn(null);
+
+    expect(serviceResourceProvider.installAndStart(clusterName)).andReturn(response);
+
+    expect(configGroupResourceProvider.createResources(
+        capture(configGroupRequestCapture))).andReturn(null);
+
+    persistKeyValue.put("CLUSTER_CURRENT_STATUS", "{\"clusterState\":\"CLUSTER_STARTED_5\"}");
+
+    replay(blueprintDAO, managementController, request, response, blueprint, stackServiceResponse1, stackServiceResponse2,
+        stackServiceComponentResponse1, stackServiceComponentResponse2, stackServiceComponentResponse3,
+        stackConfigurationResponse1, stackConfigurationResponse2, stackConfigurationResponse3, stackConfigurationResponse4,
+        blueprintConfig, hostGroup, hostGroupComponent1, hostGroupComponent2, hostGroupComponent3, hostGroupConfig,
+        serviceResourceProvider, componentResourceProvider, hostResourceProvider, hostComponentResourceProvider,
+        configGroupResourceProvider, persistKeyValue, metaInfo);
+
+    // test
+    ClusterResourceProvider.init(blueprintDAO, metaInfo);
+    PersistKeyValueService.init(persistKeyValue);
+    ResourceProvider provider = new TestClusterResourceProvider(
+        managementController, serviceResourceProvider, componentResourceProvider,
+        hostResourceProvider, hostComponentResourceProvider, configGroupResourceProvider);
+
+    RequestStatus requestStatus = provider.createResources(request);
+
+    assertEquals(RequestStatus.Status.InProgress, requestStatus.getStatus());
+
+    Set<StackServiceRequest> stackServiceRequests = stackServiceRequestCapture.getValue();
+    assertEquals(1, stackServiceRequests.size());
+    StackServiceRequest ssr = stackServiceRequests.iterator().next();
+    assertNull(ssr.getServiceName());
+    assertEquals("test", ssr.getStackName());
+    assertEquals("1.23", ssr.getStackVersion());
+
+    Set<StackServiceComponentRequest> stackServiceComponentRequests1 = serviceComponentRequestCapture1.getValue();
+    Set<StackServiceComponentRequest> stackServiceComponentRequests2 = serviceComponentRequestCapture2.getValue();
+    assertEquals(1, stackServiceComponentRequests1.size());
+    assertEquals(1, stackServiceComponentRequests2.size());
+    StackServiceComponentRequest scr1 = stackServiceComponentRequests1.iterator().next();
+    StackServiceComponentRequest scr2 = stackServiceComponentRequests2.iterator().next();
+    assertNull(scr1.getComponentName());
+    assertNull(scr2.getComponentName());
+    assertEquals("1.23", scr1.getStackVersion());
+    assertEquals("1.23", scr2.getStackVersion());
+    assertEquals("test", scr1.getStackName());
+    assertEquals("test", scr2.getStackName());
+    assertTrue(scr1.getServiceName().equals("service1") || scr1.getServiceName().equals("service2"));
+    assertTrue(scr2.getServiceName().equals("service1") || scr2.getServiceName().equals("service2") &&
+        ! scr2.getServiceName().equals(scr1.getServiceName()));
+
+    Set<StackConfigurationRequest> serviceConfigurationRequest1 = serviceConfigurationRequestCapture1.getValue();
+    Set<StackConfigurationRequest> serviceConfigurationRequest2 = serviceConfigurationRequestCapture2.getValue();
+    assertEquals(1, serviceConfigurationRequest1.size());
+    assertEquals(1, serviceConfigurationRequest2.size());
+    StackConfigurationRequest configReq1 = serviceConfigurationRequest1.iterator().next();
+    StackConfigurationRequest configReq2 = serviceConfigurationRequest2.iterator().next();
+    assertNull(configReq1.getPropertyName());
+    assertNull(configReq2.getPropertyName());
+    assertEquals("1.23", configReq1.getStackVersion());
+    assertEquals("1.23", configReq2.getStackVersion());
+    assertEquals("test", configReq1.getStackName());
+    assertEquals("test", configReq2.getStackName());
+    assertTrue(configReq1.getServiceName().equals("service1") || configReq1.getServiceName().equals("service2"));
+    assertTrue(configReq2.getServiceName().equals("service1") || configReq2.getServiceName().equals("service2") &&
+        ! configReq2.getServiceName().equals(configReq1.getServiceName()));
+
+    ClusterRequest clusterRequest = createClusterRequestCapture.getValue();
+    assertEquals(clusterName, clusterRequest.getClusterName());
+    assertEquals("test-1.23", clusterRequest.getStackVersion());
+
+    Set<ClusterRequest> updateClusterRequest1 = updateClusterRequestCapture.getValue();
+    Set<ClusterRequest> updateClusterRequest2 = updateClusterRequestCapture2.getValue();
+    Set<ClusterRequest> updateClusterRequest3 = updateClusterRequestCapture3.getValue();
+    assertEquals(1, updateClusterRequest1.size());
+    assertEquals(1, updateClusterRequest2.size());
+    assertEquals(1, updateClusterRequest3.size());
+    ClusterRequest ucr1 = updateClusterRequest1.iterator().next();
+    ClusterRequest ucr2 = updateClusterRequest2.iterator().next();
+    ClusterRequest ucr3 = updateClusterRequest3.iterator().next();
+    assertEquals(clusterName, ucr1.getClusterName());
+    assertEquals(clusterName, ucr2.getClusterName());
+    assertEquals(clusterName, ucr3.getClusterName());
+    ConfigurationRequest cr1 = ucr1.getDesiredConfig();
+    ConfigurationRequest cr2 = ucr2.getDesiredConfig();
+    ConfigurationRequest cr3 = ucr3.getDesiredConfig();
+    assertEquals("1", cr1.getVersionTag());
+    assertEquals("1", cr2.getVersionTag());
+    assertEquals("1", cr3.getVersionTag());
+    Map<String, ConfigurationRequest> mapConfigRequests = new HashMap<String, ConfigurationRequest>();
+    mapConfigRequests.put(cr1.getType(), cr1);
+    mapConfigRequests.put(cr2.getType(), cr2);
+    mapConfigRequests.put(cr3.getType(), cr3);
+    assertEquals(3, mapConfigRequests.size());
+    ConfigurationRequest globalConfigRequest = mapConfigRequests.get("global");
+    assertEquals(5, globalConfigRequest.getProperties().size());
+    assertEquals("hadoop", globalConfigRequest.getProperties().get("user_group"));
+    assertEquals("ambari-qa", globalConfigRequest.getProperties().get("smokeuser"));
+    assertEquals("default@REPLACEME.NOWHERE", globalConfigRequest.getProperties().get("nagios_contact"));
+    assertEquals("admin", globalConfigRequest.getProperties().get("nagios_web_password"));
+    assertEquals("oozie", globalConfigRequest.getProperties().get("oozie_user"));
+    ConfigurationRequest hdfsConfigRequest = mapConfigRequests.get("hdfs-site");
+    assertEquals(1, hdfsConfigRequest.getProperties().size());
+    assertEquals("value2", hdfsConfigRequest.getProperties().get("property2"));
+    ConfigurationRequest coreConfigRequest = mapConfigRequests.get("core-site");
+    assertEquals(6, coreConfigRequest.getProperties().size());
+    assertEquals("value2", coreConfigRequest.getProperties().get("property1"));
+    assertEquals("value3", coreConfigRequest.getProperties().get("property3"));
+    assertEquals("*", coreConfigRequest.getProperties().get("hadoop.proxyuser.oozie.hosts"));
+    assertEquals("users", coreConfigRequest.getProperties().get("hadoop.proxyuser.oozie.groups"));
+    assertEquals("new.property.value", coreConfigRequest.getProperties().get("new.property"));
+    assertEquals("foo", coreConfigRequest.getProperties().get("my.missing.password"));
+    assertNull(updateClusterPropertyMapCapture.getValue());
+    assertNull(updateClusterPropertyMapCapture2.getValue());
+    assertNull(updateClusterPropertyMapCapture3.getValue());
+
+    Request serviceRequest = serviceRequestCapture.getValue();
+    assertEquals(2, serviceRequest.getProperties().size());
+    Request componentRequest = componentRequestCapture.getValue();
+    Request componentRequest2 = componentRequestCapture2.getValue();
+    assertEquals(2, componentRequest.getProperties().size());
+    Set<String> componentRequest1Names = new HashSet<String>();
+    for (Map<String, Object> componentRequest1Properties : componentRequest.getProperties()) {
+      assertEquals(3, componentRequest1Properties.size());
+      assertEquals(clusterName, componentRequest1Properties.get("ServiceComponentInfo/cluster_name"));
+      assertEquals("service1", componentRequest1Properties.get("ServiceComponentInfo/service_name"));
+      componentRequest1Names.add((String) componentRequest1Properties.get("ServiceComponentInfo/component_name"));
+    }
+    assertTrue(componentRequest1Names.contains("component1") && componentRequest1Names.contains("component2"));
+    assertEquals(1, componentRequest2.getProperties().size());
+    Map<String, Object> componentRequest2Properties = componentRequest2.getProperties().iterator().next();
+    assertEquals(clusterName, componentRequest2Properties.get("ServiceComponentInfo/cluster_name"));
+    assertEquals("service2", componentRequest2Properties.get("ServiceComponentInfo/service_name"));
+    assertEquals("component3", componentRequest2Properties.get("ServiceComponentInfo/component_name"));
+    Request hostRequest = hostRequestCapture.getValue();
+    assertEquals(1, hostRequest.getProperties().size());
+    assertEquals(clusterName, hostRequest.getProperties().iterator().next().get("Hosts/cluster_name"));
+    assertEquals("host.domain", hostRequest.getProperties().iterator().next().get("Hosts/host_name"));
+    Request hostComponentRequest = hostComponentRequestCapture.getValue();
+    assertEquals(3, hostComponentRequest.getProperties().size());
+    Set<String> componentNames = new HashSet<String>();
+    for (Map<String, Object> hostComponentProperties : hostComponentRequest.getProperties()) {
+      assertEquals(3, hostComponentProperties.size());
+      assertEquals(clusterName, hostComponentProperties.get("HostRoles/cluster_name"));
+      assertEquals("host.domain", hostComponentProperties.get("HostRoles/host_name"));
+      componentNames.add((String) hostComponentProperties.get("HostRoles/component_name"));
+    }
+    assertTrue(componentNames.contains("component1") && componentNames.contains("component2") &&
+        componentNames.contains("component3"));
+
+    Set<ConfigGroupRequest> configGroupRequests = configGroupRequestCapture.getValue();
+    assertEquals(1, configGroupRequests.size());
+    ConfigGroupRequest configGroupRequest = configGroupRequests.iterator().next();
+    assertEquals(clusterName, configGroupRequest.getClusterName());
+    assertEquals("group1", configGroupRequest.getGroupName());
+    assertEquals("service1", configGroupRequest.getTag());
+    assertEquals("Host Group Configuration", configGroupRequest.getDescription());
+    Set<String> hosts = configGroupRequest.getHosts();
+    assertEquals(1, hosts.size());
+    assertEquals("host.domain", hosts.iterator().next());
+    assertEquals(1, configGroupRequest.getConfigs().size());
+
+    verify(blueprintDAO, managementController, request, response, blueprint, stackServiceResponse1, stackServiceResponse2,
+        stackServiceComponentResponse1, stackServiceComponentResponse2, stackServiceComponentResponse3,
+        stackConfigurationResponse1, stackConfigurationResponse2, stackConfigurationResponse3, stackConfigurationResponse4,
+        blueprintConfig, hostGroup, hostGroupComponent1, hostGroupComponent2, hostGroupComponent3, hostGroupConfig,
+        serviceResourceProvider, componentResourceProvider, hostResourceProvider, hostComponentResourceProvider,
+        configGroupResourceProvider, persistKeyValue);
+  }
+
+  @Test
   public void testCreateResource_blueprint_hostMappedToMultipleHG() throws Exception {
     String blueprintName = "test-blueprint";
     String stackName = "test";
@@ -700,7 +1260,7 @@ public class ClusterResourceProviderTest {
         configGroupResourceProvider);
 
     // test
-    ClusterResourceProvider.injectBlueprintDAO(blueprintDAO);
+    ClusterResourceProvider.init(blueprintDAO, null);
     ResourceProvider provider = new TestClusterResourceProvider(
         managementController, serviceResourceProvider, componentResourceProvider,
         hostResourceProvider, hostComponentResourceProvider, configGroupResourceProvider);
@@ -786,7 +1346,8 @@ public class ClusterResourceProviderTest {
 
     entry = multiHostProperty2.entrySet().iterator().next();
     newValue = propertyUpdaterMap.get(entry.getKey()).update(hostGroups, entry.getValue());
-    Assert.assertEquals("['h1','h2']", newValue);
+    // no ordering guarantee
+    Assert.assertTrue(newValue.equals("['h1','h2']") || newValue.equals("['h2','h1']"));
 
     entry = mProperty.entrySet().iterator().next();
     newValue = propertyUpdaterMap.get(entry.getKey()).update(hostGroups, entry.getValue());

http://git-wip-us.apache.org/repos/asf/ambari/blob/4651447c/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/BlueprintEntityTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/BlueprintEntityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/BlueprintEntityTest.java
index c61c109..cff9aad 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/BlueprintEntityTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/BlueprintEntityTest.java
@@ -18,13 +18,24 @@
 
 package org.apache.ambari.server.orm.entities;
 
+import com.google.gson.Gson;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.junit.Test;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
 
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 /**
  * BlueprintEntity unit tests
@@ -67,4 +78,181 @@ public class BlueprintEntityTest {
     assertSame(configurations, entity.getConfigurations());
   }
 
+  @Test
+  public void testValidateConfigurations_clusterConfig() throws Exception {
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+
+    Map<String, PropertyInfo> requiredProps = new HashMap<String, PropertyInfo>();
+    PropertyInfo prop = new PropertyInfo();
+    prop.setFilename("core-site.xml");
+    prop.setName("super.secret.password");
+    prop.setRequireInput(true);
+    prop.setType(PropertyInfo.PropertyType.PASSWORD);
+    prop.setValue(null);
+    requiredProps.put("service1", prop);
+
+    BlueprintEntity entity = new BlueprintEntity();
+    entity.setStackName("stackName");
+    entity.setStackVersion("version");
+
+    Collection<BlueprintConfigEntity> configurations = new HashSet<BlueprintConfigEntity>();
+    BlueprintConfigEntity configEntity = new BlueprintConfigEntity();
+    configEntity.setBlueprintEntity(entity);
+    configEntity.setBlueprintName("blueprint");
+    configEntity.setType("core-site");
+
+    Map<String, String> configData = new HashMap<String, String>();
+    configData.put("foo", "val1");
+    configData.put("bar", "val2");
+    configData.put("super.secret.password", "password");
+    configEntity.setConfigData(new Gson().toJson(configData));
+
+    configurations.add(configEntity);
+    entity.setConfigurations(configurations);
+
+    Collection<HostGroupEntity> hostGroupEntities = new HashSet<HostGroupEntity>();
+    HostGroupEntity hostGroupEntity = new HostGroupEntity();
+    Collection<HostGroupComponentEntity> hostGroupComponents = new HashSet<HostGroupComponentEntity>();
+    HostGroupComponentEntity componentEntity = new HostGroupComponentEntity();
+    componentEntity.setName("component1");
+    componentEntity.setBlueprintName("blueprint");
+    componentEntity.setHostGroupEntity(hostGroupEntity);
+    componentEntity.setHostGroupName("group1");
+    hostGroupComponents.add(componentEntity);
+    hostGroupEntity.setComponents(hostGroupComponents);
+    hostGroupEntity.setConfigurations(Collections.<HostGroupConfigEntity>emptyList());
+    hostGroupEntities.add(hostGroupEntity);
+    entity.setHostGroups(hostGroupEntities);
+
+    expect(metaInfo.getComponentToService("stackName", "version", "component1")).andReturn("service1");
+    expect(metaInfo.getRequiredProperties("stackName", "version", "service1")).andReturn(requiredProps);
+
+    replay(metaInfo);
+
+    Map<String, Map<String, Collection<String>>> missingProps = entity.validateConfigurations(
+        metaInfo, PropertyInfo.PropertyType.PASSWORD);
+
+    assertTrue(missingProps.isEmpty());
+
+    verify(metaInfo);
+  }
+
+  @Test
+  public void testValidateConfigurations_hostGroupConfig() throws Exception {
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+
+    Map<String, PropertyInfo> requiredProps = new HashMap<String, PropertyInfo>();
+    PropertyInfo prop = new PropertyInfo();
+    prop.setFilename("core-site.xml");
+    prop.setName("super.secret.password");
+    prop.setRequireInput(true);
+    prop.setType(PropertyInfo.PropertyType.PASSWORD);
+    prop.setValue(null);
+    requiredProps.put("service1", prop);
+
+    BlueprintEntity entity = new BlueprintEntity();
+    entity.setStackName("stackName");
+    entity.setStackVersion("version");
+
+    entity.setConfigurations(Collections.<BlueprintConfigEntity>emptyList());
+
+    Collection<HostGroupEntity> hostGroupEntities = new HashSet<HostGroupEntity>();
+    HostGroupEntity hostGroupEntity = new HostGroupEntity();
+    Collection<HostGroupComponentEntity> hostGroupComponents = new HashSet<HostGroupComponentEntity>();
+    HostGroupComponentEntity componentEntity = new HostGroupComponentEntity();
+    componentEntity.setName("component1");
+    componentEntity.setBlueprintName("blueprint");
+    componentEntity.setHostGroupEntity(hostGroupEntity);
+    componentEntity.setHostGroupName("group1");
+    hostGroupComponents.add(componentEntity);
+    hostGroupEntity.setComponents(hostGroupComponents);
+
+    Collection<HostGroupConfigEntity> configurations = new HashSet<HostGroupConfigEntity>();
+    HostGroupConfigEntity configEntity = new HostGroupConfigEntity();
+    configEntity.setHostGroupEntity(hostGroupEntity);
+    configEntity.setBlueprintName("blueprint");
+    configEntity.setType("core-site");
+
+    Map<String, String> configData = new HashMap<String, String>();
+    configData.put("foo", "val1");
+    configData.put("bar", "val2");
+    configData.put("super.secret.password", "password");
+    configEntity.setConfigData(new Gson().toJson(configData));
+    configurations.add(configEntity);
+
+    hostGroupEntity.setConfigurations(configurations);
+    hostGroupEntities.add(hostGroupEntity);
+    entity.setHostGroups(hostGroupEntities);
+
+    expect(metaInfo.getComponentToService("stackName", "version", "component1")).andReturn("service1");
+    expect(metaInfo.getRequiredProperties("stackName", "version", "service1")).andReturn(requiredProps);
+
+    replay(metaInfo);
+
+    Map<String, Map<String, Collection<String>>> missingProps = entity.validateConfigurations(
+        metaInfo, PropertyInfo.PropertyType.PASSWORD);
+
+    assertTrue(missingProps.isEmpty());
+
+    verify(metaInfo);
+  }
+
+  @Test
+  public void testValidateConfigurations_negative() throws Exception {
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+
+    Map<String, PropertyInfo> requiredProps = new HashMap<String, PropertyInfo>();
+    PropertyInfo prop = new PropertyInfo();
+    prop.setFilename("core-site.xml");
+    prop.setName("super.secret.password");
+    prop.setRequireInput(true);
+    prop.setType(PropertyInfo.PropertyType.PASSWORD);
+    prop.setValue(null);
+    requiredProps.put("service1", prop);
+
+    BlueprintEntity entity = new BlueprintEntity();
+    entity.setStackName("stackName");
+    entity.setStackVersion("version");
+
+    Collection<BlueprintConfigEntity> configurations = new HashSet<BlueprintConfigEntity>();
+    BlueprintConfigEntity configEntity = new BlueprintConfigEntity();
+    configEntity.setBlueprintEntity(entity);
+    configEntity.setBlueprintName("blueprint");
+    configEntity.setType("core-site");
+
+    Map<String, String> configData = new HashMap<String, String>();
+    configData.put("foo", "val1");
+    configData.put("bar", "val2");
+    configData.put("some.other.secret.password", "password");
+    configEntity.setConfigData(new Gson().toJson(configData));
+
+    configurations.add(configEntity);
+    entity.setConfigurations(configurations);
+
+    Collection<HostGroupEntity> hostGroupEntities = new HashSet<HostGroupEntity>();
+    HostGroupEntity hostGroupEntity = new HostGroupEntity();
+    Collection<HostGroupComponentEntity> hostGroupComponents = new HashSet<HostGroupComponentEntity>();
+    HostGroupComponentEntity componentEntity = new HostGroupComponentEntity();
+    componentEntity.setName("component1");
+    componentEntity.setBlueprintName("blueprint");
+    componentEntity.setHostGroupEntity(hostGroupEntity);
+    componentEntity.setHostGroupName("group1");
+    hostGroupComponents.add(componentEntity);
+    hostGroupEntity.setComponents(hostGroupComponents);
+    hostGroupEntity.setConfigurations(Collections.<HostGroupConfigEntity>emptyList());
+    hostGroupEntities.add(hostGroupEntity);
+    entity.setHostGroups(hostGroupEntities);
+
+    expect(metaInfo.getComponentToService("stackName", "version", "component1")).andReturn("service1");
+    expect(metaInfo.getRequiredProperties("stackName", "version", "service1")).andReturn(requiredProps);
+
+    replay(metaInfo);
+
+    Map<String, Map<String, Collection<String>>> missingProps = entity.validateConfigurations(
+        metaInfo, PropertyInfo.PropertyType.PASSWORD);
+
+    assertEquals(1, missingProps.size());
+
+    verify(metaInfo);
+  }
 }