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()) {
