ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jspei...@apache.org
Subject [10/13] ambari git commit: AMBARI-10750. Initial merge of advanced api provisioning work.
Date Mon, 27 Apr 2015 05:53:04 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExportBlueprintRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExportBlueprintRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExportBlueprintRequest.java
new file mode 100644
index 0000000..e4acea2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExportBlueprintRequest.java
@@ -0,0 +1,531 @@
+/**
+ * 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 distribut
+ * ed 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 org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.util.TreeNode;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.HostConfig;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.BlueprintImpl;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.HostGroup;
+import org.apache.ambari.server.topology.HostGroupImpl;
+import org.apache.ambari.server.topology.HostGroupInfo;
+import org.apache.ambari.server.topology.InvalidTopologyTemplateException;
+import org.apache.ambari.server.topology.TopologyRequest;
+import org.apache.ambari.server.topology.TopologyValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Request to export a blueprint from an existing cluster.
+ */
+public class ExportBlueprintRequest implements TopologyRequest {
+
+  private final static Logger LOG = LoggerFactory.getLogger(ExportBlueprintRequest.class);
+  private static AmbariManagementController controller = AmbariServer.getController();
+
+  private String clusterName;
+  private Blueprint blueprint;
+  private Configuration configuration;
+  //todo: Should this map be represented by a new class?
+  private Map<String, HostGroupInfo> hostGroupInfo = new HashMap<String, HostGroupInfo>();
+
+
+  public ExportBlueprintRequest(TreeNode<Resource> clusterNode) throws InvalidTopologyTemplateException {
+    Resource clusterResource = clusterNode.getObject();
+    clusterName = String.valueOf(clusterResource.getPropertyValue(
+        ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID));
+
+
+    createConfiguration(clusterNode);
+    //todo: should be parsing Configuration from the beginning
+    //createConfiguration(configurations);
+
+    Collection<ExportedHostGroup> exportedHostGroups = processHostGroups(clusterNode.getChild("hosts"));
+    createHostGroupInfo(exportedHostGroups);
+    createBlueprint(exportedHostGroups, parseStack(clusterResource));
+  }
+
+  @Override
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  @Override
+  public Blueprint getBlueprint() {
+    return blueprint;
+  }
+
+  @Override
+  public Configuration getConfiguration() {
+    return configuration;
+  }
+
+  @Override
+  public Map<String, HostGroupInfo> getHostGroupInfo() {
+    return hostGroupInfo;
+  }
+
+  @Override
+  public List<TopologyValidator> getTopologyValidators() {
+    return Collections.emptyList();
+  }
+
+  // ----- private instance methods ------------------------------------------
+
+
+  private void createBlueprint(Collection<ExportedHostGroup> exportedHostGroups, Stack stack) {
+    String bpName = "exported-blueprint";
+
+    Collection<HostGroup> hostGroups = new ArrayList<HostGroup>();
+    int count = 1;
+    for (ExportedHostGroup exportedHostGroup : exportedHostGroups) {
+
+      //todo: for now can just get from ExportedHostGroup
+      //String cardinality = String.valueOf(hostGroupInfo.get(exportedHostGroup.getName()).getHostNames().size());
+      hostGroups.add(new HostGroupImpl("host_group_" + count++, bpName, stack, exportedHostGroup.getComponents(),
+          exportedHostGroup.getConfiguration(), String.valueOf(exportedHostGroup.getCardinality())));
+    }
+
+
+    blueprint = new BlueprintImpl(bpName, hostGroups, stack, configuration);
+  }
+
+  private void createHostGroupInfo(Collection<ExportedHostGroup> exportedHostGroups) {
+    for (ExportedHostGroup exportedGroup : exportedHostGroups) {
+      HostGroupInfo groupInfo = new HostGroupInfo(exportedGroup.getName());
+      groupInfo.addHosts(exportedGroup.getHostInfo());
+      //todo: should be parsing Configuration from the beginning
+      groupInfo.setConfiguration(exportedGroup.getConfiguration());
+      hostGroupInfo.put(groupInfo.getHostGroupName(), groupInfo);
+    }
+  }
+
+
+  private Stack parseStack(Resource clusterResource) throws InvalidTopologyTemplateException {
+    String[] stackTokens = String.valueOf(clusterResource.getPropertyValue(
+        ClusterResourceProvider.CLUSTER_VERSION_PROPERTY_ID)).split("-");
+
+    try {
+      return new Stack(stackTokens[0], stackTokens[1], controller);
+    } catch (AmbariException e) {
+      throw new InvalidTopologyTemplateException(String.format(
+          "The specified stack doesn't exist: name=%s version=%s", stackTokens[0], stackTokens[1]));
+    }
+  }
+
+  /**
+   * Process cluster scoped configurations.
+   *
+   * @param clusterNode  cluster node
+   *
+   */
+  private void createConfiguration(TreeNode<Resource> clusterNode) {
+
+    Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
+    Map<String, Map<String, Map<String, String>>> attributes = new HashMap<String, Map<String, Map<String, String>>>();
+
+    Map<String, Object> desiredConfigMap = clusterNode.getObject().getPropertiesMap().get("Clusters/desired_configs");
+    TreeNode<Resource> configNode = clusterNode.getChild("configurations");
+    for (TreeNode<Resource> config : configNode.getChildren()) {
+      ExportedConfiguration configuration = new ExportedConfiguration(config);
+      DesiredConfig desiredConfig = (DesiredConfig) desiredConfigMap.get(configuration.getType());
+      if (desiredConfig != null && desiredConfig.getTag().equals(configuration.getTag())) {
+
+        properties.put(configuration.getType(), configuration.getProperties());
+        attributes.put(configuration.getType(), configuration.getPropertyAttributes());
+      }
+    }
+    configuration = new Configuration(properties, attributes);
+    // empty parent configuration when exporting as all properties are included in this configuration
+    configuration.setParentConfiguration(new Configuration(
+        Collections.<String, Map<String, String>>emptyMap(),
+        Collections.<String, Map<String, Map<String, String>>>emptyMap()));
+  }
+
+  /**
+   * Process cluster host groups.
+   *
+   * @param hostNode  host node
+   *
+   * @return collection of host groups
+   */
+  private Collection<ExportedHostGroup> processHostGroups(TreeNode<Resource> hostNode) {
+    Map<ExportedHostGroup, ExportedHostGroup> mapHostGroups = new HashMap<ExportedHostGroup, ExportedHostGroup>();
+    int count = 1;
+    for (TreeNode<Resource> host : hostNode.getChildren()) {
+      ExportedHostGroup group = new ExportedHostGroup(host);
+      String hostName = (String) host.getObject().getPropertyValue(
+          PropertyHelper.getPropertyId("Hosts", "host_name"));
+
+      if (mapHostGroups.containsKey(group)) {
+        ExportedHostGroup hostGroup = mapHostGroups.get(group);
+        hostGroup.incrementCardinality();
+        hostGroup.addHost(hostName);
+      } else {
+        mapHostGroups.put(group, group);
+        group.setName("host_group_" + count++);
+        group.addHost(hostName);
+      }
+      processHostGroupComponents(group);
+    }
+
+    return mapHostGroups.values();
+  }
+
+
+  /**
+   * Process host group component information for a specific host.
+   *
+   * @param group host group instance
+   *
+   * @return list of component names for the host
+   */
+  private List<Map<String, String>> processHostGroupComponents(ExportedHostGroup group) {
+    List<Map<String, String>> listHostGroupComponents = new ArrayList<Map<String, String>>();
+    for (String component : group.getComponents()) {
+      Map<String, String> mapComponentProperties = new HashMap<String, String>();
+      listHostGroupComponents.add(mapComponentProperties);
+      mapComponentProperties.put("name", component);
+    }
+    return listHostGroupComponents;
+  }
+
+
+  // ----- Host Group inner class --------------------------------------------
+
+  /**
+   * Host Group representation.
+   */
+  public class ExportedHostGroup {
+
+    /**
+     * Host Group name.
+     *
+     */
+    private String name;
+
+    /**
+     * Associated components.
+     */
+    private Set<String> components = new HashSet<String>();
+
+    /**
+     * Host group scoped configurations.
+     */
+    private Collection<ExportedConfiguration> configurations = new HashSet<ExportedConfiguration>();
+
+    /**
+     * Number of instances.
+     */
+    private int m_cardinality = 1;
+
+    /**
+     * Collection of associated hosts.
+     */
+    private Collection<String> hosts = new HashSet<String>();
+
+    /**
+     * Constructor.
+     *
+     * @param host  host node
+     */
+    public ExportedHostGroup(TreeNode<Resource> host) {
+      TreeNode<Resource> components = host.getChild("host_components");
+      for (TreeNode<Resource> component : components.getChildren()) {
+        getComponents().add((String) component.getObject().getPropertyValue(
+            "HostRoles/component_name"));
+      }
+      addAmbariComponentIfLocalhost((String) host.getObject().getPropertyValue(
+          PropertyHelper.getPropertyId("Hosts", "host_name")));
+
+      processGroupConfiguration(host);
+    }
+
+    public Configuration getConfiguration() {
+      Map<String, Map<String, String>> configProperties = new HashMap<String, Map<String, String>>();
+      Map<String, Map<String, Map<String, String>>> configAttributes = new HashMap<String, Map<String, Map<String, String>>>();
+
+      for (ExportedConfiguration config : configurations) {
+        configProperties.put(config.getType(), config.getProperties());
+        configAttributes.put(config.getType(), config.getPropertyAttributes());
+      }
+
+      return new Configuration(configProperties, configAttributes);
+    }
+
+    /**
+     * Process host group configuration.
+     *
+     * @param host  host node
+     */
+    private void processGroupConfiguration(TreeNode<Resource> host) {
+      Map<String, Object> desiredConfigMap = host.getObject().getPropertiesMap().get("Hosts/desired_configs");
+      if (desiredConfigMap != null) {
+        for (Map.Entry<String, Object> entry : desiredConfigMap.entrySet()) {
+          String type = entry.getKey();
+          HostConfig hostConfig = (HostConfig) entry.getValue();
+          Map<Long, String> overrides = hostConfig.getConfigGroupOverrides();
+
+          if (overrides != null && ! overrides.isEmpty()) {
+            Long version = Collections.max(overrides.keySet());
+            String tag = overrides.get(version);
+            TreeNode<Resource> clusterNode = host.getParent().getParent();
+            TreeNode<Resource> configNode = clusterNode.getChild("configurations");
+            for (TreeNode<Resource> config : configNode.getChildren()) {
+              ExportedConfiguration configuration = new ExportedConfiguration(config);
+              if (type.equals(configuration.getType()) && tag.equals(configuration.getTag())) {
+                getConfigurations().add(configuration);
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public Set<String> getComponents() {
+      return components;
+    }
+
+    public Collection<String> getHostInfo() {
+      return hosts;
+    }
+
+
+    /**
+     * Set the name.
+     *
+     * @param  name name of host group
+     */
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    /**
+     * Add a host.
+     *
+     * @param host  host to add
+     */
+    public void addHost(String host) {
+      hosts.add(host);
+    }
+
+    /**
+     * Obtain associated host group scoped configurations.
+     *
+     * @return collection of host group scoped configurations
+     */
+    public Collection<ExportedConfiguration> getConfigurations() {
+      return configurations;
+    }
+
+    /**
+     * Obtain the number of instances associated with this host group.
+     *
+     * @return number of hosts associated with this host group
+     */
+    public int getCardinality() {
+      return m_cardinality;
+    }
+
+    /**
+     * Increment the cardinality count by one.
+     */
+    public void incrementCardinality() {
+      m_cardinality += 1;
+    }
+
+    /**
+     * Add the AMBARI_SERVER component if the host is the local host.
+     *
+     * @param hostname  host to check
+     */
+    private void addAmbariComponentIfLocalhost(String hostname) {
+      try {
+        InetAddress hostAddress = InetAddress.getByName(hostname);
+        try {
+          if (hostAddress.equals(InetAddress.getLocalHost())) {
+            getComponents().add("AMBARI_SERVER");
+          }
+        } catch (UnknownHostException e) {
+          //todo: SystemException?
+          throw new RuntimeException("Unable to obtain local host name", e);
+        }
+      } catch (UnknownHostException e) {
+        // ignore
+      }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      ExportedHostGroup hostGroup = (ExportedHostGroup) o;
+
+      return components.equals(hostGroup.components) &&
+          configurations.equals(hostGroup.configurations);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = components.hashCode();
+      result = 31 * result + configurations.hashCode();
+      return result;
+    }
+  }
+
+  /**
+   * Encapsulates a configuration.
+   */
+  private class ExportedConfiguration {
+    /**
+     * Configuration type such as hdfs-site.
+     */
+    private String type;
+
+    /**
+     * Configuration tag.
+     */
+    private String tag;
+
+    /**
+     * Properties of the configuration.
+     */
+    private Map<String, String> properties = new HashMap<String, String>();
+
+    /**
+     * Attributes for the properties in the cluster configuration.
+     */
+    private Map<String, Map<String, String>> propertyAttributes = new HashMap<String, Map<String, String>>();
+
+    /**
+     * Constructor.
+     *
+     * @param configNode  configuration node
+     */
+    @SuppressWarnings("unchecked")
+    public ExportedConfiguration(TreeNode<Resource> configNode) {
+      Resource configResource = configNode.getObject();
+      type = (String) configResource.getPropertyValue("type");
+      tag  = (String) configResource.getPropertyValue("tag");
+
+      // property map type is currently <String, Object>
+      Map<String, Map<String, Object>> propertiesMap = configNode.getObject().getPropertiesMap();
+      if (propertiesMap.containsKey("properties")) {
+        properties = (Map) propertiesMap.get("properties");
+      }
+
+      // get the property attributes set in this configuration
+      if (propertiesMap.containsKey("properties_attributes")) {
+        propertyAttributes = (Map) propertiesMap.get("properties_attributes");
+      }
+
+      //todo: not processing config here, ensure that
+      //todo: this logic regarding null/empty properties is properly handled
+//      if (properties != null && !properties.isEmpty()) {
+//        stripRequiredProperties(properties);
+//      } else {
+//        LOG.warn("Empty configuration found for configuration type = " + type +
+//            " during Blueprint export.  This may occur after an upgrade of Ambari, when" +
+//            "attempting to export a Blueprint from a cluster started by an older version of " +
+//            "Ambari.");
+//      }
+
+    }
+
+    /**
+     * Get configuration type.
+     *
+     * @return configuration type
+     */
+    public String getType() {
+      return type;
+    }
+
+    /**
+     * Get configuration tag.
+     *
+     * @return configuration tag
+     */
+    public String getTag() {
+      return tag;
+    }
+
+    /**
+     * Get configuration properties.
+     *
+     * @return map of properties and values
+     */
+    public Map<String, String> getProperties() {
+      return properties;
+    }
+
+    /**
+     * Get property attributes.
+     *
+     * @return map of property attributes
+     */
+    public Map<String, Map<String, String>> getPropertyAttributes() {
+      return propertyAttributes;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      ExportedConfiguration that = (ExportedConfiguration) o;
+      return tag.equals(that.tag) && type.equals(that.type) && properties.equals(that.properties)
+          && propertyAttributes.equals(that.propertyAttributes);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = type.hashCode();
+      result = 31 * result + tag.hashCode();
+      result = 31 * result + properties.hashCode();
+      result = 31 * result + propertyAttributes.hashCode();
+      return result;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
index 4c37d5b..44ebe31 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
@@ -22,7 +22,6 @@ import com.google.inject.Injector;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
-import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
@@ -34,7 +33,6 @@ import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.controller.predicate.AndPredicate;
 import org.apache.ambari.server.controller.predicate.EqualsPredicate;
 import org.apache.ambari.server.controller.predicate.NotPredicate;
-import org.apache.ambari.server.controller.predicate.OrPredicate;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -48,7 +46,6 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
@@ -344,33 +341,56 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro
     return unsupportedProperties;
   }
 
-  RequestStatusResponse installAndStart(String cluster, Collection<String> hosts) throws  SystemException,
+  public RequestStatusResponse install(String cluster, String hostname) throws  SystemException,
       UnsupportedPropertyException, NoSuchParentResourceException {
 
-    final RequestStageContainer requestStages;
+    RequestStageContainer requestStages;
+    //for (String host : hosts) {
+
     Map<String, Object> installProperties = new HashMap<String, Object>();
 
     installProperties.put(HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID, "INSTALLED");
     Map<String, String> requestInfo = new HashMap<String, String>();
-    requestInfo.put("context", "Install and start components on added hosts");
+    requestInfo.put("context", "Install components on added hosts");
     Request installRequest = PropertyHelper.getUpdateRequest(installProperties, requestInfo);
 
-    Collection<EqualsPredicate> hostPredicates = new ArrayList<EqualsPredicate>();
-    for (String host : hosts) {
-      hostPredicates.add(new EqualsPredicate<String>(HOST_COMPONENT_HOST_NAME_PROPERTY_ID, host));
-    }
-
     Predicate statePredicate = new EqualsPredicate<String>(HOST_COMPONENT_STATE_PROPERTY_ID, "INIT");
     Predicate clusterPredicate = new EqualsPredicate<String>(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, cluster);
-    Predicate hostPredicate = new OrPredicate(hostPredicates.toArray(new Predicate[hostPredicates.size()]));
+    // single host
+    Predicate hostPredicate = new EqualsPredicate(HOST_COMPONENT_HOST_NAME_PROPERTY_ID, hostname);
+    //Predicate hostPredicate = new OrPredicate(hostPredicates.toArray(new Predicate[hostPredicates.size()]));
     Predicate hostAndStatePredicate = new AndPredicate(statePredicate, hostPredicate);
     Predicate installPredicate = new AndPredicate(hostAndStatePredicate, clusterPredicate);
 
     try {
-      LOG.info("Installing all components on added hosts");
+      LOG.info("Installing all components on host: " + hostname);
       requestStages = doUpdateResources(null, installRequest, installPredicate, true);
       notifyUpdate(Resource.Type.HostComponent, installRequest, installPredicate);
+      try {
+        requestStages.persist();
+      } catch (AmbariException e) {
+        throw new SystemException(e.getMessage(), e);
+      }
+    } catch (NoSuchResourceException e) {
+      // shouldn't encounter this exception here
+      throw new SystemException("An unexpected exception occurred while processing install hosts",  e);
+      }
+
+    return requestStages.getRequestStatusResponse();
+  }
+
+  public RequestStatusResponse start(String cluster, String hostName) throws  SystemException,
+      UnsupportedPropertyException, NoSuchParentResourceException {
+
+    Map<String, String> requestInfo = new HashMap<String, String>();
+    requestInfo.put("context", "Start components on added hosts");
+
+    Predicate clusterPredicate = new EqualsPredicate<String>(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, cluster);
+    Predicate hostPredicate = new EqualsPredicate(HOST_COMPONENT_HOST_NAME_PROPERTY_ID, hostName);
+    //Predicate hostPredicate = new OrPredicate(hostPredicates.toArray(new Predicate[hostPredicates.size()]));
 
+    RequestStageContainer requestStages;
+    try {
       Map<String, Object> startProperties = new HashMap<String, Object>();
       startProperties.put(HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID, "STARTED");
       Request startRequest = PropertyHelper.getUpdateRequest(startProperties, requestInfo);
@@ -381,24 +401,23 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro
       Predicate installedStatePredicate = new EqualsPredicate<String>(HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID, "INSTALLED");
       Predicate notClientPredicate = new NotPredicate(new ClientComponentPredicate());
       Predicate clusterAndClientPredicate = new AndPredicate(clusterPredicate, notClientPredicate);
-      hostAndStatePredicate = new AndPredicate(installedStatePredicate, hostPredicate);
+      Predicate hostAndStatePredicate = new AndPredicate(installedStatePredicate, hostPredicate);
       Predicate startPredicate = new AndPredicate(clusterAndClientPredicate, hostAndStatePredicate);
 
-      LOG.info("Starting all non-client components on added hosts");
-      //todo: if a host in in state HEARTBEAT_LOST, no stage will be created, so if this occurs during INSTALL
-      //todo: then no INSTALL stage will exist which will result in invalid state transition INIT->STARTED
-      doUpdateResources(requestStages, startRequest, startPredicate, true);
+      LOG.info("Starting all non-client components on host: " + hostName);
+      requestStages = doUpdateResources(null, startRequest, startPredicate, true);
       notifyUpdate(Resource.Type.HostComponent, startRequest, startPredicate);
       try {
         requestStages.persist();
       } catch (AmbariException e) {
         throw new SystemException(e.getMessage(), e);
       }
-      return requestStages.getRequestStatusResponse();
     } catch (NoSuchResourceException e) {
       // shouldn't encounter this exception here
-      throw new SystemException("An unexpected exception occurred while processing add hosts",  e);
+      throw new SystemException("An unexpected exception occurred while processing start hosts",  e);
     }
+
+    return requestStages.getRequestStatusResponse();
   }
 
 
@@ -743,13 +762,15 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro
    */
   private boolean isValidStateTransition(RequestStageContainer stages, State startState,
                                          State desiredState, ServiceComponentHost host) {
-
-    if (stages != null) {
-      State projectedState = stages.getProjectedState(host.getHostName(), host.getServiceComponentName());
-      startState = projectedState == null ? startState : projectedState;
-    }
-
-    return State.isValidStateTransition(startState, desiredState);
+    //todo: After separating install and start, the install stage is no longer included in the passed in request stage container
+    //todo: so we need to re-evaluate this getting projected state from topology manager
+    return true;
+//    if (stages != null) {
+//      State projectedState = stages.getProjectedState(host.getHostName(), host.getServiceComponentName());
+//      startState = projectedState == null ? startState : projectedState;
+//    }
+//
+//    return State.isValidStateTransition(startState, desiredState);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostGroup.java
deleted file mode 100644
index 303bd15..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostGroup.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * 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 java.util.Collection;
-import java.util.Map;
-
-/**
- * Host Group definition.
- */
-public interface HostGroup {
-
-  /**
-   * Get the host group name.
-   *
-   * @return host group name
-   */
-  public String getName();
-
-  /**
-   * Get associated host information.
-   *
-   * @return collection of hosts associated with the host group
-   */
-  public Collection<String> getHostInfo();
-
-  /**
-   * Get the components associated with the host group.
-   *
-   * @return  collection of component names for the host group
-   */
-  public Collection<String> getComponents();
-
-  /**
-   * Get the configurations associated with the host group.
-   *
-   * @return map of configuration type to a map of properties
-   */
-  public Map<String, Map<String, String>> getConfigurationProperties();
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
index 8c51177..45900e4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
@@ -49,17 +49,18 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 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.entities.BlueprintEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.MaintenanceState;
-import org.apache.ambari.server.state.SecurityType;
 import org.apache.ambari.server.state.ServiceComponentHost;
-import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.apache.ambari.server.topology.InvalidTopologyTemplateException;
+import org.apache.ambari.server.topology.TopologyManager;
+import org.apache.ambari.server.topology.TopologyRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,64 +72,65 @@ import com.google.inject.assistedinject.AssistedInject;
 /**
  * Resource provider for host resources.
  */
-public class HostResourceProvider extends BaseBlueprintProcessor {
+public class HostResourceProvider extends AbstractControllerResourceProvider {
 
   // ----- Property ID constants ---------------------------------------------
 
   // Hosts
-  protected static final String HOST_CLUSTER_NAME_PROPERTY_ID =
+  public static final String HOST_CLUSTER_NAME_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "cluster_name");
-  protected static final String HOST_NAME_PROPERTY_ID =
+  public static final String HOST_NAME_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "host_name");
-  protected static final String HOST_PUBLIC_NAME_PROPERTY_ID =
+  public static final String HOST_PUBLIC_NAME_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "public_host_name");
-  protected static final String HOST_IP_PROPERTY_ID =
+  public static final String HOST_IP_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "ip");
-  protected static final String HOST_TOTAL_MEM_PROPERTY_ID =
+  public static final String HOST_TOTAL_MEM_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "total_mem");
-  protected static final String HOST_CPU_COUNT_PROPERTY_ID =
+  public static final String HOST_CPU_COUNT_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "cpu_count");
-  protected static final String HOST_PHYSICAL_CPU_COUNT_PROPERTY_ID =
+  public static final String HOST_PHYSICAL_CPU_COUNT_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "ph_cpu_count");  
-  protected static final String HOST_OS_ARCH_PROPERTY_ID =
+  public static final String HOST_OS_ARCH_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "os_arch");
-  protected static final String HOST_OS_TYPE_PROPERTY_ID =
+  public static final String HOST_OS_TYPE_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "os_type");
-  protected static final String HOST_OS_FAMILY_PROPERTY_ID =
+  public static final String HOST_OS_FAMILY_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "os_family");
-  protected static final String HOST_RACK_INFO_PROPERTY_ID =
+  public static final String HOST_RACK_INFO_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "rack_info");
-  protected static final String HOST_LAST_HEARTBEAT_TIME_PROPERTY_ID =
+  public static final String HOST_LAST_HEARTBEAT_TIME_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "last_heartbeat_time");
-  protected static final String HOST_LAST_REGISTRATION_TIME_PROPERTY_ID =
+  public static final String HOST_LAST_REGISTRATION_TIME_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "last_registration_time");
-  protected static final String HOST_DISK_INFO_PROPERTY_ID =
+  public static final String HOST_DISK_INFO_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "disk_info");
   
   
-  protected static final String HOST_HOST_STATUS_PROPERTY_ID =
+  public static final String HOST_HOST_STATUS_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "host_status");
-  protected static final String HOST_MAINTENANCE_STATE_PROPERTY_ID = 
+  public static final String HOST_MAINTENANCE_STATE_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "maintenance_state");
 
-  protected static final String HOST_HOST_HEALTH_REPORT_PROPERTY_ID =
+  public static final String HOST_HOST_HEALTH_REPORT_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "host_health_report");
-  protected static final String HOST_RECOVERY_REPORT_PROPERTY_ID =
+  public static final String HOST_RECOVERY_REPORT_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "recovery_report");
-  protected static final String HOST_RECOVERY_SUMMARY_PROPERTY_ID =
+  public static final String HOST_RECOVERY_SUMMARY_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "recovery_summary");
-  protected static final String HOST_STATE_PROPERTY_ID =
+  public static final String HOST_STATE_PROPERTY_ID =
+
       PropertyHelper.getPropertyId("Hosts", "host_state");
-  protected static final String HOST_LAST_AGENT_ENV_PROPERTY_ID =
+  public static final String HOST_LAST_AGENT_ENV_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "last_agent_env");
-  protected static final String HOST_DESIRED_CONFIGS_PROPERTY_ID = 
+  public static final String HOST_DESIRED_CONFIGS_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "desired_configs");
 
-  protected static final String BLUEPRINT_PROPERTY_ID =
+  public static final String BLUEPRINT_PROPERTY_ID =
       PropertyHelper.getPropertyId(null, "blueprint");
-  protected static final String HOSTGROUP_PROPERTY_ID =
+  public static final String HOSTGROUP_PROPERTY_ID =
       PropertyHelper.getPropertyId(null, "host_group");
-  protected static final String HOST_NAME_NO_CATEGORY_PROPERTY_ID =
+  public static final String HOST_NAME_NO_CATEGORY_PROPERTY_ID =
       PropertyHelper.getPropertyId(null, "host_name");
 
   private static Set<String> pkPropertyIds =
@@ -141,6 +143,9 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
   @Inject
   private OsFamily osFamily;
 
+  @Inject
+  private static TopologyManager topologyManager;
+
   // ----- Constructors ----------------------------------------------------
 
   /**
@@ -168,7 +173,8 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
 
     RequestStatusResponse createResponse = null;
     if (isHostGroupRequest(request)) {
-      createResponse = addHostsUsingHostgroup(request);
+//      createResponse = addHostsUsingHostgroup(request);
+      createResponse = submitHostRequests(request);
     } else {
       createResources(new Command<Void>() {
         @Override
@@ -178,7 +184,6 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
         }
       });
     }
-
     notifyCreate(Resource.Type.Host, request);
 
     return getRequestStatus(createResponse);
@@ -328,6 +333,9 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
     baseUnsupported.remove(BLUEPRINT_PROPERTY_ID);
     baseUnsupported.remove(HOSTGROUP_PROPERTY_ID);
     baseUnsupported.remove(HOST_NAME_NO_CATEGORY_PROPERTY_ID);
+    //todo: constants
+    baseUnsupported.remove("host_count");
+    baseUnsupported.remove("host_predicate");
 
     return checkConfigPropertyIds(baseUnsupported, "Hosts");
   }
@@ -403,7 +411,7 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
    * @param request Request that must contain registered hosts, and optionally a cluster.
    * @throws AmbariException
    */
-  protected synchronized void createHosts(Request request)
+  public synchronized void createHosts(Request request)
       throws AmbariException {
 
     Set<Map<String, Object>> propertySet = request.getProperties();
@@ -530,145 +538,27 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
     }
   }
 
-
-  /**
-   * Add hosts based on a blueprint and hostgroup.  This will create the necessary resources and install/start all
-   * if the components on the hosts.
-   *
-   * @param request  add hosts request
-   * @return async request response
-   *
-   * @throws ResourceAlreadyExistsException  if an added host already exists in the cluster
-   * @throws SystemException                 in an unknown exception occurs
-   * @throws NoSuchParentResourceException   a parent resource doesnt exist
-   * @throws UnsupportedPropertyException    an unsupported property was specified for the request
-   */
-  private RequestStatusResponse addHostsUsingHostgroup(final Request request)
+  public RequestStatusResponse install(final String hostname, final String cluster)
       throws ResourceAlreadyExistsException,
       SystemException,
       NoSuchParentResourceException,
       UnsupportedPropertyException {
 
-    //todo: idempotency of request.  Need to define failure models ...
-    Set<Map<String, Object>> propertySet = request.getProperties();
-    if (propertySet == null || propertySet.isEmpty()) {
-      LOG.warn("Received a create host request with no associated property sets");
-      return null;
-    }
-
-    Set<String> addedHosts = new HashSet<String>();
-    // all hosts will have same cluster
-    String clusterName = null;
-    for (Map<String, Object> properties : propertySet) {
-      clusterName = (String) properties.get(HOST_CLUSTER_NAME_PROPERTY_ID);
-      String bpName = (String) properties.get(BLUEPRINT_PROPERTY_ID);
-      String hgName = (String) properties.get(HOSTGROUP_PROPERTY_ID);
-      String hostname = getHostNameFromProperties(properties);
-
-      addedHosts.add(hostname);
-
-      String configGroupName = getConfigurationGroupName(bpName, hgName);
-      BlueprintEntity blueprint = getExistingBlueprint(bpName);
-      Stack stack = parseStack(blueprint);
-      Map<String, HostGroupImpl> blueprintHostGroups = parseBlueprintHostGroups(blueprint, stack);
-      addKerberosClientIfNecessary(clusterName, blueprintHostGroups);
-      addHostToHostgroup(hgName, hostname, blueprintHostGroups);
-      createHostAndComponentResources(blueprintHostGroups, clusterName, this);
-      //todo: optimize: update once per hostgroup with added hosts
-      addHostToExistingConfigGroups(configGroupName, clusterName, hostname);
-    }
-    return ((HostComponentResourceProvider) getResourceProvider(Resource.Type.HostComponent)).
-        installAndStart(clusterName, addedHosts);
-  }
 
-  /**
-   * Add the kerberos client to groups if kerberos is enabled for the cluster.
-   *
-   * @param clusterName  cluster name
-   * @param groups       host groups
-   *
-   * @throws NoSuchParentResourceException unable to get cluster instance
-   */
-  private void addKerberosClientIfNecessary(String clusterName, Map<String, HostGroupImpl> groups)
-      throws NoSuchParentResourceException {
-
-    //todo: logic would ideally be contained in the stack
-    Cluster cluster;
-    try {
-      cluster = getManagementController().getClusters().getCluster(clusterName);
-    } catch (AmbariException e) {
-      throw new NoSuchParentResourceException("Parent Cluster resource doesn't exist.  clusterName= " + clusterName);
-    }
-    if (cluster.getSecurityType() == SecurityType.KERBEROS) {
-      for (HostGroupImpl group : groups.values()) {
-        group.addComponent("KERBEROS_CLIENT");
-      }
-    }
-  }
-
-  /**
-   * Add the new host to an existing config group.
-   *
-   * @param configGroupName  name of the config group
-   * @param clusterName      cluster name
-   * @param hostName         host name
-   *
-   * @throws SystemException                an unknown exception occurred
-   * @throws UnsupportedPropertyException   an unsupported property was specified in the request
-   * @throws NoSuchParentResourceException  a parent resource doesn't exist
-   */
-  private void addHostToExistingConfigGroups(String configGroupName, String clusterName, String hostName)
-      throws SystemException,
-      UnsupportedPropertyException,
-      NoSuchParentResourceException {
-
-    Clusters clusters;
-    Cluster cluster;
-    try {
-      clusters = getManagementController().getClusters();
-      cluster = clusters.getCluster(clusterName);
-    } catch (AmbariException e) {
-      throw new IllegalArgumentException(
-          String.format("Attempt to add hosts to a non-existent cluster: '%s'", clusterName));
-    }
-    Map<Long, ConfigGroup> configGroups = cluster.getConfigGroups();
-    for (ConfigGroup group : configGroups.values()) {
-      if (group.getName().equals(configGroupName)) {
-        try {
-          group.addHost(clusters.getHost(hostName));
-          group.persist();
-        } catch (AmbariException e) {
-          // shouldn't occur, this host was just added to the cluster
-          throw new SystemException(String.format(
-              "Unable to obtain newly created host '%s' from cluster '%s'", hostName, clusterName));
-        }
-      }
-    }
+    return ((HostComponentResourceProvider) getResourceProvider(Resource.Type.HostComponent)).
+        install(cluster, hostname);
   }
 
-  /**
-   * Associate a host with a host group.
-   *
-   * @param hostGroupName        name of host group
-   * @param hostname             host name
-   * @param blueprintHostGroups  map of host group name to host group
-   *
-   * @throws IllegalArgumentException if the specified host group doesn't exist
-   */
-  private void addHostToHostgroup(String hostGroupName, String hostname, Map<String, HostGroupImpl> blueprintHostGroups)
-      throws IllegalArgumentException {
-
-    HostGroupImpl hostGroup = blueprintHostGroups.get(hostGroupName);
-    if (hostGroup == null) {
-      // this case should have been caught sooner
-      throw new IllegalArgumentException(String.format("Invalid host_group specified '%s'. " +
-          "All request host groups must have a corresponding host group in the specified blueprint", hostGroupName));
-    }
+  public RequestStatusResponse start(final String hostname, final String cluster)
+      throws ResourceAlreadyExistsException,
+      SystemException,
+      NoSuchParentResourceException,
+      UnsupportedPropertyException {
 
-    hostGroup.addHostInfo(hostname);
+    return ((HostComponentResourceProvider) getResourceProvider(Resource.Type.HostComponent)).
+        start(cluster, hostname);
   }
 
-
   protected Set<HostResponse> getHosts(Set<HostRequest> requests) throws AmbariException {
     Set<HostResponse> response = new HashSet<HostResponse>();
 
@@ -956,4 +846,31 @@ public class HostResourceProvider extends BaseBlueprintProcessor {
     return hostname != null ? hostname :
         (String) properties.get(HOST_NAME_NO_CATEGORY_PROPERTY_ID);
   }
+
+  //todo: for api/v1/hosts we also end up here so we need to ensure proper 400 response
+  //todo: since a user shouldn't be posing to that endpoint
+  private RequestStatusResponse submitHostRequests(Request request) throws SystemException {
+    TopologyRequest requestRequest;
+    try {
+      requestRequest = new ScaleClusterRequest(request);
+    } catch (InvalidTopologyTemplateException e) {
+      throw new IllegalArgumentException("Invalid Add Hosts Template: " + e, e);
+    }
+
+    try {
+      return topologyManager.scaleHosts(requestRequest);
+    } catch (InvalidTopologyException e) {
+      throw new IllegalArgumentException("Topology validation failed: " + e, e);
+    } catch (AmbariException e) {
+      //todo: handle non-system exceptions
+      e.printStackTrace();
+      //todo: for now just throw SystemException
+      throw new SystemException("Unable to add hosts", e);
+    }
+  }
+
+  //todo: proper static injection of topology manager
+  public static void setTopologyManager(TopologyManager topologyManager) {
+    HostResourceProvider.topologyManager = topologyManager;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/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
new file mode 100644
index 0000000..3da92f1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
@@ -0,0 +1,180 @@
+/**
+ * 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.
+ */
+
+//todo: in which package does this belong?  For now it is co-located with resource providers because
+//todo: it needs to understand the syntax of the associated resource provider request
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.PredicateCompiler;
+import org.apache.ambari.server.stack.NoSuchStackException;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.BlueprintFactory;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.ConfigurationFactory;
+import org.apache.ambari.server.topology.HostGroupInfo;
+import org.apache.ambari.server.topology.InvalidTopologyTemplateException;
+import org.apache.ambari.server.topology.NoSuchBlueprintException;
+import org.apache.ambari.server.topology.RequiredPasswordValidator;
+import org.apache.ambari.server.topology.TopologyRequest;
+import org.apache.ambari.server.topology.TopologyValidator;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Request for provisioning a cluster.
+ */
+public class ProvisionClusterRequest implements TopologyRequest {
+
+  private static BlueprintFactory blueprintFactory;
+  private static PredicateCompiler predicateCompiler = new PredicateCompiler();
+  private static ConfigurationFactory configurationFactory = new ConfigurationFactory();
+
+  private String clusterName;
+  private String defaultPassword;
+  private Blueprint blueprint;
+  private Configuration configuration;
+  private Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<String, HostGroupInfo>();
+
+  @SuppressWarnings("unchecked")
+  public ProvisionClusterRequest(Map<String, Object> properties) throws InvalidTopologyTemplateException {
+    this.clusterName = String.valueOf(properties.get(
+        ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID));
+
+    //todo: constant
+    if (properties.containsKey("default_password")) {
+      defaultPassword = String.valueOf(properties.get("default_password"));
+    }
+
+    try {
+      parseBlueprint(properties);
+    } catch (NoSuchStackException e) {
+      throw new InvalidTopologyTemplateException("The specified stack doesn't exist: " + e, e);
+    } catch (NoSuchBlueprintException e) {
+      throw new InvalidTopologyTemplateException("The specified blueprint doesn't exist: " + e, e);
+    }
+    this.configuration = configurationFactory.getConfiguration(
+        (Collection<Map<String, String>>) properties.get("configurations"));
+    this.configuration.setParentConfiguration(blueprint.getConfiguration());
+    //parseConfiguration(properties);
+    parseHostGroupInfo(properties);
+  }
+
+  //todo:
+  public static void init(BlueprintFactory factory) {
+    blueprintFactory = factory;
+  }
+
+  @Override
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  @Override
+  public Blueprint getBlueprint() {
+    return blueprint;
+  }
+
+  @Override
+  public Configuration getConfiguration() {
+    return configuration;
+  }
+
+  @Override
+  //todo: return copy?
+  public Map<String, HostGroupInfo> getHostGroupInfo() {
+    return hostGroupInfoMap;
+  }
+
+  @Override
+  public List<TopologyValidator> getTopologyValidators() {
+    return Collections.<TopologyValidator>singletonList(new RequiredPasswordValidator(defaultPassword));
+  }
+
+  private void parseBlueprint(Map<String, Object> properties) throws NoSuchStackException, NoSuchBlueprintException {
+    String blueprintName = String.valueOf(properties.get(ClusterResourceProvider.BLUEPRINT_PROPERTY_ID));
+    blueprint = blueprintFactory.getBlueprint(blueprintName);
+
+    if (blueprint == null) {
+      throw new NoSuchBlueprintException(blueprintName);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void parseHostGroupInfo(Map<String, Object> properties) throws InvalidTopologyTemplateException {
+    Collection<Map<String, Object>> hostGroups =
+        (Collection<Map<String, Object>>) properties.get("host_groups");
+
+    if (hostGroups == null || hostGroups.isEmpty()) {
+      throw new InvalidTopologyTemplateException("'host_groups' element must be included in cluster create body");
+    }
+
+    // iterate over host groups provided in request body
+    for (Map<String, Object> hostGroupProperties : hostGroups) {
+      String name = String.valueOf(hostGroupProperties.get("name"));
+      // String.valueOf() converts null to "null"
+      if (name.equals("null") || name.isEmpty()) {
+        throw new InvalidTopologyTemplateException("All host groups must contain a 'name' element");
+      }
+
+      Collection hosts = (Collection) hostGroupProperties.get("hosts");
+      if (hosts == null || hosts.isEmpty()) {
+        throw new InvalidTopologyTemplateException("Host group '" + name + "' must contain a 'hosts' element");
+      }
+
+      // blueprint was parsed already
+      HostGroupInfo hostGroupInfo = new HostGroupInfo(name);
+      hostGroupInfoMap.put(name, hostGroupInfo);
+
+      for (Object oHost : hosts) {
+        Map<String, String> hostProperties = (Map<String, String>) oHost;
+        //add host information to host group
+        String fqdn = hostProperties.get("fqdn");
+        if (fqdn == null || fqdn.isEmpty()) {
+          //todo: validate the host_name and host_predicate are not both specified for same group
+          String predicate = hostProperties.get("host_predicate");
+          if (predicate != null && ! predicate.isEmpty()) {
+            try {
+              hostGroupInfo.setPredicate(predicateCompiler.compile(predicate));
+            } catch (InvalidQueryException e) {
+              throw new InvalidTopologyTemplateException(
+                  String.format("Unable to compile host predicate '%s': %s", predicate, e), e);
+            }
+          }
+
+          if (hostProperties.containsKey("host_count")) {
+            hostGroupInfo.setRequestedCount(Integer.valueOf(hostProperties.get("host_count")));
+          } else {
+            throw new InvalidTopologyTemplateException(
+                "Host group '" + name + "' hosts element must include at least one fqdn" +
+                " or a host_count must be specified");
+          }
+        } else {
+          hostGroupInfo.addHost(fqdn);
+        }
+      }
+      // don't set the parent configuration
+      hostGroupInfo.setConfiguration(configurationFactory.getConfiguration(
+          (Collection<Map<String, String>>) hostGroupProperties.get("configurations")));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
index 1d5d90a..fa49d7f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
@@ -54,6 +54,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 
 import com.google.inject.Inject;
+import org.apache.ambari.server.topology.TopologyManager;
 
 /**
  * Resource provider for request resources.
@@ -67,6 +68,9 @@ public class RequestResourceProvider extends AbstractControllerResourceProvider
   @Inject
   private static HostRoleCommandDAO s_hostRoleCommandDAO = null;
 
+  @Inject
+  private static TopologyManager topologyManager;
+
   // ----- Property ID constants ---------------------------------------------
   // Requests
   public static final String REQUEST_CLUSTER_NAME_PROPERTY_ID = "Requests/cluster_name";
@@ -433,6 +437,23 @@ public class RequestResourceProvider extends AbstractControllerResourceProvider
     Map<Long, Resource> resourceMap = new HashMap<Long, Resource>();
 
     List<RequestEntity> requests = s_requestDAO.findByPks(requestIds, true);
+
+
+    //todo: this was (and still is) in ActionManager but this class was changed to not use ActionManager recently
+    List<RequestEntity> topologyRequestEntities = new ArrayList<RequestEntity>();
+    Collection<? extends org.apache.ambari.server.actionmanager.Request> topologyRequests =
+        topologyManager.getRequests(requestIds);
+    for (org.apache.ambari.server.actionmanager.Request request : topologyRequests) {
+      topologyRequestEntities.add(request.constructNewPersistenceEntity());
+    }
+
+    // if requests is empty, map is Collections.emptyMap() which can't be added to so create a new map
+    if (requests.isEmpty()) {
+      requests = new ArrayList<RequestEntity>();
+    }
+
+    requests.addAll(topologyRequestEntities);
+
     for (RequestEntity re : requests) {
       if ((null == clusterId && (null == re.getClusterId() || -1L == re.getClusterId())) ||
           (null != clusterId && null != re.getRequestId() && re.getClusterId().equals(clusterId))) {
@@ -480,6 +501,10 @@ public class RequestResourceProvider extends AbstractControllerResourceProvider
 
 
     Map<Long, HostRoleCommandStatusSummaryDTO> summary = s_hostRoleCommandDAO.findAggregateCounts(entity.getRequestId());
+
+    // get summaries from TopologyManager for logical requests
+    summary.putAll(topologyManager.getStageSummaries(entity.getRequestId()));
+
     CalculatedStatus status = CalculatedStatus.statusFromStageSummary(summary, summary.keySet());
 
     setResourceProperty(resource, REQUEST_STATUS_PROPERTY_ID, status.getStatus().toString(), requestedPropertyIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ScaleClusterRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ScaleClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ScaleClusterRequest.java
new file mode 100644
index 0000000..f3e45aa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ScaleClusterRequest.java
@@ -0,0 +1,156 @@
+/**
+ * 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 org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.PredicateCompiler;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.stack.NoSuchStackException;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.BlueprintFactory;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.HostGroupInfo;
+import org.apache.ambari.server.topology.InvalidTopologyTemplateException;
+import org.apache.ambari.server.topology.TopologyRequest;
+import org.apache.ambari.server.topology.TopologyValidator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A request for a scaling an existing cluster.
+ */
+public class ScaleClusterRequest implements TopologyRequest {
+
+  private static BlueprintFactory blueprintFactory;
+  private static final PredicateCompiler predicateCompiler = new PredicateCompiler();
+
+  private String clusterName;
+
+  private Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<String, HostGroupInfo>();
+
+  public static void init(BlueprintFactory factory) {
+    blueprintFactory = factory;
+  }
+
+  public ScaleClusterRequest(Request request) throws InvalidTopologyTemplateException {
+    for (Map<String, Object> properties : request.getProperties()) {
+      // can only operate on a single cluster per logical request
+      if (clusterName == null) {
+        clusterName = String.valueOf(properties.get(HostResourceProvider.HOST_CLUSTER_NAME_PROPERTY_ID));
+      }
+      parseHostGroup(properties);
+    }
+  }
+
+  private void parseHostGroup(Map<String, Object> properties) throws InvalidTopologyTemplateException {
+    String hgName = String.valueOf(properties.get(HostResourceProvider.HOSTGROUP_PROPERTY_ID));
+    //todo: need to use fully qualified host group name.  For now, disregard name collisions across BP's
+    HostGroupInfo hostGroupInfo = hostGroupInfoMap.get(hgName);
+
+    if (hostGroupInfo == null) {
+      String bpName = String.valueOf(properties.get(HostResourceProvider.BLUEPRINT_PROPERTY_ID));
+      Blueprint blueprint = parseBlueprint(bpName);
+
+      if (blueprint.getHostGroup(hgName) == null) {
+        throw new InvalidTopologyTemplateException("Invalid host group specified in request: " + hgName);
+      }
+      hostGroupInfo = new HostGroupInfo(hgName);
+      hostGroupInfoMap.put(hgName, hostGroupInfo);
+    }
+
+    // process host_name and host_count
+    if (properties.containsKey("host_count")) {
+
+      //todo: validate the host_name and host_predicate are not both specified for same group
+      //todo: validate that when predicate is specified that only a single host group entry is specified
+      String predicate = String.valueOf(properties.get("host_predicate"));
+      if (predicate != null && ! predicate.isEmpty()) {
+        try {
+          hostGroupInfo.setPredicate(predicateCompiler.compile(predicate));
+        } catch (InvalidQueryException e) {
+          throw new InvalidTopologyTemplateException(
+              String.format("Unable to compile host predicate '%s': %s", predicate, e), e);
+        }
+      }
+
+      if (! hostGroupInfo.getHostNames().isEmpty()) {
+        throw new InvalidTopologyTemplateException("Can't specify both host_name and host_count for the same hostgroup: " + hgName);
+      }
+      hostGroupInfo.setRequestedCount(Integer.valueOf(String.valueOf(properties.get("host_count"))));
+    } else {
+      if (hostGroupInfo.getRequestedHostCount() != hostGroupInfo.getHostNames().size()) {
+        throw new InvalidTopologyTemplateException("Can't specify both host_name and host_count for the same hostgroup: " + hgName);
+      }
+      hostGroupInfo.addHost(getHostNameFromProperties(properties));
+    }
+  }
+
+  @Override
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  @Override
+  public Blueprint getBlueprint() {
+    // bp is only set at HG level from scaling operations
+    return null;
+  }
+
+  @Override
+  public Configuration getConfiguration() {
+    // currently don't allow cluster scoped configuration in scaling operation
+    return null;
+  }
+
+  @Override
+  public Map<String, HostGroupInfo> getHostGroupInfo() {
+    return hostGroupInfoMap;
+  }
+
+  @Override
+  public List<TopologyValidator> getTopologyValidators() {
+    return Collections.emptyList();
+  }
+
+  private Blueprint parseBlueprint(String blueprintName) throws InvalidTopologyTemplateException  {
+    Blueprint blueprint;
+    try {
+      blueprint = blueprintFactory.getBlueprint(blueprintName);
+    } catch (NoSuchStackException e) {
+      throw new InvalidTopologyTemplateException("Invalid stack specified in the blueprint: " + blueprintName);
+    }
+
+    if (blueprint == null) {
+      throw new InvalidTopologyTemplateException("The specified blueprint doesn't exist: " + blueprintName);
+    }
+    return blueprint;
+  }
+
+  //todo: this was copied exactly from HostResourceProvider
+  private String getHostNameFromProperties(Map<String, Object> properties) {
+    String hostname = String.valueOf(properties.get(HostResourceProvider.HOST_NAME_PROPERTY_ID));
+
+    return hostname != null ? hostname :
+        String.valueOf(properties.get(HostResourceProvider.HOST_NAME_NO_CATEGORY_PROPERTY_ID));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c9f0dd0b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
index e715d42..96cad45 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
@@ -37,8 +37,6 @@ import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.controller.ServiceRequest;
 import org.apache.ambari.server.controller.ServiceResponse;
-import org.apache.ambari.server.controller.predicate.AndPredicate;
-import org.apache.ambari.server.controller.predicate.EqualsPredicate;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -48,7 +46,6 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
-import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.serveraction.kerberos.KerberosAdminAuthenticationException;
@@ -63,10 +60,7 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
-import org.apache.ambari.server.state.stack.WidgetLayout;
-import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
 import org.apache.commons.lang.StringUtils;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -77,7 +71,6 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -91,10 +84,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
   // ----- Property ID constants ---------------------------------------------
 
   // Services
-  protected static final String SERVICE_CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "cluster_name");
-  protected static final String SERVICE_SERVICE_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "service_name");
-  protected static final String SERVICE_SERVICE_STATE_PROPERTY_ID   = PropertyHelper.getPropertyId("ServiceInfo", "state");
-  protected static final String SERVICE_MAINTENANCE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "maintenance_state");
+  public static final String SERVICE_CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "cluster_name");
+  public static final String SERVICE_SERVICE_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "service_name");
+  public static final String SERVICE_SERVICE_STATE_PROPERTY_ID   = PropertyHelper.getPropertyId("ServiceInfo", "state");
+  public static final String SERVICE_MAINTENANCE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "maintenance_state");
 
   //Parameters from the predicate
   private static final String QUERY_PARAMETERS_RUN_SMOKE_TEST_ID =
@@ -286,52 +279,6 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
     return pkPropertyIds;
   }
 
-
-  // ----- ServiceResourceProvider -----------------------------------------
-
-  RequestStatusResponse installAndStart(String clusterName) throws  SystemException,
-      UnsupportedPropertyException, NoSuchParentResourceException {
-
-    final RequestStageContainer requestStages;
-    Map<String, Object> installProperties = new HashMap<String, Object>();
-    installProperties.put(SERVICE_SERVICE_STATE_PROPERTY_ID, "INSTALLED");
-    Map<String, String> requestInfo = new HashMap<String, String>();
-    requestInfo.put("context", "Install and start all services");
-    Request installRequest = new RequestImpl(null, Collections.singleton(installProperties), requestInfo, null);
-    Predicate statePredicate = new EqualsPredicate<String>(SERVICE_SERVICE_STATE_PROPERTY_ID, "INIT");
-    Predicate clusterPredicate = new EqualsPredicate<String>(SERVICE_CLUSTER_NAME_PROPERTY_ID, clusterName);
-    Predicate installPredicate = new AndPredicate(statePredicate, clusterPredicate);
-
-    final Request startRequest;
-    Predicate startPredicate;
-    try {
-      LOG.info("Installing all services");
-      requestStages = doUpdateResources(null, installRequest, installPredicate);
-      notifyUpdate(Resource.Type.Service, installRequest, installPredicate);
-
-      Map<String, Object> startProperties = new HashMap<String, Object>();
-      startProperties.put(SERVICE_SERVICE_STATE_PROPERTY_ID, "STARTED");
-      startRequest = new RequestImpl(null, Collections.singleton(startProperties), requestInfo, null);
-      Predicate installedStatePredicate = new EqualsPredicate<String>(SERVICE_SERVICE_STATE_PROPERTY_ID, "INSTALLED");
-      Predicate serviceClusterPredicate = new EqualsPredicate<String>(SERVICE_CLUSTER_NAME_PROPERTY_ID, clusterName);
-      startPredicate = new AndPredicate(installedStatePredicate, serviceClusterPredicate);
-
-      LOG.info("Starting all services");
-      doUpdateResources(requestStages, startRequest, startPredicate);
-      notifyUpdate(Resource.Type.Service, startRequest, startPredicate);
-      try {
-        requestStages.persist();
-      } catch (AmbariException e) {
-        throw new SystemException(e.getMessage(), e);
-      }
-      return requestStages.getRequestStatusResponse();
-
-    } catch (NoSuchResourceException e) {
-      throw new SystemException("Attempted to modify a non-existing service",  e);
-    }
-  }
-
-
   // ----- utility methods -------------------------------------------------
 
   private RequestStageContainer doUpdateResources(final RequestStageContainer stages, final Request request, Predicate predicate)
@@ -388,7 +335,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
   }
 
   // Create services from the given request.
-  protected synchronized void createServices(Set<ServiceRequest> requests)
+  public synchronized void createServices(Set<ServiceRequest> requests)
       throws AmbariException {
 
     if (requests.isEmpty()) {


Mime
View raw message