ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jspei...@apache.org
Subject [2/2] git commit: AMBARI-6015. Provide topology validation when creating blueprint.
Date Tue, 03 Jun 2014 21:13:25 GMT
AMBARI-6015. Provide topology validation when creating blueprint.


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

Branch: refs/heads/trunk
Commit: ac8641fb30a9acd2e5426f16285716ced78a41c0
Parents: e81706f
Author: John Speidel <jspeidel@hortonworks.com>
Authored: Tue Jun 3 16:16:40 2014 -0400
Committer: John Speidel <jspeidel@hortonworks.com>
Committed: Tue Jun 3 17:13:12 2014 -0400

----------------------------------------------------------------------
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/BaseBlueprintProcessor.java        | 968 +++++++++++++++++++
 .../internal/BlueprintResourceProvider.java     | 102 +-
 .../internal/ClusterResourceProvider.java       | 497 +---------
 .../internal/DefaultProviderModule.java         |   2 -
 .../server/orm/entities/HostGroupEntity.java    |   9 +
 .../ambari/server/state/DependencyInfo.java     |   8 +
 .../src/main/resources/properties.json          |   3 +-
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml |  10 -
 .../HDP/1.3.2/services/ZOOKEEPER/metainfo.xml   |   2 +-
 .../HDP/2.0.6/services/FLUME/metainfo.xml       |   1 +
 .../HDP/2.0.6/services/GANGLIA/metainfo.xml     |   5 +
 .../HDP/2.0.6/services/HBASE/metainfo.xml       |   2 +
 .../stacks/HDP/2.0.6/services/HDFS/metainfo.xml |  10 +-
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |  11 +-
 .../HDP/2.0.6/services/ZOOKEEPER/metainfo.xml   |   2 +-
 .../stacks/HDP/2.1/services/FALCON/metainfo.xml |   2 +
 .../stacks/HDP/2.1/services/TEZ/metainfo.xml    |   1 +
 .../internal/BlueprintResourceProviderTest.java |  51 +-
 .../internal/ClusterResourceProviderTest.java   |  59 +-
 20 files changed, 1140 insertions(+), 607 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 3e5a224..a62b0d4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -138,6 +138,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new RequestScheduleResourceProvider(propertyIds, keyPropertyIds, managementController);
       case HostComponentProcess:
         return new HostComponentProcessResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case Blueprint:
+        return new BlueprintResourceProvider(propertyIds, keyPropertyIds, managementController);
       default:
         throw new IllegalArgumentException("Unknown type " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java
new file mode 100644
index 0000000..3f5a7c4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java
@@ -0,0 +1,968 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.StackConfigurationRequest;
+import org.apache.ambari.server.controller.StackConfigurationResponse;
+import org.apache.ambari.server.controller.StackServiceComponentRequest;
+import org.apache.ambari.server.controller.StackServiceComponentResponse;
+import org.apache.ambari.server.controller.StackServiceRequest;
+import org.apache.ambari.server.controller.StackServiceResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.orm.dao.BlueprintDAO;
+import org.apache.ambari.server.orm.entities.BlueprintConfigEntity;
+import org.apache.ambari.server.orm.entities.BlueprintEntity;
+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.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.DependencyInfo;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Base blueprint processing resource provider.
+ */
+public abstract class BaseBlueprintProcessor extends AbstractControllerResourceProvider {
+
+  /**
+   * Data access object used to obtain blueprint entities.
+   */
+  protected static BlueprintDAO blueprintDAO;
+
+  /**
+   * Stack related information.
+   */
+  protected static AmbariMetaInfo stackInfo;
+
+
+  protected BaseBlueprintProcessor(Set<String> propertyIds,
+                                   Map<Resource.Type, String> keyPropertyIds,
+                                   AmbariManagementController managementController) {
+
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  /**
+   * Get host groups which contain a component.
+   *
+   * @param component   component name
+   * @param hostGroups  collection of host groups to check
+   *
+   * @return collection of host groups which contain the specified component
+   */
+  protected Collection<HostGroup> getHostGroupsForComponent(String component, Collection<HostGroup> hostGroups) {
+    Collection<HostGroup> resultGroups = new HashSet<HostGroup>();
+    for (HostGroup group : hostGroups ) {
+      if (group.getComponents().contains(component)) {
+        resultGroups.add(group);
+      }
+    }
+    return resultGroups;
+  }
+
+  /**
+   * Parse blueprint host groups.
+   *
+   * @param blueprint  associated blueprint
+   * @param stack      associated stack
+   *
+   * @return map of host group name to host group
+   */
+  protected Map<String, HostGroup> parseBlueprintHostGroups(BlueprintEntity blueprint, Stack stack) {
+    Map<String, HostGroup> mapHostGroups = new HashMap<String, HostGroup>();
+
+    for (HostGroupEntity hostGroup : blueprint.getHostGroups()) {
+      mapHostGroups.put(hostGroup.getName(), new HostGroup(hostGroup, stack));
+    }
+    return mapHostGroups;
+  }
+
+  /**
+   * Parse stack information.
+   *
+   * @param blueprint  associated blueprint
+   *
+   * @return stack instance
+   *
+   * @throws SystemException an unexpected exception occurred
+   */
+  protected Stack parseStack(BlueprintEntity blueprint) throws SystemException {
+    Stack stack;
+    try {
+      stack = new Stack(blueprint.getStackName(), blueprint.getStackVersion());
+    } catch (StackAccessException e) {
+      throw new IllegalArgumentException("Invalid stack information provided for cluster.  " +
+          "stack name: " + blueprint.getStackName() +
+          " stack version: " + blueprint.getStackVersion());
+    } catch (AmbariException e) {
+      throw new SystemException("Unable to obtain stack information.", e);
+    }
+    return stack;
+  }
+
+  /**
+   * Validate blueprint topology.
+   * An exception is thrown in the case of validation failure.
+   * For missing components which are auto-deploy enabled, these are added to the topology which is reflected
+   * in the blueprint entity that is returned.
+   *
+   * @param blueprint  blueprint to validate
+   *
+   * @return blueprint entity which may have been updated as a result of auto-deployment of components.
+   *
+   * @throws AmbariException an unexpected error occurred
+   * @throws IllegalArgumentException when validation fails
+   */
+  protected BlueprintEntity validateTopology(BlueprintEntity blueprint) throws AmbariException {
+    Stack stack = new Stack(blueprint.getStackName(), blueprint.getStackVersion());
+    Map<String, HostGroup> hostGroupMap = parseBlueprintHostGroups(blueprint, stack);
+    Collection<HostGroup> hostGroups = hostGroupMap.values();
+    Map<String, Map<String, Collection<DependencyInfo>>> missingDependencies =
+        new HashMap<String, Map<String, Collection<DependencyInfo>>>();
+
+    Collection<String> services = getTopologyServices(hostGroups);
+    for (HostGroup group : hostGroups) {
+      Map<String, Collection<DependencyInfo>> missingGroupDependencies = group.validateTopology(hostGroups, services);
+      if (! missingGroupDependencies.isEmpty()) {
+        missingDependencies.put(group.getEntity().getName(), missingGroupDependencies);
+      }
+    }
+
+    Collection<String> cardinalityFailures = new HashSet<String>();
+    for (String service : services) {
+      for (String component : stack.getComponents(service)) {
+        Cardinality cardinality = stack.getCardinality(component);
+        AutoDeployInfo autoDeploy = stack.getAutoDeployInfo(component);
+        if (cardinality.isAll()) {
+          cardinalityFailures.addAll(verifyComponentInAllHostGroups(
+              blueprint, hostGroups, component, autoDeploy));
+        } else {
+          cardinalityFailures.addAll(verifyComponentCardinalityCount(
+              blueprint, hostGroups, component, cardinality, autoDeploy));
+        }
+      }
+    }
+
+    if (! missingDependencies.isEmpty() || ! cardinalityFailures.isEmpty()) {
+      generateInvalidTopologyException(missingDependencies, cardinalityFailures);
+    }
+
+    return blueprint;
+  }
+
+  /**
+   * Process cluster scoped configurations contained in blueprint.
+   *
+   * @param blueprint  blueprint entity
+   *
+   * @return cluster scoped properties contained within in blueprint
+   */
+  protected 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;
+  }
+
+  /**
+   * Override existing properties or add new.
+   *
+   * @param existingProperties  current property values
+   * @param configOverrides     override properties
+   */
+  protected 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());
+        }
+      }
+    }
+  }
+
+  /**
+   * Add a new component entity to a host group entity.
+   *
+   * @param blueprint  blueprint entity
+   * @param hostGroup  host group name
+   * @param component  name of component which is being added
+   */
+  protected void addComponentToBlueprint(BlueprintEntity blueprint, String hostGroup, String component) {
+    HostGroupComponentEntity componentEntity = new HostGroupComponentEntity();
+    componentEntity.setBlueprintName(blueprint.getBlueprintName());
+    componentEntity.setName(component);
+
+    for (HostGroupEntity hostGroupEntity : blueprint.getHostGroups()) {
+      if (hostGroupEntity.getName().equals(hostGroup))  {
+        componentEntity.setHostGroupEntity(hostGroupEntity);
+        componentEntity.setHostGroupName(hostGroupEntity.getName());
+        hostGroupEntity.addComponent(componentEntity);
+        break;
+      }
+    }
+  }
+
+  /**
+   * Obtain a blueprint entity based on name.
+   *
+   * @param blueprintName  name of blueprint to obtain
+   *
+   * @return blueprint entity for the given name
+   * @throws IllegalArgumentException no blueprint with the given name found
+   */
+  protected BlueprintEntity getExistingBlueprint(String blueprintName) {
+    BlueprintEntity blueprint = blueprintDAO.findByName(blueprintName);
+    if (blueprint == null) {
+      throw new IllegalArgumentException("Specified blueprint doesn't exist: " + blueprintName);
+    }
+    return blueprint;
+  }
+
+  /**
+   * Get all services provided in topology.
+   *
+   * @param hostGroups  all host groups in topology
+   *
+   * @return collections of all services provided by topology
+   */
+  protected Collection<String> getTopologyServices(Collection<HostGroup> hostGroups) {
+    Collection<String> services = new HashSet<String>();
+    for (HostGroup group : hostGroups) {
+      services.addAll(group.getServices());
+    }
+    return services;
+  }
+
+  /**
+   * Verify that a component meets cardinality requirements.  For components that are
+   * auto-install enabled, will add component to topology if needed.
+   *
+   * @param blueprint    blueprint instance
+   * @param hostGroups   collection of host groups
+   * @param component    component to validate
+   * @param cardinality  required cardinality
+   * @param autoDeploy   auto-deploy information for component
+   *
+   * @return collection of missing component information
+   */
+  private Collection<String> verifyComponentCardinalityCount(BlueprintEntity blueprint,
+                                                             Collection<HostGroup> hostGroups,
+                                                             String component,
+                                                             Cardinality cardinality,
+                                                             AutoDeployInfo autoDeploy) {
+
+    Collection<String> cardinalityFailures = new HashSet<String>();
+
+    int actualCount = getHostGroupsForComponent(component, hostGroups).size();
+    boolean autoDeployed = false;
+    if (! cardinality.isValidCount(actualCount)) {
+      if (autoDeploy != null && autoDeploy.isEnabled() && cardinality.cardinality.equals("1")) {
+        String coLocateName = autoDeploy.getCoLocate();
+        if (coLocateName != null && ! coLocateName.isEmpty()) {
+          Collection<HostGroup> coLocateHostGroups = getHostGroupsForComponent(
+              coLocateName.split("/")[1], hostGroups);
+          if (! coLocateHostGroups.isEmpty()) {
+            autoDeployed = true;
+            HostGroup group = coLocateHostGroups.iterator().next();
+            if (group.addComponent(component)) {
+              addComponentToBlueprint(blueprint, group.getEntity().getName(), component);
+            }
+          }
+        }
+      }
+      if (! autoDeployed) {
+        cardinalityFailures.add(component + "(actual=" + actualCount + ", required=" +
+            cardinality.cardinality + ")");
+      }
+    }
+    return cardinalityFailures;
+  }
+
+  /**
+   * Verify that a component is included in all host groups.
+   * For components that are auto-install enabled, will add component to topology if needed.
+   *
+   * @param blueprint   blueprint instance
+   * @param hostGroups  collection of host groups
+   * @param component   component to validate
+   * @param autoDeploy  auto-deploy information for component
+   *
+   * @return collection of missing component information
+   */
+  private Collection<String> verifyComponentInAllHostGroups(BlueprintEntity blueprint,
+                                                            Collection<HostGroup> hostGroups,
+                                                            String component,
+                                                            AutoDeployInfo autoDeploy) {
+
+    Collection<String> cardinalityFailures = new HashSet<String>();
+    int actualCount = getHostGroupsForComponent(component, hostGroups).size();
+    if (actualCount != hostGroups.size()) {
+      if (autoDeploy != null && autoDeploy.isEnabled()) {
+        for (HostGroup group : hostGroups) {
+          if (group.addComponent(component)) {
+            addComponentToBlueprint(blueprint, group.getEntity().getName(), component);
+          }
+        }
+      } else {
+        cardinalityFailures.add(component + "(actual=" + actualCount + ", required=ALL)");
+      }
+    }
+    return cardinalityFailures;
+  }
+
+  /**
+   * Generate an exception for topology validation failure.
+   *
+   * @param missingDependencies  missing dependency information
+   * @param cardinalityFailures  missing service component information
+   *
+   * @throws IllegalArgumentException  Always thrown and contains information regarding the topology validation failure
+   *                                   in the msg
+   */
+  private void generateInvalidTopologyException(Map<String, Map<String, Collection<DependencyInfo>>> missingDependencies,
+                                                Collection<String> cardinalityFailures) {
+
+    String msg = "Cluster Topology validation failed.";
+    if (! cardinalityFailures.isEmpty()) {
+      msg += "  Invalid service component count: " + cardinalityFailures;
+    }
+    if (! missingDependencies.isEmpty()) {
+      msg += "  Unresolved component dependencies: " + missingDependencies;
+    }
+    msg += ".  To disable topology validation and create the blueprint, " +
+           "add the following to the end of the url: '?validate_topology=false'";
+    throw new IllegalArgumentException(msg);
+  }
+
+
+  // ----- Inner Classes -----------------------------------------------------
+
+  /**
+   * Encapsulates stack information.
+   */
+  protected class Stack {
+    /**
+     * Stack name
+     */
+    private String name;
+
+    /**
+     * Stack version
+     */
+    private String version;
+
+    /**
+     * Map of service name to components
+     */
+    private Map<String, Collection<String>> serviceComponents =
+        new HashMap<String, Collection<String>>();
+
+    /**
+     * Map of component to service
+     */
+    private Map<String, String> componentService = new HashMap<String, String>();
+
+    /**
+     * Map of component to dependencies
+     */
+    private Map<String, Collection<DependencyInfo>> dependencies =
+        new HashMap<String, Collection<DependencyInfo>>();
+
+    /**
+     * Map of dependency to conditional service
+     */
+    private Map<DependencyInfo, String> dependencyConditionalServiceMap =
+        new HashMap<DependencyInfo, String>();
+
+    /**
+     * Map of component to required cardinality
+     */
+    private Map<String, String> cardinalityRequirements = new HashMap<String, String>();
+
+    /**
+     * Map of component to auto-deploy information
+     */
+    private Map<String, AutoDeployInfo> componentAutoDeployInfo =
+        new HashMap<String, AutoDeployInfo>();
+
+    /**
+     * Map of service to config type properties
+     */
+    private Map<String, Map<String, Map<String, String>>> serviceConfigurations =
+        new HashMap<String, Map<String, Map<String, String>>>();
+
+    /**
+     * Constructor.
+     *
+     * @param name     stack name
+     * @param version  stack version
+     *
+     * @throws AmbariException an exception occurred getting stack information
+     *                         for the specified name and version
+     */
+    public Stack(String name, String version) throws AmbariException {
+      this.name = name;
+      this.version = version;
+
+      Set<StackServiceResponse> stackServices = getManagementController().getStackServices(
+          Collections.singleton(new StackServiceRequest(name, version, null)));
+
+      for (StackServiceResponse stackService : stackServices) {
+        String serviceName = stackService.getServiceName();
+        parseComponents(serviceName);
+        parseConfigurations(serviceName);
+        recordConditionalDependencies();
+      }
+    }
+
+    /**
+     * Obtain stack name.
+     *
+     * @return stack name
+     */
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * Obtain stack version.
+     *
+     * @return stack version
+     */
+    public String getVersion() {
+      return version;
+    }
+
+    /**
+     * Get services contained in the stack.
+     *
+     * @return collection of all services for the stack
+     */
+    public Collection<String> getServices() {
+      return serviceComponents.keySet();
+    }
+
+    /**
+     * Get components contained in the stack for the specified service.
+     *
+     * @param service  service name
+     *
+     * @return collection of component names for the specified service
+     */
+    public Collection<String> getComponents(String service) {
+      return serviceComponents.get(service);
+    }
+
+    /**
+     * Get configuration types for the specified service.
+     *
+     * @param service  service name
+     *
+     * @return collection of configuration types for the specified service
+     */
+    public Collection<String> getConfigurationTypes(String service) {
+      return serviceConfigurations.get(service).keySet();
+    }
+
+    /**
+     * Get config properties for the specified service and configuration type.
+     *
+     * @param service  service name
+     * @param type     configuration type
+     *
+     * @return map of property names to values for the specified service and configuration type
+     */
+    public Map<String, String> getConfigurationProperties(String service, String type) {
+      return serviceConfigurations.get(service).get(type);
+    }
+
+    /**
+     * Get the service for the specified component.
+     *
+     * @param component  component name
+     *
+     * @return service name that contains tha specified component
+     */
+    public String getServiceForComponent(String component) {
+      return componentService.get(component);
+    }
+
+    /**
+     * Get the names of the services which contains the specified components.
+     *
+     * @param components collection of components
+     *
+     * @return collection of services which contain the specified components
+     */
+    public Collection<String> getServicesForComponents(Collection<String> components) {
+      Set<String> services = new HashSet<String>();
+      for (String component : components) {
+        services.add(getServiceForComponent(component));
+      }
+
+      return services;
+    }
+
+    /**
+     * Obtain the service name which corresponds to the specified configuration.
+     *
+     * @param config  configuration type
+     *
+     * @return name of service which corresponds to the specified configuration type
+     */
+    public String getServiceForConfigType(String config) {
+      for (Map.Entry<String, Map<String, Map<String, String>>> entry : serviceConfigurations.entrySet()) {
+        Map<String, Map<String, String>> typeMap = entry.getValue();
+        if (typeMap.containsKey(config)) {
+          return entry.getKey();
+        }
+      }
+      throw new IllegalArgumentException(
+          "Specified configuration type is not associated with any service: " + config);
+    }
+
+    /**
+     * Return the dependencies specified for the given component.
+     *
+     * @param component  component to get dependency information for
+     *
+     * @return collection of dependency information for the specified component
+     */
+    //todo: full dependency graph
+    public Collection<DependencyInfo> getDependenciesForComponent(String component) {
+      return dependencies.containsKey(component) ? dependencies.get(component) :
+          Collections.<DependencyInfo>emptySet();
+    }
+
+    /**
+     * Get the service, if any, that a component dependency is conditional on.
+     *
+     * @param dependency  dependency to get conditional service for
+     *
+     * @return conditional service for provided component or null if dependency
+     *         is not conditional on a service
+     */
+    public String getConditionalServiceForDependency(DependencyInfo dependency) {
+      return dependencyConditionalServiceMap.get(dependency);
+    }
+
+    /**
+     * Obtain the required cardinality for the specified component.
+     */
+    public Cardinality getCardinality(String component) {
+      return new Cardinality(cardinalityRequirements.get(component));
+    }
+
+    /**
+     * Obtain auto-deploy information for the specified component.
+     */
+    public AutoDeployInfo getAutoDeployInfo(String component) {
+      return componentAutoDeployInfo.get(component);
+    }
+
+    /**
+     * Parse components for the specified service from the stack definition.
+     *
+     * @param service  service name
+     *
+     * @throws AmbariException an exception occurred getting components from the stack definition
+     */
+    private void parseComponents(String service) throws AmbariException{
+      Collection<String> componentSet = new HashSet<String>();
+
+      Set<StackServiceComponentResponse> components = getManagementController().getStackComponents(
+          Collections.singleton(new StackServiceComponentRequest(name, version, service, null)));
+
+      // stack service components
+      for (StackServiceComponentResponse component : components) {
+        String componentName = component.getComponentName();
+        componentSet.add(componentName);
+        componentService.put(componentName, service);
+        String cardinality = component.getCardinality();
+        if (cardinality != null) {
+          cardinalityRequirements.put(componentName, cardinality);
+        }
+        AutoDeployInfo autoDeploy = component.getAutoDeploy();
+        if (autoDeploy != null) {
+          componentAutoDeployInfo.put(componentName, autoDeploy);
+        }
+
+        // populate component dependencies
+        Collection<DependencyInfo> componentDependencies = stackInfo.getComponentDependencies(
+            name, version, service, componentName);
+
+        if (componentDependencies != null && ! componentDependencies.isEmpty()) {
+          dependencies.put(componentName, componentDependencies);
+        }
+      }
+      this.serviceComponents.put(service, componentSet);
+    }
+
+    /**
+     * Parse configurations for the specified service from the stack definition.
+     *
+     * @param service  service name
+     *
+     * @throws AmbariException an exception occurred getting configurations from the stack definition
+     */
+    private void parseConfigurations(String service) throws AmbariException {
+      Map<String, Map<String, String>> mapServiceConfig = new HashMap<String, Map<String, String>>();
+
+      serviceConfigurations.put(service, mapServiceConfig);
+
+      Set<StackConfigurationResponse> serviceConfigs = getManagementController().getStackConfigurations(
+          Collections.singleton(new StackConfigurationRequest(name, version, service, null)));
+
+      for (StackConfigurationResponse config : serviceConfigs) {
+        String type = config.getType();
+        //strip .xml from type
+        if (type.endsWith(".xml")) {
+          type = type.substring(0, type.length() - 4);
+        }
+        Map<String, String> mapTypeConfig = mapServiceConfig.get(type);
+        if (mapTypeConfig == null) {
+          mapTypeConfig = new HashMap<String, String>();
+          mapServiceConfig.put(type, mapTypeConfig);
+        }
+        mapTypeConfig.put(config.getPropertyName(), config.getPropertyValue());
+      }
+    }
+
+    /**
+     * Register conditional dependencies.
+     */
+    //todo: This information should be specified in the stack definition.
+    private void recordConditionalDependencies() {
+      Collection<DependencyInfo> nagiosDependencies = getDependenciesForComponent("NAGIOS_SERVER");
+      for (DependencyInfo dependency : nagiosDependencies) {
+        if (dependency.getComponentName().equals("HCAT")) {
+          dependencyConditionalServiceMap.put(dependency, "HCATALOG");
+        } else if (dependency.getComponentName().equals("OOZIE_CLIENT")) {
+          dependencyConditionalServiceMap.put(dependency, "OOZIE");
+        }
+      }
+    }
+  }
+
+  /**
+   * Host group representation.
+   */
+  protected class HostGroup {
+    /**
+     * Host group entity
+     */
+    private HostGroupEntity hostGroup;
+
+    /**
+     * Components contained in the host group
+     */
+    private Collection<String> components = new HashSet<String>();
+
+    /**
+     * Hosts contained associated with the host group
+     */
+    private Collection<String> hosts = new HashSet<String>();
+
+    /**
+     * Map of service to components for the host group
+     */
+    private Map<String, Set<String>> componentsForService = new HashMap<String, Set<String>>();
+
+    /**
+     * Map of host group configurations.
+     * Type -> Map<Key, Val>
+     */
+    private Map<String, Map<String, String>> configurations =
+        new HashMap<String, Map<String, String>>();
+
+    /**
+     * Associated stack
+     */
+    private Stack stack;
+
+    /**
+     * Constructor.
+     *
+     * @param hostGroup  host group
+     * @param stack      stack
+     */
+    public HostGroup(HostGroupEntity hostGroup, Stack stack) {
+      this.hostGroup = hostGroup;
+      this.stack = stack;
+      parseComponents();
+      parseConfigurations();
+    }
+
+    /**
+     * Associate a host with the host group.
+     *
+     * @param fqdn  fully qualified domain name of the host being added
+     */
+    public void addHostInfo(String fqdn) {
+      this.hosts.add(fqdn);
+    }
+
+    /**
+     * Get associated host information.
+     *
+     * @return collection of hosts associated with the host group
+     */
+    public Collection<String> getHostInfo() {
+      return this.hosts;
+    }
+
+    /**
+     * Get the services which are deployed to this host group.
+     *
+     * @return collection of services which have components in this host group
+     */
+    public Collection<String> getServices() {
+      return componentsForService.keySet();
+    }
+
+    /**
+     * Get the components associated with the host group.
+     *
+     * @return  collection of component names for the host group
+     */
+    public Collection<String> getComponents() {
+      return this.components;
+    }
+
+
+    /**
+     * Add a component to the host group.
+     *
+     * @param component  component to add
+     *
+     * @return true if component was added; false if component already existed
+     */
+    public boolean addComponent(String component) {
+      boolean added = components.add(component);
+      if (added) {
+        String service = stack.getServiceForComponent(component);
+        if (service != null) {
+          // an example of a component without a service in the stack is AMBARI_SERVER
+          Set<String> serviceComponents = componentsForService.get(service);
+          if (serviceComponents == null) {
+            serviceComponents = new HashSet<String>();
+            componentsForService.put(service, serviceComponents);
+          }
+          serviceComponents.add(component);
+        }
+      }
+      return added;
+    }
+
+    /**
+     * Get the components for the specified service which are associated with the host group.
+     *
+     * @param service  service name
+     *
+     * @return set of component names
+     */
+    public Collection<String> getComponents(String service) {
+      return componentsForService.get(service);
+    }
+
+    /**
+     * Get the configurations associated with the host group.
+     *
+     * @return map of configuration type to a map of properties
+     */
+    public Map<String, Map<String, String>> getConfigurations() {
+      return configurations;
+    }
+
+    /**
+     * Get the associated entity.
+     *
+     * @return  associated host group entity
+     */
+    public HostGroupEntity getEntity() {
+      return hostGroup;
+    }
+
+    /**
+     * Validate host group topology. This includes ensuring that all component dependencies are satisfied.
+     *
+     * @param hostGroups  collection of all host groups
+     *
+     * @return map of component to missing dependencies
+     */
+    public Map<String, Collection<DependencyInfo>> validateTopology(Collection<HostGroup> hostGroups,
+                                                                    Collection<String> services) {
+
+      Map<String, Collection<DependencyInfo>> missingDependencies =
+          new HashMap<String, Collection<DependencyInfo>>();
+
+      for (String component : new HashSet<String>(components)) {
+        Collection<DependencyInfo> dependenciesForComponent = stack.getDependenciesForComponent(component);
+        for (DependencyInfo dependency : dependenciesForComponent) {
+          String conditionalService = stack.getConditionalServiceForDependency(dependency);
+          if (conditionalService != null && ! services.contains(conditionalService)) {
+            continue;
+          }
+
+          BlueprintEntity   entity          = hostGroup.getBlueprintEntity();
+          String            dependencyScope = dependency.getScope();
+          String            componentName   = dependency.getComponentName();
+          AutoDeployInfo    autoDeployInfo  = dependency.getAutoDeploy();
+          boolean           resolved        = false;
+
+          if (dependencyScope.equals("cluster")) {
+            Collection<String> missingDependencyInfo = verifyComponentCardinalityCount(entity, hostGroups,
+                componentName, new Cardinality("1"), autoDeployInfo);
+            resolved = missingDependencyInfo.isEmpty();
+          } else if (dependencyScope.equals("host")) {
+            if (components.contains(component) || (autoDeployInfo != null && autoDeployInfo.isEnabled())) {
+              resolved = true;
+              if (addComponent(componentName)) {
+                addComponentToBlueprint(hostGroup.getBlueprintEntity(), getEntity().getName(), componentName);
+              }
+            }
+          }
+
+          if (! resolved) {
+            Collection<DependencyInfo> missingCompDependencies = missingDependencies.get(component);
+            if (missingCompDependencies == null) {
+              missingCompDependencies = new HashSet<DependencyInfo>();
+              missingDependencies.put(component, missingCompDependencies);
+            }
+            missingCompDependencies.add(dependency);
+          }
+        }
+      }
+      return missingDependencies;
+    }
+
+    /**
+     * Parse component information.
+     */
+    private void parseComponents() {
+      for (HostGroupComponentEntity componentEntity : hostGroup.getComponents() ) {
+        addComponent(componentEntity.getName());
+      }
+    }
+
+    /**
+     * Parse host group configurations.
+     */
+    private void parseConfigurations() {
+      Gson jsonSerializer = new Gson();
+      for (HostGroupConfigEntity configEntity : hostGroup.getConfigurations()) {
+        String type = configEntity.getType();
+        Map<String, String> typeProperties = configurations.get(type);
+        if ( typeProperties == null) {
+          typeProperties = new HashMap<String, String>();
+          configurations.put(type, typeProperties);
+        }
+        configurations.put(type, jsonSerializer.<Map<String, String>>fromJson(
+            configEntity.getConfigData(), Map.class));
+      }
+    }
+  }
+
+  /**
+   * Component cardinality representation.
+   */
+  protected static class Cardinality {
+    String cardinality;
+    int min = 0;
+    int max = Integer.MAX_VALUE;
+    int exact = -1;
+    boolean isAll = false;
+
+    public Cardinality(String cardinality) {
+      this.cardinality = cardinality;
+      if (cardinality != null && ! cardinality.isEmpty()) {
+        if (cardinality.contains("+")) {
+          min = Integer.valueOf(cardinality.split("\\+")[0]);
+        } else if (cardinality.contains("-")) {
+          String[] toks = cardinality.split("-");
+          min = Integer.parseInt(toks[0]);
+          max = Integer.parseInt(toks[1]);
+        } else if (cardinality.equals("ALL")) {
+          isAll = true;
+        } else {
+          exact = Integer.parseInt(cardinality);
+        }
+      }
+    }
+
+    /**
+     * Determine if component is required for all host groups.
+     *
+     * @return true if cardinality is 'ALL', false otherwise
+     */
+    public boolean isAll() {
+      return isAll;
+    }
+
+    /**
+     * Determine if the given count satisfies the required cardinality.
+     *
+     * @param count  number of host groups containing component
+     *
+     * @return true id count satisfies the required cardinality, false otherwise
+     */
+    public boolean isValidCount(int count) {
+      if (isAll) {
+        return false;
+      } else if (exact != -1) {
+        return count == exact;
+      } else return count >= min && count <= max;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/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 5e04141..8c99f90 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
@@ -23,6 +23,7 @@ import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.DuplicateResourceException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -58,7 +59,7 @@ import java.util.Set;
 /**
  * Resource Provider for Blueprint resources.
  */
-public class BlueprintResourceProvider extends AbstractResourceProvider {
+public class BlueprintResourceProvider extends BaseBlueprintProcessor {
 
   // ----- Property ID constants ---------------------------------------------
 
@@ -88,20 +89,10 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
           BLUEPRINT_NAME_PROPERTY_ID}));
 
   /**
-   * Blueprint data access object.
-   */
-  private static BlueprintDAO dao;
-
-  /**
    * Used to serialize to/from json.
    */
   private static Gson jsonSerializer;
 
-  /**
-   * Stack information.
-   */
-  private static AmbariMetaInfo stackInfo;
-
 
   // ----- Constructors ----------------------------------------------------
 
@@ -110,21 +101,25 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
    *
    * @param propertyIds     the property ids
    * @param keyPropertyIds  the key property ids
+   * @param controller      management controller
    */
-  BlueprintResourceProvider(Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds) {
-    super(propertyIds, keyPropertyIds);
+  BlueprintResourceProvider(Set<String> propertyIds,
+                            Map<Resource.Type, String> keyPropertyIds,
+                            AmbariManagementController controller) {
+
+    super(propertyIds, keyPropertyIds, controller);
   }
 
   /**
    * Static initialization.
    *
-   * @param blueprintDAO  blueprint data access object
-   * @param gson          gson json serializer
-   * @param metaInfo      stack related information
+   * @param dao       blueprint data access object
+   * @param gson      json serializer
+   * @param metaInfo  stack related information
    */
   @Inject
-  public static void init(BlueprintDAO blueprintDAO, Gson gson, AmbariMetaInfo metaInfo) {
-    dao            = blueprintDAO;
+  public static void init(BlueprintDAO dao, Gson gson, AmbariMetaInfo metaInfo) {
+    blueprintDAO   = dao;
     jsonSerializer = gson;
     stackInfo      = metaInfo;
   }
@@ -165,7 +160,7 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
             BLUEPRINT_NAME_PROPERTY_ID);
 
         if (name != null) {
-          BlueprintEntity entity = dao.findByName(name);
+          BlueprintEntity entity = blueprintDAO.findByName(name);
           results = entity == null ? Collections.<BlueprintEntity>emptyList() :
               Collections.singletonList(entity);
         }
@@ -174,7 +169,7 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
 
     if (results == null) {
       applyPredicate = true;
-      results = dao.findAll();
+      results = blueprintDAO.findAll();
     }
 
     Set<Resource> resources  = new HashSet<Resource>();
@@ -220,7 +215,7 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
       modifyResources(new Command<Void>() {
         @Override
         public Void invoke() throws AmbariException {
-        dao.removeByName(blueprintName);
+        blueprintDAO.removeByName(blueprintName);
         return null;
         }
       });
@@ -272,57 +267,6 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
 
     return resource;
   }
-  /**
-   * Convert a resource to a blueprint entity.
-   *
-   * @param resource the resource to convert
-   * @return  a new blueprint entity
-   */
-  @SuppressWarnings("unchecked")
-  protected BlueprintEntity toEntity(Resource resource) {
-    BlueprintEntity entity = new BlueprintEntity();
-    entity.setBlueprintName((String) resource.getPropertyValue(BLUEPRINT_NAME_PROPERTY_ID));
-    entity.setStackName((String) resource.getPropertyValue(STACK_NAME_PROPERTY_ID));
-    entity.setStackVersion((String) resource.getPropertyValue(STACK_VERSION_PROPERTY_ID));
-
-    Collection<HostGroupEntity> blueprintHostGroups = new ArrayList<HostGroupEntity>();
-    entity.setHostGroups(blueprintHostGroups);
-
-    Collection<Map<String, Object>> hostGroupProps = (Collection<Map<String, Object>>)
-        resource.getPropertyValue(HOST_GROUP_PROPERTY_ID);
-
-    for (Map<String, Object> properties : hostGroupProps) {
-      HostGroupEntity group = new HostGroupEntity();
-      group.setName((String) properties.get(BlueprintResourceProvider.HOST_GROUP_NAME_PROPERTY_ID));
-      group.setBlueprintEntity(entity);
-      group.setBlueprintName(entity.getBlueprintName());
-      group.setCardinality((String) properties.get(HOST_GROUP_CARDINALITY_PROPERTY_ID));
-
-      Collection<HostGroupComponentEntity> hostGroupComponents = new ArrayList<HostGroupComponentEntity>();
-      group.setComponents(hostGroupComponents);
-      createHostGroupConfigEntities((Collection<Map<String,
-          String>>) properties.get(CONFIGURATION_PROPERTY_ID), group);
-
-      List<Map<String, String>> listComponents = (List<Map<String, String>>)
-          properties.get(BlueprintResourceProvider.COMPONENT_PROPERTY_ID);
-
-      for (Map<String, String> componentProperties : listComponents) {
-        HostGroupComponentEntity component = new HostGroupComponentEntity();
-        component.setName(componentProperties.get(COMPONENT_NAME_PROPERTY_ID));
-        component.setBlueprintName(entity.getBlueprintName());
-        component.setHostGroupEntity(group);
-        component.setHostGroupName((String) properties.get(HOST_GROUP_NAME_PROPERTY_ID));
-
-        hostGroupComponents.add(component);
-      }
-      blueprintHostGroups.add(group);
-    }
-
-    createBlueprintConfigEntities((Collection<Map<String,
-        String>>) resource.getPropertyValue(CONFIGURATION_PROPERTY_ID), entity);
-
-    return entity;
-  }
 
   /**
    * Convert a map of properties to a blueprint entity.
@@ -588,12 +532,11 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
       public Void invoke() throws AmbariException {
         BlueprintEntity blueprint = toBlueprintEntity(properties);
 
-        if (dao.findByName(blueprint.getBlueprintName()) != null) {
+        if (blueprintDAO.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);
 
@@ -602,10 +545,19 @@ public class BlueprintResourceProvider extends AbstractResourceProvider {
                                              missingProperties);
         }
 
+        String validateTopology = (String) properties.get("validate_topology");
+        if (validateTopology == null || ! validateTopology.equalsIgnoreCase("false")) {
+          validateTopology(blueprint);
+        }
+
         if (LOG.isDebugEnabled()) {
           LOG.debug("Creating Blueprint, name=" + blueprint.getBlueprintName());
         }
-        dao.create(blueprint);
+        try {
+          blueprintDAO.create(blueprint);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
         return null;
       }
     };

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/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 2aa9ea1..054bd98 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
@@ -27,7 +27,6 @@ import java.util.Map;
 import java.util.Set;
 
 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;
@@ -36,12 +35,6 @@ import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.controller.ConfigGroupRequest;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
-import org.apache.ambari.server.controller.StackConfigurationRequest;
-import org.apache.ambari.server.controller.StackConfigurationResponse;
-import org.apache.ambari.server.controller.StackServiceComponentRequest;
-import org.apache.ambari.server.controller.StackServiceComponentResponse;
-import org.apache.ambari.server.controller.StackServiceRequest;
-import org.apache.ambari.server.controller.StackServiceResponse;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -54,21 +47,16 @@ import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.BlueprintDAO;
-import org.apache.ambari.server.orm.entities.BlueprintConfigEntity;
 import org.apache.ambari.server.orm.entities.BlueprintEntity;
-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.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigImpl;
 import org.apache.ambari.server.state.PropertyInfo;
 
-import com.google.gson.Gson;
-
 /**
  * Resource provider for cluster resources.
  */
-public class ClusterResourceProvider extends AbstractControllerResourceProvider {
+public class ClusterResourceProvider extends BaseBlueprintProcessor {
 
   // ----- Property ID constants ---------------------------------------------
 
@@ -85,17 +73,7 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{CLUSTER_ID_PROPERTY_ID}));
 
-  /**
-   * Data access object used to obtain blueprint entities.
-   */
-  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 =
@@ -331,7 +309,7 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
         "' based on blueprint '" + blueprintName + "'.");
 
     //todo: build up a proper topology object
-    BlueprintEntity blueprint = getBlueprint(blueprintName);
+    BlueprintEntity blueprint = getExistingBlueprint(blueprintName);
     Stack stack = parseStack(blueprint);
 
     Map<String, HostGroup> blueprintHostGroups = parseBlueprintHostGroups(blueprint, stack);
@@ -455,52 +433,6 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * 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
-   *
-   * @return blueprint entity for the given name
-   * @throws IllegalArgumentException no blueprint with the given name found
-   */
-  private BlueprintEntity getBlueprint(String blueprintName) {
-    BlueprintEntity blueprint = blueprintDAO.findByName(blueprintName);
-    if (blueprint == null) {
-      throw new IllegalArgumentException("Specified blueprint doesn't exist: " + blueprintName);
-    }
-    return blueprint;
-  }
-
-  /**
    * Create service and component resources.
    *
    * @param blueprintHostGroups  host groups contained in blueprint
@@ -542,7 +474,7 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   private Map<String, Object> buildClusterResourceProperties(Stack stack, String clusterName) {
     Map<String, Object> clusterProperties = new HashMap<String, Object>();
     clusterProperties.put(CLUSTER_NAME_PROPERTY_ID, clusterName);
-    clusterProperties.put(CLUSTER_VERSION_PROPERTY_ID, stack.name + "-" + stack.version);
+    clusterProperties.put(CLUSTER_VERSION_PROPERTY_ID, stack.getName() + "-" + stack.getVersion());
     return clusterProperties;
   }
 
@@ -732,47 +664,6 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * Parse blueprint host groups.
-   *
-   * @param blueprint  associated blueprint
-   * @param stack      associated stack
-   *
-   * @return map of host group name to host group
-   */
-  private Map<String, HostGroup> parseBlueprintHostGroups(BlueprintEntity blueprint, Stack stack) {
-    Map<String, HostGroup> mapHostGroups = new HashMap<String, HostGroup>();
-
-    for (HostGroupEntity hostGroup : blueprint.getHostGroups()) {
-      mapHostGroups.put(hostGroup.getName(), new HostGroup(hostGroup, stack));
-    }
-    return mapHostGroups;
-  }
-
-  /**
-   * Parse stack information.
-   *
-   * @param blueprint  associated blueprint
-   *
-   * @return stack instance
-   *
-   * @throws SystemException an unexpected exception occurred
-   */
-  private Stack parseStack(BlueprintEntity blueprint) throws SystemException {
-    Stack stack;
-    try {
-      stack = new Stack(blueprint.getStackName(), blueprint.getStackVersion());
-    } catch (StackAccessException e) {
-      throw new IllegalArgumentException("Invalid stack information provided for cluster.  " +
-          "stack name: " + blueprint.getStackName() +
-          " stack version: " + blueprint.getStackVersion());
-    } catch (AmbariException e) {
-      //todo: review all exception handling associated with cluster creation via blueprint
-      throw new SystemException("Unable to obtain stack information.", e);
-    }
-    return stack;
-  }
-
-  /**
    * Create the cluster resource.
    *
    * @param properties  cluster resource request properties
@@ -810,28 +701,6 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * Process configurations contained in blueprint.
-   *
-   * @param blueprint  blueprint entity
-   *
-   * @return configuration properties contained within in 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;
-  }
-
-  /**
    * Process cluster configurations.  This includes obtaining the default configuration properties
    * from the stack,overlaying configuration properties specified in the blueprint and cluster
    * create request and updating properties with topology specific information.
@@ -1022,24 +891,6 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * Get host groups which contain a component.
-   *
-   * @param component   component name
-   * @param hostGroups  collection of host groups to check
-   *
-   * @return collection of host groups which contain the specified component
-   */
-  private Collection<HostGroup> getHostGroupsForComponent(String component, Collection<HostGroup> hostGroups) {
-    Collection<HostGroup> resultGroups = new HashSet<HostGroup>();
-    for (HostGroup group : hostGroups ) {
-      if (group.getComponents().contains(component)) {
-        resultGroups.add(group);
-      }
-    }
-    return resultGroups;
-  }
-
-  /**
    * Register config groups for host group scoped configuration.
    * For each host group with configuration specified in the blueprint, a config group is created
    * and the hosts associated with the host group are assigned to the config group.
@@ -1114,346 +965,6 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   }
 
 
-  // ----- Inner Classes -----------------------------------------------------
-
-  /**
-   * Encapsulates stack information.
-   */
-  private class Stack {
-    /**
-     * Stack name
-     */
-    private String name;
-
-    /**
-     * Stack version
-     */
-    private String version;
-
-    /**
-     * Map of service name to components
-     */
-    private Map<String, Collection<String>> serviceComponents = new HashMap<String, Collection<String>>();
-
-    /**
-     * Map of component to service
-     */
-    private Map<String, String> componentService = new HashMap<String, String>();
-
-    /**
-     * Map of service to config type properties
-     */
-    private Map<String, Map<String, Map<String, String>>> serviceConfigurations =
-        new HashMap<String, Map<String, Map<String, String>>>();
-
-    /**
-     * Constructor.
-     *
-     * @param name     stack name
-     * @param version  stack version
-     *
-     * @throws AmbariException an exception occurred getting stack information
-     *                         for the specified name and version
-     */
-    public Stack(String name, String version) throws AmbariException {
-      this.name = name;
-      this.version = version;
-
-      Set<StackServiceResponse> stackServices = getManagementController().getStackServices(
-          Collections.singleton(new StackServiceRequest(name, version, null)));
-
-      for (StackServiceResponse stackService : stackServices) {
-        String serviceName = stackService.getServiceName();
-        parseComponents(serviceName);
-        parseConfigurations(serviceName);
-      }
-    }
-
-    /**
-     * Get services contained in the stack.
-     *
-     * @return collection of all services for the stack
-     */
-    public Collection<String> getServices() {
-      return serviceComponents.keySet();
-    }
-
-    /**
-     * Get components contained in the stack for the specified service.
-     *
-     * @param service  service name
-     *
-     * @return collection of component names for the specified service
-     */
-    public Collection<String> getComponents(String service) {
-      return serviceComponents.get(service);
-    }
-
-    /**
-     * Get configuration types for the specified service.
-     *
-     * @param service  service name
-     *
-     * @return collection of configuration types for the specified service
-     */
-    public Collection<String> getConfigurationTypes(String service) {
-      return serviceConfigurations.get(service).keySet();
-    }
-
-    /**
-     * Get config properties for the specified service and configuration type.
-     *
-     * @param service  service name
-     * @param type     configuration type
-     *
-     * @return map of property names to values for the specified service and configuration type
-     */
-    public Map<String, String> getConfigurationProperties(String service, String type) {
-      return serviceConfigurations.get(service).get(type);
-    }
-
-    /**
-     * Get the service for the specified component.
-     *
-     * @param component  component name
-     *
-     * @return service name that contains tha specified component
-     */
-    public String getServiceForComponent(String component) {
-      return componentService.get(component);
-    }
-
-    /**
-     * Get the names of the services which contains the specified components.
-     *
-     * @param components collection of components
-     *
-     * @return collection of services which contain the specified components
-     */
-    public Collection<String> getServicesForComponents(Collection<String> components) {
-      Set<String> services = new HashSet<String>();
-      for (String component : components) {
-        services.add(getServiceForComponent(component));
-      }
-
-      return services;
-    }
-
-    /**
-     * Obtain the service name which corresponds to the specified configuration.
-     *
-     * @param config  configuration type
-     *
-     * @return name of service which corresponds to the specified configuration type
-     */
-    public String getServiceForConfigType(String config) {
-      for (Map.Entry<String, Map<String, Map<String, String>>> entry : serviceConfigurations.entrySet()) {
-        Map<String, Map<String, String>> typeMap = entry.getValue();
-        if (typeMap.containsKey(config)) {
-          return entry.getKey();
-        }
-      }
-      throw new IllegalArgumentException(
-          "Specified configuration type is not associated with any service: " + config);
-    }
-
-    /**
-     * Parse components for the specified service from the stack definition.
-     *
-     * @param service  service name
-     *
-     * @throws AmbariException an exception occurred getting components from the stack definition
-     */
-    private void parseComponents(String service) throws AmbariException{
-      Collection<String> componentSet = new HashSet<String>();
-
-      Set<StackServiceComponentResponse> components = getManagementController().getStackComponents(
-          Collections.singleton(new StackServiceComponentRequest(name, version, service, null)
-      ));
-
-      // stack service components
-      for (StackServiceComponentResponse component : components) {
-        String componentName = component.getComponentName();
-        componentSet.add(componentName);
-        componentService.put(componentName, service);
-      }
-      this.serviceComponents.put(service, componentSet);
-    }
-
-    /**
-     * Parse configurations for the specified service from the stack definition.
-     *
-     * @param service  service name
-     *
-     * @throws AmbariException an exception occurred getting configurations from the stack definition
-     */
-    private void parseConfigurations(String service) throws AmbariException {
-      Map<String, Map<String, String>> mapServiceConfig = new HashMap<String, Map<String, String>>();
-
-      serviceConfigurations.put(service, mapServiceConfig);
-
-      Set<StackConfigurationResponse> serviceConfigs =
-        getManagementController().getStackConfigurations(
-          Collections.singleton(new StackConfigurationRequest(name, version, service, null)
-        ));
-
-      for (StackConfigurationResponse config : serviceConfigs) {
-        String type = config.getType();
-        //strip .xml from type
-        if (type.endsWith(".xml")) {
-          type = type.substring(0, type.length() - 4);
-        }
-        Map<String, String> mapTypeConfig = mapServiceConfig.get(type);
-        if (mapTypeConfig == null) {
-          mapTypeConfig = new HashMap<String, String>();
-          mapServiceConfig.put(type, mapTypeConfig);
-        }
-
-        mapTypeConfig.put(config.getPropertyName(), config.getPropertyValue());
-      }
-    }
-  }
-
-  /**
-   * Host group representation.
-   */
-  protected class HostGroup {
-    /**
-     * Host group entity
-     */
-    private HostGroupEntity hostGroup;
-
-    /**
-     * Components contained in the host group
-     */
-    private Collection<String> components = new HashSet<String>();
-
-    /**
-     * Hosts contained associated with the host group
-     */
-    private Collection<String> hosts = new HashSet<String>();
-
-    /**
-     * Map of service to components for the host group
-     */
-    private Map<String, Set<String>> componentsForService = new HashMap<String, Set<String>>();
-
-    /**
-     * Map of host group configurations.
-     * Type -> Map<Key, Val>
-     */
-    private Map<String, Map<String, String>> configurations =
-        new HashMap<String, Map<String, String>>();
-
-    /**
-     * Associated stack
-     */
-    private Stack stack;
-
-    /**
-     * Constructor.
-     *
-     * @param hostGroup  host group
-     * @param stack      stack
-     */
-    public HostGroup(HostGroupEntity hostGroup, Stack stack) {
-      this.hostGroup = hostGroup;
-      this.stack = stack;
-      parseComponents();
-      parseConfigurations();
-    }
-
-    /**
-     * Associate a host with the host group.
-     *
-     * @param fqdn  fully qualified domain name of the host being added
-     */
-    public void addHostInfo(String fqdn) {
-      this.hosts.add(fqdn);
-    }
-
-    /**
-     * Get associated host information.
-     *
-     * @return collection of hosts associated with the host group
-     */
-    public Collection<String> getHostInfo() {
-      return this.hosts;
-    }
-
-    /**
-     * Get the components associated with the host group.
-     *
-     * @return  collection of component names for the host group
-     */
-    public Collection<String> getComponents() {
-      return this.components;
-    }
-
-    /**
-     * Get the components for the specified service which are associated with the host group.
-     *
-     * @param service  service name
-     *
-     * @return set of component names
-     */
-    public Collection<String> getComponents(String service) {
-      return componentsForService.get(service);
-    }
-
-    /**
-     * Get the configurations associated with the host group.
-     *
-     * @return map of configuration type to a map of properties
-     */
-    public Map<String, Map<String, String>> getConfigurations() {
-      return configurations;
-    }
-
-    /**
-     * Get the associated entity.
-     *
-     * @return  associated host group entity
-     */
-    public HostGroupEntity getEntity() {
-      return hostGroup;
-    }
-
-    /**
-     * Parse component information.
-     */
-    private void parseComponents() {
-      for (HostGroupComponentEntity componentEntity : hostGroup.getComponents() ) {
-        String name = componentEntity.getName();
-        components.add(name);
-        String service = stack.getServiceForComponent(name);
-        Set<String> serviceComponents = componentsForService.get(service);
-        if (serviceComponents == null) {
-          serviceComponents = new HashSet<String>();
-          componentsForService.put(service, serviceComponents);
-        }
-        serviceComponents.add(name);
-      }
-    }
-
-    /**
-     * Parse host group configurations.
-     */
-    private void parseConfigurations() {
-      Gson jsonSerializer = new Gson();
-      for (HostGroupConfigEntity configEntity : hostGroup.getConfigurations()) {
-        String type = configEntity.getType();
-        Map<String, String> typeProperties = configurations.get(type);
-        if ( typeProperties == null) {
-          typeProperties = new HashMap<String, String>();
-          configurations.put(type, typeProperties);
-        }
-        configurations.put(type, jsonSerializer.<Map<String, String>>fromJson(
-            configEntity.getConfigData(), Map.class));
-      }
-    }
-  }
-
   /**
    * Provides functionality to update a property value.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index cdc30d2..923202c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -67,8 +67,6 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new ViewVersionResourceProvider();
       case ViewInstance:
         return new ViewInstanceResourceProvider();
-      case Blueprint:
-        return new BlueprintResourceProvider(propertyIds, keyPropertyIds);
       case StackServiceComponentDependency:
         return new StackDependencyResourceProvider(propertyIds, keyPropertyIds);
       default:

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupEntity.java
index f0422e3..87f1a93 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupEntity.java
@@ -133,6 +133,15 @@ public class HostGroupEntity {
   }
 
   /**
+   * Add a component to the host group.
+   *
+   * @param component  component to add
+   */
+  public void addComponent(HostGroupComponentEntity component) {
+    this.components.add(component);
+  }
+
+  /**
    * Get the collection of associated configuration entities.
    *
    * @return collection of configurations

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
index d6d000f..58e6e4c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
@@ -135,4 +135,12 @@ public class DependencyInfo {
   public String getServiceName() {
     return serviceName;
   }
+
+  @Override
+  public String toString() {
+    return "DependencyInfo[name=" + getName() +
+           ", scope=" + getScope() +
+           ", auto-deploy=" + m_autoDeploy.isEnabled() +
+           "]";
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 9c6dd9c..b24aa0b 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -334,7 +334,8 @@
         "host_groups",
         "host_groups/components",
         "host_groups/cardinality",
-        "configurations"
+        "configurations",
+        "validate_topology"
     ],
     "HostComponentProcess": [
       "HostComponentProcess/cluster_name",

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/HIVE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/HIVE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/HIVE/metainfo.xml
index 6e057d2..36338ff 100644
--- a/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/HIVE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/HIVE/metainfo.xml
@@ -27,12 +27,7 @@
         <component>
           <name>HIVE_METASTORE</name>
           <category>MASTER</category>
-          <!-- may be 0 if specifying external metastore, how to specify this? -->
           <cardinality>1</cardinality>
-          <auto-deploy>
-            <enabled>true</enabled>
-            <co-locate>HIVE/HIVE_SERVER</co-locate>
-          </auto-deploy>
           <commandScript>
             <script>scripts/hive_metastore.py</script>
             <scriptType>PYTHON</scriptType>
@@ -70,12 +65,7 @@
         <component>
           <name>MYSQL_SERVER</name>
           <category>MASTER</category>
-          <!-- may be 0 if specifying external db, how to specify this? -->
           <cardinality>1</cardinality>
-          <auto-deploy>
-            <enabled>true</enabled>
-            <co-locate>HIVE/HIVE_SERVER</co-locate>
-          </auto-deploy>
           <commandScript>
             <script>scripts/mysql_server.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/ZOOKEEPER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/ZOOKEEPER/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/ZOOKEEPER/metainfo.xml
index d3e6ee0..216fc3c 100644
--- a/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/ZOOKEEPER/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/ZOOKEEPER/metainfo.xml
@@ -27,7 +27,7 @@
         <component>
           <name>ZOOKEEPER_SERVER</name>
           <category>MASTER</category>
-          <cardinality>1</cardinality>
+          <cardinality>1+</cardinality>
           <commandScript>
             <script>scripts/zookeeper_server.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/FLUME/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/FLUME/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/FLUME/metainfo.xml
index 0e25020..6eec545 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/FLUME/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/FLUME/metainfo.xml
@@ -26,6 +26,7 @@
         <component>
           <name>FLUME_HANDLER</name>
           <category>SLAVE</category>
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/flume_handler.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/GANGLIA/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/GANGLIA/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/GANGLIA/metainfo.xml
index 3a181b8..3f97445 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/GANGLIA/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/GANGLIA/metainfo.xml
@@ -26,6 +26,7 @@
         <component>
           <name>GANGLIA_SERVER</name>
           <category>MASTER</category>
+          <cardinality>1</cardinality>
           <commandScript>
             <script>scripts/ganglia_server.py</script>
             <scriptType>PYTHON</scriptType>
@@ -36,6 +37,10 @@
         <component>
           <name>GANGLIA_MONITOR</name>
           <category>SLAVE</category>
+          <cardinality>ALL</cardinality>
+          <auto-deploy>
+            <enabled>true</enabled>
+          </auto-deploy>
           <commandScript>
             <script>scripts/ganglia_monitor.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml
index bf4e40b..e738877 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml
@@ -66,6 +66,7 @@
         <component>
           <name>HBASE_REGIONSERVER</name>
           <category>SLAVE</category>
+          <cardinality>1+</cardinality>
           <commandScript>
             <script>scripts/hbase_regionserver.py</script>
             <scriptType>PYTHON</scriptType>
@@ -75,6 +76,7 @@
         <component>
           <name>HBASE_CLIENT</name>
           <category>CLIENT</category>
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/hbase_client.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/metainfo.xml
index 4b498a7..feff2ab 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/metainfo.xml
@@ -27,6 +27,7 @@
         <component>
           <name>NAMENODE</name>
           <category>MASTER</category>
+          <cardinality>1</cardinality>
           <commandScript>
             <script>scripts/namenode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -47,6 +48,7 @@
         <component>
           <name>DATANODE</name>
           <category>SLAVE</category>
+          <cardinality>1+</cardinality>
           <commandScript>
             <script>scripts/datanode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -56,6 +58,8 @@
 
         <component>
           <name>SECONDARY_NAMENODE</name>
+          <!-- TODO:  cardinality is conditional on HA usage -->
+          <cardinality>1</cardinality>
           <category>MASTER</category>
           <commandScript>
             <script>scripts/snamenode.py</script>
@@ -67,6 +71,7 @@
         <component>
           <name>HDFS_CLIENT</name>
           <category>CLIENT</category>
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/hdfs_client.py</script>
             <scriptType>PYTHON</scriptType>
@@ -76,7 +81,8 @@
 
         <component>
           <name>JOURNALNODE</name>
-          <category>MASTER</category>
+          <category>SLAVE</category>
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/journalnode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -87,6 +93,8 @@
         <component>
           <name>ZKFC</name>
           <category>SLAVE</category>
+          <!-- TODO: cardinality is conditional on HA topology -->
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/zkfc_slave.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HIVE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HIVE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HIVE/metainfo.xml
index d6b8fd2..636ecd3 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HIVE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HIVE/metainfo.xml
@@ -27,12 +27,7 @@
         <component>
           <name>HIVE_METASTORE</name>
           <category>MASTER</category>
-          <!-- may be 0 if specifying external metastore, how to specify this? -->
           <cardinality>1</cardinality>
-          <auto-deploy>
-            <enabled>true</enabled>
-            <co-locate>HIVE/HIVE_SERVER</co-locate>
-          </auto-deploy>
           <commandScript>
             <script>scripts/hive_metastore.py</script>
             <scriptType>PYTHON</scriptType>
@@ -84,12 +79,7 @@
         <component>
           <name>MYSQL_SERVER</name>
           <category>MASTER</category>
-          <!-- may be 0 if specifying external db, how to specify this? -->
           <cardinality>1</cardinality>
-          <auto-deploy>
-            <enabled>true</enabled>
-            <co-locate>HIVE/HIVE_SERVER</co-locate>
-          </auto-deploy>
           <commandScript>
             <script>scripts/mysql_server.py</script>
             <scriptType>PYTHON</scriptType>
@@ -99,6 +89,7 @@
         <component>
           <name>HIVE_CLIENT</name>
           <category>CLIENT</category>
+          <cardinality>0</cardinality>
           <commandScript>
             <script>scripts/hive_client.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/ZOOKEEPER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/ZOOKEEPER/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/ZOOKEEPER/metainfo.xml
index fc09417..8b00331 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/ZOOKEEPER/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/ZOOKEEPER/metainfo.xml
@@ -27,7 +27,7 @@
         <component>
           <name>ZOOKEEPER_SERVER</name>
           <category>MASTER</category>
-          <cardinality>1</cardinality>
+          <cardinality>1+</cardinality>
           <commandScript>
             <script>scripts/zookeeper_server.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.1/services/FALCON/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.1/services/FALCON/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.1/services/FALCON/metainfo.xml
index f878d77..5e2f942 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/services/FALCON/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/services/FALCON/metainfo.xml
@@ -26,6 +26,7 @@
         <component>
           <name>FALCON_CLIENT</name>
           <category>CLIENT</category>
+          <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/falcon_client.py</script>
             <scriptType>PYTHON</scriptType>
@@ -35,6 +36,7 @@
         <component>
           <name>FALCON_SERVER</name>
           <category>MASTER</category>
+          <cardinality>1</cardinality> 
           <commandScript>
             <script>scripts/falcon_server.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac8641fb/ambari-server/src/main/resources/stacks/HDP/2.1/services/TEZ/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.1/services/TEZ/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.1/services/TEZ/metainfo.xml
index 71c7837..ed9cfe3 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/services/TEZ/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/services/TEZ/metainfo.xml
@@ -25,6 +25,7 @@
       <components>
         <component>
           <name>TEZ_CLIENT</name>
+          <cardinality>0+</cardinality>
           <category>CLIENT</category>
           <commandScript>
             <script>scripts/tez_client.py</script>


Mime
View raw message