You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ad...@apache.org on 2017/11/17 17:23:00 UTC

ambari git commit: AMBARI-22253. Cluster creation via V2 blueprint (adoroszlai)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714-blueprintv2 5243104a4 -> b91ad4867


AMBARI-22253. Cluster creation via V2 blueprint (adoroszlai)


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

Branch: refs/heads/branch-feature-AMBARI-14714-blueprintv2
Commit: b91ad486751547e5672b7a982cb4db5c0a1f221f
Parents: 5243104
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Wed Nov 15 12:29:22 2017 +0100
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Fri Nov 17 18:17:30 2017 +0100

----------------------------------------------------------------------
 .../controller/internal/BaseClusterRequest.java |   2 +-
 .../internal/ProvisionClusterRequest.java       | 130 +++++++++----------
 .../server/state/cluster/ClusterImpl.java       |  12 +-
 .../ambari/server/topology/AmbariContext.java   |  53 +++-----
 .../server/topology/BlueprintFactory.java       |   6 +-
 .../ambari/server/topology/BlueprintImplV2.java |   9 +-
 .../ambari/server/topology/BlueprintV2.java     |   1 -
 .../server/topology/BlueprintV2Factory.java     |   2 -
 .../topology/ClusterConfigurationRequest.java   |  51 +++-----
 .../ambari/server/topology/ClusterTopology.java |   4 +-
 .../server/topology/ClusterTopologyImpl.java    |  79 +++++------
 .../ambari/server/topology/Configuration.java   |   4 +
 .../server/topology/ConfigurationFactory.java   |  14 +-
 .../ambari/server/topology/HostGroupInfo.java   |  70 +++++-----
 .../ambari/server/topology/HostGroupV2.java     |   3 +-
 .../apache/ambari/server/topology/Service.java  |   1 +
 .../validators/ClusterConfigTypeValidator.java  |   2 +-
 .../topology/ConfigurationFactoryTest.java      |   6 +-
 18 files changed, 201 insertions(+), 248 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java
index eefb31b..4a32529 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java
@@ -52,7 +52,7 @@ public abstract class BaseClusterRequest implements TopologyRequest {
   /**
    * host group info map
    */
-  protected final Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<>();
+  private final Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<>();
 
   protected ProvisionAction provisionAction;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
index 48d5016..a38b314 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
@@ -17,13 +17,16 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import static org.apache.ambari.server.topology.ConfigurationFactory.toBranchMapList;
+import static org.apache.ambari.server.topology.ConfigurationFactory.toLeafMapList;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.ambari.server.api.predicate.InvalidQueryException;
 import org.apache.ambari.server.security.encryption.CredentialStoreType;
@@ -45,13 +48,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Enums;
-import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 
 /**
  * Request for provisioning a cluster.
  */
-@SuppressWarnings("unchecked")
 public class ProvisionClusterRequest extends BaseClusterRequest {
   /**
    * host groups property name
@@ -131,12 +132,6 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
   public static final String SERVICE_GROUP_NAME_PROPERETY = "service_group";
   public static final String SERVICE_NAME_PROPERTY = "name";
 
-
-  /**
-   * configuration factory
-   */
-  private static ConfigurationFactory configurationFactory = new ConfigurationFactory();
-
   /**
    * cluster name
    */
@@ -194,33 +189,7 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
     }
 
     this.securityConfiguration = securityConfiguration;
-
-    // parse service configs and merge with BP service configs
-    serviceConfigs = new ArrayList<>();
-    Collection<Map> services = (Collection<Map>) properties.get(SERVICES_PROPERTY);
-    for (Map serviceMap : services) {
-      String serviceName = (String) serviceMap.get(SERVICE_NAME_PROPERTY);
-      if (StringUtils.isEmpty(serviceName)) {
-        throw new InvalidTopologyTemplateException("Service name must be specified.");
-      }
-      String serviceGroupName = (String) serviceMap.get(SERVICE_GROUP_NAME_PROPERETY);
-      if (StringUtils.isEmpty(serviceGroupName)) {
-        throw new InvalidTopologyTemplateException("Service group name must be specified for service: " + serviceName);
-      }
-      Configuration configuration = configurationFactory.getConfiguration((Collection<Map<String, String>>)
-              serviceMap.get(CONFIGURATIONS_PROPERTY));
-      ServiceId serviceId = ServiceId.of(serviceName, serviceGroupName);
-      Service service = blueprint.getServiceById(serviceId);
-      if (service == null) {
-        throw new InvalidTopologyTemplateException("Service: " + serviceName + " in service group: "
-                + serviceGroupName + " not found.");
-      }
-      service.getConfiguration().setParentConfiguration(service.getStack().getConfiguration());
-      configuration.setParentConfiguration(service.getConfiguration());
-      service.setConfiguration(configuration);
-      serviceConfigs.add(service);
-    }
-
+    serviceConfigs = parseServiceConfigs(properties);
     parseHostGroupInfo(properties);
     this.credentialsMap = parseCredentials(properties);
     this.configRecommendationStrategy = parseConfigRecommendationStrategy(properties);
@@ -234,6 +203,35 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
     }
   }
 
+  private List<Service> parseServiceConfigs(Map<String, Object> properties) throws InvalidTopologyTemplateException {
+    // parse service configs and merge with BP service configs
+    List<Service> serviceConfigs = new ArrayList<>();
+    Collection<Map<String, Object>> services = toBranchMapList(properties.get(SERVICES_PROPERTY));
+    if (services != null) {
+      for (Map<String, Object> serviceMap : services) {
+        String serviceName = (String) serviceMap.get(SERVICE_NAME_PROPERTY);
+        if (StringUtils.isEmpty(serviceName)) {
+          throw new InvalidTopologyTemplateException("Service name must be specified.");
+        }
+        String serviceGroupName = (String) serviceMap.get(SERVICE_GROUP_NAME_PROPERETY);
+        if (StringUtils.isEmpty(serviceGroupName)) {
+          throw new InvalidTopologyTemplateException("Service group name must be specified for service: " + serviceName);
+        }
+        Configuration configuration = ConfigurationFactory.toConfiguration(toLeafMapList(serviceMap.get(CONFIGURATIONS_PROPERTY)));
+        ServiceId serviceId = ServiceId.of(serviceName, serviceGroupName);
+        Service service = blueprint.getServiceById(serviceId);
+        if (service == null) {
+          throw new InvalidTopologyTemplateException("Service: " + serviceName + " in service group: "
+            + serviceGroupName + " not found.");
+        }
+        configuration.setParentConfiguration(service.getConfiguration());
+        service.setConfiguration(configuration);
+        serviceConfigs.add(service);
+      }
+    }
+    return serviceConfigs;
+  }
+
   private String processQuickLinksProfile(Map<String, Object> properties) throws QuickLinksProfileEvaluationException {
     Object globalFilters = properties.get(QUICKLINKS_PROFILE_FILTERS_PROPERTY);
     Object serviceFilters = properties.get(QUICKLINKS_PROFILE_SERVICES_PROPERTY);
@@ -245,7 +243,7 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
   private Map<String, Credential> parseCredentials(Map<String, Object> properties) throws
     InvalidTopologyTemplateException {
     HashMap<String, Credential> credentialHashMap = new HashMap<>();
-    Set<Map<String, String>> credentialsSet = (Set<Map<String, String>>) properties.get(ClusterResourceProvider.CREDENTIALS);
+    Collection<Map<String, String>> credentialsSet = toLeafMapList(properties.get(ClusterResourceProvider.CREDENTIALS));
     if (credentialsSet != null) {
       for (Map<String, String> credentialMap : credentialsSet) {
         String alias = Strings.emptyToNull(credentialMap.get("alias"));
@@ -267,8 +265,9 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
         CredentialStoreType type = Enums.getIfPresent(CredentialStoreType.class, typeString.toUpperCase()).orNull();
         if (type == null) {
           throw new InvalidTopologyTemplateException(
-              String.format("credential.type [%s] is invalid. acceptable values: %s", typeString.toUpperCase(),
-                  Arrays.toString(CredentialStoreType.values())));
+            String.format("credential.type [%s] is invalid. acceptable values: %s", typeString.toUpperCase(),
+              Arrays.toString(CredentialStoreType.values())
+            ));
         }
         credentialHashMap.put(alias, new Credential(alias, principal, key, type));
       }
@@ -342,8 +341,7 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
    * @throws InvalidTopologyTemplateException  if any validation checks on properties fail
    */
   private void parseHostGroupInfo(Map<String, Object> properties) throws InvalidTopologyTemplateException {
-    Collection<Map<String, Object>> hostGroups =
-      (Collection<Map<String, Object>>) properties.get(HOSTGROUPS_PROPERTY);
+    Collection<Map<String, Object>> hostGroups = toBranchMapList(properties.get(HOSTGROUPS_PROPERTY));
 
     if (hostGroups == null || hostGroups.isEmpty()) {
       throw new InvalidTopologyTemplateException("'host_groups' element must be included in cluster create body");
@@ -372,12 +370,10 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
     getHostGroupInfo().put(name, hostGroupInfo);
 
     processHostCountAndPredicate(hostGroupProperties, hostGroupInfo);
-    processGroupHosts(name, (Collection<Map<String, String>>)
-      hostGroupProperties.get(HOSTGROUP_HOSTS_PROPERTY), hostGroupInfo);
+    processGroupHosts(name, toLeafMapList(hostGroupProperties.get(HOSTGROUP_HOSTS_PROPERTY)), hostGroupInfo);
 
     // don't set the parent configuration
-    hostGroupInfo.setConfiguration(configurationFactory.getConfiguration(
-      (Collection<Map<String, String>>) hostGroupProperties.get(CONFIGURATIONS_PROPERTY)));
+    hostGroupInfo.setConfiguration(ConfigurationFactory.toConfiguration(toLeafMapList(hostGroupProperties.get(CONFIGURATIONS_PROPERTY))));
   }
 
   /**
@@ -465,39 +461,31 @@ public class ProvisionClusterRequest extends BaseClusterRequest {
    * @param properties request properties
    * @throws InvalidTopologyTemplateException specified config recommendation strategy property fail validation
    */
-  private ConfigRecommendationStrategy parseConfigRecommendationStrategy(Map<String, Object> properties)
-    throws InvalidTopologyTemplateException {
-    if (properties.containsKey(CONFIG_RECOMMENDATION_STRATEGY)) {
-      String configRecommendationStrategy = String.valueOf(properties.get(CONFIG_RECOMMENDATION_STRATEGY));
-      Optional<ConfigRecommendationStrategy> configRecommendationStrategyOpt =
-        Enums.getIfPresent(ConfigRecommendationStrategy.class, configRecommendationStrategy);
-      if (!configRecommendationStrategyOpt.isPresent()) {
-        throw new InvalidTopologyTemplateException(String.format(
-          "Config recommendation strategy is not supported: %s", configRecommendationStrategy));
-      }
-      return configRecommendationStrategyOpt.get();
-    } else {
-      // default
-      return ConfigRecommendationStrategy.NEVER_APPLY;
-    }
+  private ConfigRecommendationStrategy parseConfigRecommendationStrategy(Map<String, Object> properties) throws InvalidTopologyTemplateException {
+    return getEnumValue(properties, CONFIG_RECOMMENDATION_STRATEGY, ConfigRecommendationStrategy.class, ConfigRecommendationStrategy.NEVER_APPLY);
   }
 
   /**
    * Parse Provision Action specified in RequestInfo properties.
    */
   private ProvisionAction parseProvisionAction(Map<String, Object> properties) throws InvalidTopologyTemplateException {
-    if (properties.containsKey(PROVISION_ACTION_PROPERTY)) {
-      String provisionActionStr = String.valueOf(properties.get(PROVISION_ACTION_PROPERTY));
-      Optional<ProvisionAction> provisionActionOptional =
-        Enums.getIfPresent(ProvisionAction.class, provisionActionStr);
+    return getEnumValue(properties, PROVISION_ACTION_PROPERTY, ProvisionAction.class, ProvisionAction.INSTALL_AND_START);
+  }
 
-      if (!provisionActionOptional.isPresent()) {
-        throw new InvalidTopologyTemplateException(String.format(
-          "Invalid provision_action specified in the template: %s", provisionActionStr));
-      }
-      return provisionActionOptional.get();
-    } else {
-      return ProvisionAction.INSTALL_AND_START;
+  private static <T extends Enum<T>> T getEnumValue(Map<String, ?> properties, String key, Class<T> enumType, T defaultValue)
+    throws InvalidTopologyTemplateException {
+
+    Object obj = properties.get(key);
+    if (obj == null) {
+      return defaultValue;
+    }
+
+    String name = String.valueOf(obj);
+    try {
+      return Enum.valueOf(enumType, name);
+    } catch (IllegalArgumentException e) {
+      String msg = String.format("Unsupported '%s' value: '%s'", key, name);
+      throw new InvalidTopologyTemplateException(msg);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index e3b5d6e..db00dac 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -1887,14 +1887,14 @@ public class ClusterImpl implements Cluster {
       throw new NullPointerException("User must be specified.");
     }
 
-    clusterGlobalLock.writeLock().lock();
-    try {
-      if (configs == null) {
-        return null;
-      }
+    if (configs == null) {
+      return null;
+    }
 
-      Iterator<Config> configIterator = configs.iterator();
+    Iterator<Config> configIterator = configs.iterator();
 
+    clusterGlobalLock.writeLock().lock();
+    try {
       while (configIterator.hasNext()) {
         Config config = configIterator.next();
         if (config == null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
index 4c23e2f..a12e066 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
@@ -32,7 +32,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
 
-import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.apache.ambari.server.AmbariException;
@@ -89,8 +88,6 @@ import org.apache.ambari.server.utils.RetryHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.Striped;
 import com.google.inject.Provider;
 
@@ -409,7 +406,7 @@ public class AmbariContext {
         createConfigGroupsAndRegisterHost(topology, groupName);
       }
     } catch (Exception e) {
-      LOG.error("Unable to register config group for host: ", e);
+      LOG.error("Unable to register config group for host {}", hostName, e);
       throw new RuntimeException("Unable to register config group for host: " + hostName);
     }
     finally {
@@ -661,13 +658,11 @@ public class AmbariContext {
    * and the hosts associated with the host group are assigned to the config group.
    */
   private void createConfigGroupsAndRegisterHost(ClusterTopology topology, String groupName) throws AmbariException {
-
     Map<Service, Map<String, Config>> groupConfigs = new HashMap<>();
 
-
     // only get user provided configuration for host group per service which includes only CCT/HG and BP/HG properties
-    Collection<Service> serviceConfigurations = topology.getHostGroupInfo().get(groupName).getServiceConfigs();
-    serviceConfigurations.forEach(service -> {
+    Collection<Service> services = topology.getHostGroupInfo().get(groupName).getServiceConfigs();
+    for (Service service : services) {
       Map<String, Map<String, String>> userProvidedGroupProperties = service.getConfiguration().getProperties();
 
       // iterate over topo host group configs which were defined in
@@ -675,55 +670,39 @@ public class AmbariContext {
         String type = entry.getKey();
         Config config = configFactory.createReadOnly(type, groupName, entry.getValue(), null);
         //todo: attributes
-        Map<String, Config> serviceConfigs = groupConfigs.get(service);
-        if (serviceConfigs == null) {
-          serviceConfigs = new HashMap<>();
-          groupConfigs.put(service, serviceConfigs);
-        }
-        serviceConfigs.put(type, config);
+        groupConfigs.computeIfAbsent(service, __ -> new HashMap<>())
+          .put(type, config);
       }
-    });
+    }
 
     String bpName = topology.getBlueprint().getName();
     for (Map.Entry<Service, Map<String, Config>> entry : groupConfigs.entrySet()) {
       Service service = entry.getKey();
       Map<String, Config> serviceConfigs = entry.getValue();
       String absoluteGroupName = getConfigurationGroupName(bpName, groupName);
-      Collection<String> groupHosts;
-
-      groupHosts = topology.getHostGroupInfo().
-          get(groupName).getHostNames();
 
       // remove hosts that are not assigned to the cluster yet
-      String clusterName = null;
-      try {
-        clusterName = getClusterName(topology.getClusterId());
-      } catch (AmbariException e) {
-        LOG.error("Cannot get cluster name for clusterId = " + topology.getClusterId(), e);
-        throw new RuntimeException(e);
-      }
+      Long clusterId = topology.getClusterId();
+      String clusterName = getClusterName(clusterId);
+      Set<String> groupHosts = topology.getHostGroupInfo().get(groupName).getHostNames();
+      Set<String> clusterHosts = getController().getClusters().getHostsForCluster(clusterName).keySet();
+      groupHosts.retainAll(clusterHosts);
 
-      final Map<String, Host> clusterHosts = getController().getClusters().getHostsForCluster(clusterName);
-      Iterable<String> filteredGroupHosts = Iterables.filter(groupHosts, new com.google.common.base.Predicate<String>() {
-        @Override
-        public boolean apply(@Nullable String groupHost) {
-          return clusterHosts.containsKey(groupHost);
-        }
-      });
+      LOG.debug("Creating config group {} ");
 
       ConfigGroupRequest request = new ConfigGroupRequest(null, clusterName,
         absoluteGroupName, service.getName(), service.getServiceGroupName(), service.getName(), "Host Group Configuration",
-        Sets.newHashSet(filteredGroupHosts), serviceConfigs);
+        groupHosts, serviceConfigs);
 
-      // get the config group provider and create config group resource
       ConfigGroupResourceProvider configGroupProvider = (ConfigGroupResourceProvider)
           getClusterController().ensureResourceProvider(Resource.Type.ConfigGroup);
 
       try {
         configGroupProvider.createResources(Collections.singleton(request));
       } catch (Exception e) {
-        LOG.error("Failed to create new configuration group: " + e);
-        throw new RuntimeException("Failed to create new configuration group: " + e, e);
+        String msg = String.format("Failed to create new configuration group '%s'", absoluteGroupName);
+        LOG.error(msg, e);
+        throw new RuntimeException(msg, e);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
index 404068d..8c6198f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
@@ -70,8 +70,6 @@ public class BlueprintFactory {
   protected static final String SETTINGS_PROPERTY_ID = "settings";
 
   private static BlueprintDAO blueprintDAO;
-  private ConfigurationFactory configFactory = new ConfigurationFactory();
-
   private final StackFactory stackFactory;
 
   public BlueprintFactory() {
@@ -106,7 +104,7 @@ public class BlueprintFactory {
 
     Stack stack = createStack(properties);
     Collection<HostGroup> hostGroups = processHostGroups(name, stack, properties);
-    Configuration configuration = configFactory.getConfiguration((Collection<Map<String, String>>)
+    Configuration configuration = ConfigurationFactory.toConfiguration((Collection<Map<String, String>>)
             properties.get(CONFIGURATION_PROPERTY_ID));
     Setting setting =  SettingFactory.getSetting((Collection<Map<String, Object>>) properties.get(SETTINGS_PROPERTY_ID));
 
@@ -149,9 +147,9 @@ public class BlueprintFactory {
 
       Collection<Map<String, String>> configProps = (Collection<Map<String, String>>)
           hostGroupProperties.get(CONFIGURATION_PROPERTY_ID);
+      Configuration configuration = ConfigurationFactory.toConfiguration(configProps);
 
       Collection<Component> components = processHostGroupComponents(stack, hostGroupName, componentProps);
-      Configuration configuration = configFactory.getConfiguration(configProps);
       String cardinality = String.valueOf(hostGroupProperties.get(HOST_GROUP_CARDINALITY_PROPERTY_ID));
 
       HostGroup group = new HostGroupImpl(hostGroupName, bpName, stack, components, configuration, cardinality);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
index 93dba0c..0dd55e8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
@@ -52,7 +52,7 @@ public class BlueprintImplV2 implements BlueprintV2 {
   private Collection<RepositoryVersion> repositoryVersions = new ArrayList<>(0);
   private Map<String, ServiceGroup> serviceGroups;
   private Setting setting;
-  private Configuration configuration;
+  private final Configuration configuration = new Configuration(new HashMap<>(), new HashMap<>());;
 
   // Transient fields
   @JsonIgnore
@@ -255,13 +255,6 @@ public class BlueprintImplV2 implements BlueprintV2 {
   @Override
   @JsonIgnore
   public Configuration getConfiguration() {
-    if (null == configuration) {
-      configuration = new Configuration(new HashMap<>(), new HashMap<>());
-      getServiceGroups().forEach( sg -> addChildConfiguration(configuration, sg.getConfiguration()) );
-      getHostGroups().values().forEach(
-        hg -> hg.getComponents().forEach(
-          c -> addChildConfiguration(configuration, c.getConfiguration())));
-    }
     return configuration;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
index eed0b68..9921430 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
@@ -173,7 +173,6 @@ public interface BlueprintV2 {
    *
    * @return blueprint cluster scoped configuration
    */
-  @Deprecated
   Configuration getConfiguration();
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
index 3542ef2..e16ba86 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
@@ -75,8 +75,6 @@ public class BlueprintV2Factory {
   private static BlueprintV2DAO blueprintDAO;
   private static RepositoryVersionDAO repositoryVersionDAO;
 
-  private ConfigurationFactory configFactory = new ConfigurationFactory();
-
   private StackV2Factory stackFactory;
 
   protected BlueprintV2Factory() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java
index 96550d5..a4abe60 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java
@@ -76,15 +76,14 @@ public class ClusterConfigurationRequest {
     this.ambariContext = ambariContext;
     this.clusterTopology = clusterTopology;
     BlueprintV2 blueprint = clusterTopology.getBlueprint();
-    // set initial configuration (not topology resolved)
+
     //TODO set up proper ConfigurationContext
-    ConfigurationContext configurationContext = new ConfigurationContext(blueprint.getStacks().iterator().next(), clusterTopology
-            .getConfiguration());
+    ConfigurationContext configurationContext = new ConfigurationContext(blueprint.getStacks().iterator().next(), clusterTopology.getConfiguration());
     this.configurationProcessor = new BlueprintConfigurationProcessor(clusterTopology, configurationContext);
     this.stackAdvisorBlueprintProcessor = stackAdvisorBlueprintProcessor;
     removeOrphanConfigTypes();
     if (setInitial) {
-      setConfigurationsOnCluster(clusterTopology, TopologyManager.INITIAL_CONFIG_TAG, Collections.emptySet());
+      setConfigurationsOnCluster(TopologyManager.INITIAL_CONFIG_TAG, Collections.emptySet());
     }
   }
 
@@ -136,8 +135,6 @@ public class ClusterConfigurationRequest {
     // this will update the topo cluster config and all host group configs in the cluster topology
     Set<String> updatedConfigTypes = new HashSet<>();
 
-    Map<String, Map<String, String>> userProvidedConfigurations = clusterTopology.getConfiguration().getFullProperties(1);
-
     try {
       if (configureSecurity) {
         Configuration clusterConfiguration = clusterTopology.getConfiguration();
@@ -148,6 +145,7 @@ public class ClusterConfigurationRequest {
       // obtain recommended configurations before config updates
       if (!ConfigRecommendationStrategy.NEVER_APPLY.equals(this.clusterTopology.getConfigRecommendationStrategy())) {
         // get merged properties form Blueprint & cluster template (this doesn't contains stack default values)
+        Map<String, Map<String, String>> userProvidedConfigurations = clusterTopology.getConfiguration().getFullProperties(1);
         stackAdvisorBlueprintProcessor.adviseConfiguration(this.clusterTopology, userProvidedConfigurations);
       }
 
@@ -157,7 +155,7 @@ public class ClusterConfigurationRequest {
       LOG.error("An exception occurred while doing configuration topology update: " + e, e);
     }
 
-    setConfigurationsOnCluster(clusterTopology, TopologyManager.TOPOLOGY_RESOLVED_TAG, updatedConfigTypes);
+    setConfigurationsOnCluster(TopologyManager.TOPOLOGY_RESOLVED_TAG, updatedConfigTypes);
   }
 
   private Set<String> configureKerberos(Configuration clusterConfiguration, Map<String, Map<String, String>> existingConfigurations) throws AmbariException {
@@ -345,46 +343,37 @@ public class ClusterConfigurationRequest {
 
   /**
    * Set all configurations on the cluster resource.
-   * @param clusterTopology  cluster topology
    * @param tag              config tag
    */
-  public void setConfigurationsOnCluster(ClusterTopology clusterTopology, String tag, Set<String> updatedConfigTypes)  {
+  private void setConfigurationsOnCluster(String tag, Set<String> updatedConfigTypes)  {
     //todo: also handle setting of host group scoped configuration which is updated by config processor
     List<BlueprintServiceConfigRequest> configurationRequests = new LinkedList<>();
 
     BlueprintV2 blueprint = clusterTopology.getBlueprint();
-    Configuration clusterConfiguration = clusterTopology.getConfiguration();
 
     for (Service service : blueprint.getAllServices()) {
       //todo: remove intermediate request type
       // one bp config request per service
-      BlueprintServiceConfigRequest blueprintConfigRequest = new BlueprintServiceConfigRequest(service.getType());
-      String serviceStackId = service.getStackId();
-      StackV2 serviceStack = blueprint.getStackById(serviceStackId);
-      for (String serviceConfigType : serviceStack.getAllConfigurationTypes(service.getType())) {
-        Set<String> excludedConfigTypes = serviceStack.getExcludedConfigurationTypes(service.getType());
-        if (!excludedConfigTypes.contains(serviceConfigType)) {
-          // skip handling of cluster-env here
-          if (! serviceConfigType.equals("cluster-env")) {
-            if (clusterConfiguration.getFullProperties().containsKey(serviceConfigType)) {
-              blueprintConfigRequest.addConfigElement(serviceConfigType,
-                  clusterConfiguration.getFullProperties().get(serviceConfigType),
-                  clusterConfiguration.getFullAttributes().get(serviceConfigType));
-            }
-          }
+      BlueprintServiceConfigRequest serviceConfigRequest = new BlueprintServiceConfigRequest(service.getType());
+      StackV2 serviceStack = service.getStack();
+      Map<String, Map<String, String>> serviceProperties = service.getConfiguration().getFullProperties();
+      Map<String, Map<String, Map<String, String>>> serviceAttributes = service.getConfiguration().getFullAttributes();
+
+      for (String configType : serviceStack.getConfigurationTypes(service.getType())) {
+        if (!configType.equals("cluster-env")) {
+          serviceConfigRequest.addConfigElement(configType, serviceProperties.get(configType), serviceAttributes.get(configType));
         }
       }
 
-      configurationRequests.add(blueprintConfigRequest);
+      configurationRequests.add(serviceConfigRequest);
     }
 
     // since the stack returns "cluster-env" with each service's config ensure that only one
     // ClusterRequest occurs for the global cluster-env configuration
     BlueprintServiceConfigRequest globalConfigRequest = new BlueprintServiceConfigRequest("GLOBAL-CONFIG");
-    Map<String, String> clusterEnvProps = clusterConfiguration.getFullProperties().get("cluster-env");
-    Map<String, Map<String, String>> clusterEnvAttributes = clusterConfiguration.getFullAttributes().get("cluster-env");
-
-    globalConfigRequest.addConfigElement("cluster-env", clusterEnvProps,clusterEnvAttributes);
+    Map<String, String> properties = clusterTopology.getConfiguration().getFullProperties().get("cluster-env");
+    Map<String, Map<String, String>> attributes = clusterTopology.getConfiguration().getFullAttributes().get("cluster-env");
+    globalConfigRequest.addConfigElement("cluster-env", properties, attributes);
     configurationRequests.add(globalConfigRequest);
 
     setConfigurationsOnCluster(configurationRequests, tag, updatedConfigTypes);
@@ -494,9 +483,7 @@ public class ClusterConfigurationRequest {
   private static class BlueprintServiceConfigRequest {
 
     private final String serviceName;
-
-    private List<BlueprintServiceConfigElement> configElements =
-      new LinkedList<>();
+    private final List<BlueprintServiceConfigElement> configElements = new LinkedList<>();
 
     BlueprintServiceConfigRequest(String serviceName) {
       this.serviceName = serviceName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopology.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopology.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopology.java
index 289f053..eea8e30 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopology.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopology.java
@@ -48,7 +48,7 @@ public interface ClusterTopology {
   /**
    * Get the blueprint associated with the cluster.
    *
-   * @return assocaited blueprint
+   * @return associated blueprint
    */
   BlueprintV2 getBlueprint();
 
@@ -147,7 +147,6 @@ public interface ClusterTopology {
    * Install the specified host.
    *
    * @param hostName  host name
-   * @param skipInstallTaskCreate
    * @return install response
    */
   RequestStatusResponse installHost(String hostName, boolean skipInstallTaskCreate, boolean skipFailure);
@@ -179,7 +178,6 @@ public interface ClusterTopology {
 
   /**
    * Removes host from stateful ClusterTopology
-   * @param hostname
    */
   void removeHost(String hostname);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java
index db3f29b..33673be 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java
@@ -19,11 +19,13 @@
 
 package org.apache.ambari.server.topology;
 
+import static java.util.stream.Collectors.toMap;
 import static org.apache.ambari.server.controller.internal.ProvisionAction.INSTALL_AND_START;
 import static org.apache.ambari.server.controller.internal.ProvisionAction.INSTALL_ONLY;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -34,6 +36,7 @@ import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.internal.ConfigurationContext;
 import org.apache.ambari.server.controller.internal.ProvisionAction;
 import org.apache.ambari.server.controller.internal.ProvisionClusterRequest;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,18 +47,18 @@ import org.slf4j.LoggerFactory;
 public class ClusterTopologyImpl implements ClusterTopology {
 
   private final static Logger LOG = LoggerFactory.getLogger(ClusterTopologyImpl.class);
+  private final Configuration configuration;
 
   private Long clusterId;
 
   //todo: currently topology is only associated with a single bp
   //todo: this will need to change to allow usage of multiple bp's for the same cluster
   //todo: for example: provision using bp1 and scale using bp2
-  private BlueprintV2 blueprint;
-  private Configuration configuration;
-  private Collection<Service> serviceConfigs;
+  private final BlueprintV2 blueprint;
+  private final Collection<Service> serviceConfigs;
   private ConfigRecommendationStrategy configRecommendationStrategy;
   private ProvisionAction provisionAction = ProvisionAction.INSTALL_AND_START;
-  private Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
+  private final Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
   private final Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<>();
   private final AmbariContext ambariContext;
   private final String defaultPassword;
@@ -66,6 +69,8 @@ public class ClusterTopologyImpl implements ClusterTopology {
     this.clusterId = topologyRequest.getClusterId();
     // provision cluster currently requires that all hostgroups have same BP so it is ok to use root level BP here
     this.blueprint = topologyRequest.getBlueprint();
+    this.configuration = blueprint.getConfiguration();
+    this.configuration.setParentConfiguration(new Configuration(Collections.singletonMap("cluster-env", getDefaultClusterSettings()), new HashMap<>()));
     this.serviceConfigs = topologyRequest.getServiceConfigs();
     if (topologyRequest instanceof ProvisionClusterRequest) {
       this.defaultPassword = ((ProvisionClusterRequest) topologyRequest).getDefaultPassword();
@@ -75,15 +80,6 @@ public class ClusterTopologyImpl implements ClusterTopology {
 
     registerHostGroupInfo(topologyRequest.getHostGroupInfo());
 
-    // merge service configs into global cluster configs
-    Map<String, Map<String, String>> properties = new HashMap<>();
-    Map<String, Map<String, Map<String, String>>> attributes = new HashMap<>();
-    serviceConfigs.forEach(service -> {
-      properties.putAll(service.getConfiguration().getProperties());
-      attributes.putAll(service.getConfiguration().getAttributes());
-    });
-    configuration = new Configuration(properties, attributes);
-
     // todo extract validation to specialized service
     validateTopology();
     this.ambariContext = ambariContext;
@@ -110,7 +106,6 @@ public class ClusterTopologyImpl implements ClusterTopology {
   }
 
   @Override
-  @Deprecated
   public Configuration getConfiguration() {
     return configuration;
   }
@@ -138,13 +133,11 @@ public class ClusterTopologyImpl implements ClusterTopology {
 
   @Override
   public String getHostGroupForHost(String hostname) {
-    for (HostGroupInfo groupInfo : hostGroupInfoMap.values() ) {
-      if (groupInfo.getHostNames().contains(hostname)) {
-        // a host can only be associated with a single host group
-        return groupInfo.getHostGroupName();
-      }
-    }
-    return null;
+    return hostGroupInfoMap.values().stream()
+      .filter(g -> g.getHostNames().contains(hostname))
+      .findAny()
+      .map(HostGroupInfo::getHostGroupName)
+      .orElse(null);
   }
 
   //todo: host info?
@@ -327,44 +320,46 @@ public class ClusterTopologyImpl implements ClusterTopology {
     return defaultPassword;
   }
 
-  private void registerHostGroupInfo(Map<String, HostGroupInfo> requestedHostGroupInfoMap) throws InvalidTopologyException {
-    LOG.debug("Registering requested host group information for {} hostgroups", requestedHostGroupInfoMap.size());
-    checkForDuplicateHosts(requestedHostGroupInfoMap);
+  private void registerHostGroupInfo(Map<String, HostGroupInfo> requestHostGroups) throws InvalidTopologyException {
+    LOG.debug("Registering requested host group information for {} host groups", requestHostGroups.size());
+    checkForDuplicateHosts(requestHostGroups);
 
-    for (HostGroupInfo requestedHostGroupInfo : requestedHostGroupInfoMap.values()) {
-      String hostGroupName = requestedHostGroupInfo.getHostGroupName();
+    for (HostGroupInfo requestHostGroup : requestHostGroups.values()) {
+      String hostGroupName = requestHostGroup.getHostGroupName();
 
       //todo: doesn't support using a different blueprint for update (scaling)
-      HostGroupV2 baseHostGroup = getBlueprint().getHostGroup(hostGroupName);
-
-      if (baseHostGroup == null) {
-        throw new IllegalArgumentException("Invalid host_group specified: " + hostGroupName +
-            ".  All request host groups must have a corresponding host group in the specified blueprint");
+      HostGroupV2 bpHostGroup = getBlueprint().getHostGroup(hostGroupName);
+      if (bpHostGroup == null) {
+        String msg = String.format("The host group '%s' is not present in the blueprint '%s'", hostGroupName, blueprint.getName());
+        LOG.error(msg);
+        throw new InvalidTopologyException(msg);
       }
+
       //todo: split into two methods
       HostGroupInfo currentHostGroupInfo = hostGroupInfoMap.get(hostGroupName);
       if (currentHostGroupInfo == null) {
         // blueprint host group config
-        Configuration bpHostGroupConfig = baseHostGroup.getConfiguration();
+        Configuration bpHostGroupConfig = bpHostGroup.getConfiguration();
         // parent config is BP host group config but with parent set to topology cluster scoped config
-        Configuration parentConfiguration = new Configuration(bpHostGroupConfig.getProperties(),
-            bpHostGroupConfig.getAttributes(), getConfiguration());
+        Configuration parentConfiguration = new Configuration(bpHostGroupConfig, getConfiguration());
 
-        requestedHostGroupInfo.getConfiguration().setParentConfiguration(parentConfiguration);
-        hostGroupInfoMap.put(hostGroupName, requestedHostGroupInfo);
+        requestHostGroup.getConfiguration().setParentConfiguration(parentConfiguration);
+        requestHostGroup.setServiceConfigs(bpHostGroup.getServices());
+
+        hostGroupInfoMap.put(hostGroupName, requestHostGroup);
       } else {
         // Update.  Either add hosts or increment request count
-        if (!requestedHostGroupInfo.getHostNames().isEmpty()) {
+        if (!requestHostGroup.getHostNames().isEmpty()) {
           try {
             // this validates that hosts aren't already registered with groups
-            addHostsToTopology(requestedHostGroupInfo);
+            addHostsToTopology(requestHostGroup);
           } catch (NoSuchHostGroupException e) {
             //todo
             throw new InvalidTopologyException("Attempted to add hosts to unknown host group: " + hostGroupName);
           }
         } else {
           currentHostGroupInfo.setRequestedCount(
-              currentHostGroupInfo.getRequestedHostCount() + requestedHostGroupInfo.getRequestedHostCount());
+              currentHostGroupInfo.getRequestedHostCount() + requestHostGroup.getRequestedHostCount());
         }
         //todo: throw exception in case where request attempts to modify HG configuration in scaling operation
       }
@@ -411,4 +406,10 @@ public class ClusterTopologyImpl implements ClusterTopology {
         " Be aware that host names are converted to lowercase, case differences do not matter in Ambari deployments.");
     }
   }
+
+  private static Map<String, String> getDefaultClusterSettings() { // TODO temporary
+    return AmbariContext.getController().getAmbariMetaInfo().getClusterProperties().stream()
+      .collect(toMap(PropertyInfo::getName, PropertyInfo::getValue));
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/Configuration.java
index 28dbbaa..6adcf18 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/Configuration.java
@@ -45,6 +45,10 @@ public class Configuration {
    */
   private Configuration parentConfiguration;
 
+  public Configuration(Configuration config, Configuration parent) {
+    this(config.getProperties(), config.getAttributes(), parent);
+  }
+
   /**
    * Constructor.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/ConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ConfigurationFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ConfigurationFactory.java
index 7f9a06f..63a96e5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ConfigurationFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ConfigurationFactory.java
@@ -33,7 +33,7 @@ public class ConfigurationFactory {
   private static final String SCHEMA_IS_NOT_SUPPORTED_MESSAGE =
       "Provided configuration format is not supported";
 
-  public Configuration getConfiguration(Collection<Map<String, String>> configProperties) {
+  public static Configuration toConfiguration(Collection<Map<String, String>> configProperties) {
     Map<String, Map<String, String>> properties = new HashMap<>();
     Map<String, Map<String, Map<String, String>>> attributes = new HashMap<>();
     Configuration configuration = new Configuration(properties, attributes);
@@ -51,7 +51,7 @@ public class ConfigurationFactory {
     return configuration;
   }
 
-  private ConfigurationStrategy decidePopulationStrategy(Map<String, String> configuration) {
+  private static ConfigurationStrategy decidePopulationStrategy(Map<String, String> configuration) {
     if (configuration != null && !configuration.isEmpty()) {
       String keyEntry = configuration.keySet().iterator().next();
       String[] keyNameTokens = keyEntry.split("/");
@@ -70,6 +70,16 @@ public class ConfigurationFactory {
     }
   }
 
+  @SuppressWarnings("unchecked")
+  public static Collection<Map<String, Object>> toBranchMapList(Object o) {
+    return (Collection<Map<String, Object>>) o;
+  }
+
+  @SuppressWarnings("unchecked")
+  public static Collection<Map<String, String>> toLeafMapList(Object o) {
+    return (Collection<Map<String, String>>) o;
+  }
+
   /**
    * The structure of blueprints is evolving where multiple resource
    * structures are to be supported. This class abstracts the population

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupInfo.java
index 7cbdd98..8ddc088 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupInfo.java
@@ -18,10 +18,14 @@
 
 package org.apache.ambari.server.topology;
 
+import static java.util.stream.Collectors.toSet;
+
 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.api.predicate.InvalidQueryException;
 import org.apache.ambari.server.api.predicate.PredicateCompiler;
@@ -39,7 +43,7 @@ public class HostGroupInfo {
   /**
    * predicate compiler
    */
-  private static PredicateCompiler predicateCompiler = new PredicateCompiler();
+  private static final PredicateCompiler PREDICATE_COMPILER = new PredicateCompiler();
 
   /**
    * host group name
@@ -48,7 +52,7 @@ public class HostGroupInfo {
   /**
    * hosts contained associated with the host group
    */
-  private final Collection<String> hostNames = new HashSet<>();
+  private final Set<String> hostNames = Collections.synchronizedSet(new HashSet<>());
 
   /**
    * maps host names to rack information
@@ -56,25 +60,27 @@ public class HostGroupInfo {
    */
   private final Map<String, String> hostRackInfo = new HashMap<>();
 
+  private Configuration configuration;
+
   /**
    * List of services
    */
-  protected Collection<Service> serviceConfigs;
+  private Collection<Service> serviceConfigs = Collections.emptySet();
 
   /**
    * explicitly specified host count
    */
-  private int requested_count = 0;
+  private int requestedCount;
 
   /**
    * explicitly specified host predicate string
    */
-  String predicateString;
+  private String predicateString;
 
   /**
    * compiled host predicate
    */
-  Predicate predicate;
+  private Predicate predicate;
 
 
   /**
@@ -102,9 +108,7 @@ public class HostGroupInfo {
    *
    * @return collection of user specified host names; will never be null
    */
-  public Collection<String> getHostNames() {
-    // needs to be an exclusive lock, not a read lock because collection
-    // shouldn't change while copying elements into the new set instance
+  public Set<String> getHostNames() {
     synchronized (hostNames) {
       return new HashSet<>(hostNames);
     }
@@ -114,6 +118,10 @@ public class HostGroupInfo {
     return serviceConfigs;
   }
 
+  public void setServiceConfigs(Collection<Service> serviceConfigs) {
+    this.serviceConfigs = serviceConfigs;
+  }
+
   /**
    * Get the requested host count.
    * This is either the user specified value or
@@ -122,9 +130,7 @@ public class HostGroupInfo {
    * @return number of requested hosts for the group
    */
   public int getRequestedHostCount() {
-    synchronized (hostNames) {
-      return requested_count == 0 ? hostNames.size() : requested_count;
-    }
+    return requestedCount == 0 ? hostNames.size() : requestedCount;
   }
 
   /**
@@ -133,13 +139,12 @@ public class HostGroupInfo {
    * @param hostName  the host name to associate with the host group
    */
   public void addHost(String hostName) {
-    synchronized(hostNames) {
-      String lowerHostName = hostName.toLowerCase();
-      if (!hostName.equals(lowerHostName)) {
-        LOG.warn("Host name {} contains upper case letters, will be converted to lowercase!", hostName );
-      }
-      hostNames.add(lowerHostName);
+    String lowerHostName = hostName.toLowerCase();
+    if (!hostName.equals(lowerHostName)) {
+      LOG.warn("Host name {} contains upper case letters, will be converted to lowercase!", hostName );
     }
+
+    hostNames.add(lowerHostName);
   }
 
   /**
@@ -148,20 +153,20 @@ public class HostGroupInfo {
    * @param hosts  collection of host names to associate with the host group
    */
   public void addHosts(Collection<String> hosts) {
-    synchronized (hostNames) {
-      for (String host : hosts) {
-        addHost(host);
-      }
-    }
+    Collection<String> lower = hosts.stream()
+      .map(String::toLowerCase)
+      .collect(toSet());
+
+    hostNames.addAll(lower);
   }
 
   /**
    * Set the requested host count for the host group.
    *
-   * @param num  requested host count
+   * @param count requested host count
    */
-  public void setRequestedCount(int num) {
-    requested_count = num;
+  public void setRequestedCount(int count) {
+    requestedCount = count;
   }
 
   /**
@@ -170,7 +175,7 @@ public class HostGroupInfo {
    * @param configuration configuration instance
    */
   public void setConfiguration(Configuration configuration) {
-
+    this.configuration = configuration;
   }
 
   /**
@@ -179,20 +184,18 @@ public class HostGroupInfo {
    * @return associated host group scoped configuration or null if no configuration
    *         is specified for the host group
    */
-  @Deprecated
   public Configuration getConfiguration() {
-    return null;
+    return configuration;
   }
 
   /**
    * Set the host predicate for the host group.
    *
    * @param predicateString  host predicate as a string
-   *
    * @throws InvalidQueryException if compilation of the predicate fails
    */
   public void setPredicate(String predicateString) throws InvalidQueryException {
-    this.predicate = predicateCompiler.compile(predicateString);
+    this.predicate = PREDICATE_COMPILER.compile(predicateString);
     this.predicateString = predicateString;
   }
 
@@ -239,12 +242,9 @@ public class HostGroupInfo {
 
   /**
    * Removes hostname from group
-   * @param hostname
    */
   public void removeHost(String hostname) {
-    synchronized (hostNames) {
-      hostNames.remove(hostname);
-    }
+    hostNames.remove(hostname);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupV2.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupV2.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupV2.java
index 8da24bd..4d3d1f0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupV2.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/HostGroupV2.java
@@ -48,7 +48,7 @@ public interface HostGroupV2 {
 
   /**
    * Get the fully qualified host group name in the form of
-   * blueprintName:hostgroupName
+   * blueprintName:hostGroupName
    *
    * @return fully qualified host group name
    */
@@ -122,7 +122,6 @@ public interface HostGroupV2 {
    *
    * @return host group configuration
    */
-  @Deprecated
   Configuration getConfiguration();
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/Service.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/Service.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/Service.java
index 90b4764..e80396f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/Service.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/Service.java
@@ -130,6 +130,7 @@ public class Service implements Configurable {
 
   public void setStackFromBlueprint(BlueprintV2 blueprint) {
     this.stack = blueprint.getStackById(this.stackId);
+    configuration.setParentConfiguration(stack.getConfiguration());
   }
 
   public void setConfiguration(Configuration configuration) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/ClusterConfigTypeValidator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/ClusterConfigTypeValidator.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/ClusterConfigTypeValidator.java
index 7ac75e9..20fc5f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/ClusterConfigTypeValidator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/ClusterConfigTypeValidator.java
@@ -36,7 +36,7 @@ public class ClusterConfigTypeValidator implements TopologyValidator {
   public void validate(ClusterTopology topology) throws InvalidTopologyException {
 
     // config types in from the request / configuration is always set in the request instance
-    Set<String> topologyClusterConfigTypes = new HashSet(topology.getConfiguration().getAllConfigTypes());
+    Set<String> topologyClusterConfigTypes = new HashSet<>(topology.getConfiguration().getAllConfigTypes());
     LOGGER.debug("Cluster config types: {}", topologyClusterConfigTypes);
 
     if (topologyClusterConfigTypes.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b91ad486/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurationFactoryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurationFactoryTest.java
index 14614fd..270b07c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurationFactoryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurationFactoryTest.java
@@ -36,8 +36,7 @@ public class ConfigurationFactoryTest {
 
   @Test
   public void testOldSyntax() throws Exception {
-    ConfigurationFactory factory = new ConfigurationFactory();
-    Configuration configuration = factory.getConfiguration(getOldSyntaxConfigProps());
+    Configuration configuration = ConfigurationFactory.toConfiguration(getOldSyntaxConfigProps());
 
     assertEquals(2, configuration.getProperties().size());
 
@@ -55,8 +54,7 @@ public class ConfigurationFactoryTest {
 
   @Test
   public void testNewSyntax() throws Exception {
-    ConfigurationFactory factory = new ConfigurationFactory();
-    Configuration configuration = factory.getConfiguration(getNewSyntaxConfigProps());
+    Configuration configuration = ConfigurationFactory.toConfiguration(getNewSyntaxConfigProps());
 
     // properties
     Map<String, Map<String, String>> properties = configuration.getProperties();