diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java index 77eafebf4bd..0d243a2f551 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseClusterRequest.java @@ -29,6 +29,7 @@ import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.utilities.ClusterControllerHelper; +import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.topology.Blueprint; import org.apache.ambari.server.topology.BlueprintFactory; import org.apache.ambari.server.topology.Configuration; @@ -36,6 +37,7 @@ import org.apache.ambari.server.topology.InvalidTopologyTemplateException; import org.apache.ambari.server.topology.SecurityConfiguration; import org.apache.ambari.server.topology.TopologyRequest; +import org.apache.ambari.server.topology.TopologyRequestUtil; /** * Provides common cluster request functionality. @@ -53,6 +55,11 @@ public abstract class BaseClusterRequest implements TopologyRequest { protected ProvisionAction provisionAction; + /** + * The raw request body. We would like to persist it. + */ + protected String rawRequestBody; + /** * cluster id */ @@ -118,6 +125,19 @@ public Map getHostGroupInfo() { return hostGroupInfoMap; } + /** + * @return the raw request body in JSON string + */ + public String getRawRequestBody() { + return rawRequestBody; + } + + @Override + public Set getStackIds() { + return TopologyRequestUtil.getStackIdsFromRequest( + TopologyRequestUtil.getPropertyMap(rawRequestBody)); + } + /** * Validate that all properties specified in the predicate are valid for the Host resource. * @@ -180,6 +200,7 @@ public SecurityConfiguration getSecurityConfiguration() { return securityConfiguration; } + /** * Get the host resource provider instance. * diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java index f03231bfac1..baf64e05e75 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java @@ -533,7 +533,8 @@ private RequestStatusResponse processBlueprintCreate(Map propert ProvisionClusterRequest createClusterRequest; try { - createClusterRequest = topologyRequestFactory.createProvisionClusterRequest(properties, securityConfiguration); + createClusterRequest = + topologyRequestFactory.createProvisionClusterRequest(rawRequestBody, properties, securityConfiguration); } catch (InvalidTopologyTemplateException e) { throw new IllegalArgumentException("Invalid Cluster Creation Template: " + e, e); } 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 79f4233ebce..412d0c0eac2 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 @@ -1086,7 +1086,9 @@ public static String getHostNameFromProperties(Map properties) { private RequestStatusResponse submitHostRequests(Request request) throws SystemException { ScaleClusterRequest requestRequest; try { - requestRequest = new ScaleClusterRequest(request.getProperties()); + requestRequest = new ScaleClusterRequest( + request.getRequestInfoProperties().get(Request.REQUEST_INFO_BODY_PROPERTY), + request.getProperties()); } catch (InvalidTopologyTemplateException e) { throw new IllegalArgumentException("Invalid Add Hosts Template: " + e, e); } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java index 70b8ab54b34..7a5086d6b48 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java @@ -174,8 +174,10 @@ public class ProvisionClusterRequest extends BaseClusterRequest implements Provi * @param properties request properties * @param securityConfiguration security config related properties */ - public ProvisionClusterRequest(Map properties, SecurityConfiguration securityConfiguration) throws + public ProvisionClusterRequest(String rawRequestBody, Map properties, SecurityConfiguration securityConfiguration) throws InvalidTopologyTemplateException { + this.rawRequestBody = rawRequestBody; + setClusterName(String.valueOf(properties.get( ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID))); 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 index 5e5eec8936e..958a3d58fb7 100644 --- 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 @@ -51,7 +51,8 @@ public class ScaleClusterRequest extends BaseClusterRequest { * * @throws InvalidTopologyTemplateException if any validation of properties fails */ - public ScaleClusterRequest(Set> propertySet) throws InvalidTopologyTemplateException { + public ScaleClusterRequest(String rawRequestBody, Set> propertySet) throws InvalidTopologyTemplateException { + this.rawRequestBody = rawRequestBody; for (Map properties : propertySet) { // can only operate on a single cluster per logical request if (getClusterName() == null) { diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/TopologyRequestEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/TopologyRequestEntity.java index d28183882ed..d9ab181d455 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/TopologyRequestEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/TopologyRequestEntity.java @@ -75,6 +75,10 @@ public class TopologyRequestEntity { @Column(name = "description", length = 1024, nullable = false) private String description; + @Lob + @Column(name = "raw_request_body", length = 100000, nullable = false) + private String rawRequestBody; + @OneToMany(mappedBy = "topologyRequestEntity", cascade = CascadeType.ALL) private Collection topologyHostGroupEntities; @@ -141,6 +145,20 @@ public void setDescription(String description) { this.description = description; } + /** + * @return the raw request body in JSON + */ + public String getRawRequestBody() { + return rawRequestBody; + } + + /** + * @param rawRequestBody the raw request body in JSON + */ + public void setRawRequestBody(String rawRequestBody) { + this.rawRequestBody = rawRequestBody; + } + public Collection getTopologyHostGroupEntities() { return topologyHostGroupEntities; } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintBasedClusterProvisionRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintBasedClusterProvisionRequest.java index 43f372457ed..22d4bab2e07 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintBasedClusterProvisionRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintBasedClusterProvisionRequest.java @@ -24,7 +24,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Function; -import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -37,7 +36,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -52,7 +50,7 @@ public class BlueprintBasedClusterProvisionRequest implements Blueprint, Provisi private final ProvisionClusterRequest request; private final Set stackIds; private final StackDefinition stack; - private final Map mpacks; + private final Set mpacks; private final SecurityConfiguration securityConfiguration; public BlueprintBasedClusterProvisionRequest(AmbariContext ambariContext, SecurityConfigurationFactory securityConfigurationFactory, Blueprint blueprint, ProvisionClusterRequest request) { @@ -61,9 +59,9 @@ public BlueprintBasedClusterProvisionRequest(AmbariContext ambariContext, Securi stackIds = ImmutableSet.copyOf(Sets.union(blueprint.getStackIds(), request.getStackIds())); stack = ambariContext.composeStacks(stackIds); - mpacks = ImmutableMap.copyOf( - Stream.concat(blueprint.getMpacks().stream(), request.getMpacks().stream()) - .collect(toMap(MpackInstance::getMpackName, Function.identity()))); + mpacks = ImmutableSet.builder(). + addAll(blueprint.getMpacks()). + addAll(request.getMpacks()).build(); securityConfiguration = processSecurityConfiguration(securityConfigurationFactory); @@ -104,7 +102,7 @@ public Set getStackIds() { @Override public Collection getMpacks() { - return mpacks.values(); + return mpacks; } @Override @@ -166,7 +164,7 @@ public StackDefinition getStack() { public Map> getServicesByMpack() { Map> result = new HashMap<>(); - for (MpackInstance mpack : mpacks.values()) { + for (MpackInstance mpack : mpacks) { Map services = mpack.getServiceInstances().stream() .collect(toMap(ServiceInstance::getName, Function.identity())); result.put(mpack.getMpackName(), services); @@ -179,7 +177,7 @@ public Map> getServicesByMpack() { * whose name is unique across all mpacks. */ public Map getUniqueServices() { - Map map = mpacks.values().stream() + Map map = mpacks.stream() .flatMap(mpack -> mpack.getServiceInstances().stream()) .collect(toMap(ServiceInstance::getName, Function.identity(), (s1, s2) -> null)); map.entrySet().removeIf(e -> e.getValue() == null); // remove non-unique names mapped to null diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java index 95814579f19..1ea1101d0fb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterTopologyImpl.java @@ -46,6 +46,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; /** * Represents a cluster topology. @@ -68,18 +69,21 @@ public class ClusterTopologyImpl implements ClusterTopology { private final BlueprintBasedClusterProvisionRequest provisionRequest; private final String defaultPassword; private final Map> resolvedComponents; + private final Setting setting; public ClusterTopologyImpl(AmbariContext ambariContext, TopologyRequest topologyRequest) throws InvalidTopologyException { this.ambariContext = ambariContext; this.clusterId = topologyRequest.getClusterId(); this.blueprint = topologyRequest.getBlueprint(); + this.setting = blueprint.getSetting(); this.configuration = topologyRequest.getConfiguration(); configRecommendationStrategy = ConfigRecommendationStrategy.NEVER_APPLY; provisionAction = topologyRequest instanceof BaseClusterRequest ? ((BaseClusterRequest) topologyRequest).getProvisionAction() : INSTALL_AND_START; // FIXME provisionRequest = null; defaultPassword = null; - stackIds = topologyRequest.getBlueprint().getStackIds(); + stackIds = ImmutableSet.copyOf( + Sets.union(topologyRequest.getStackIds(), topologyRequest.getBlueprint().getStackIds())); stack = ambariContext.composeStacks(stackIds); resolvedComponents = ImmutableMap.of(); @@ -104,7 +108,7 @@ public ClusterTopologyImpl( defaultPassword = provisionRequest.getDefaultPassword(); stackIds = request.getStackIds(); stack = request.getStack(); - + setting = request.getSetting(); blueprint.getConfiguration().setParentConfiguration(stack.getConfiguration(getServices())); registerHostGroupInfo(request.getHostGroupInfo()); } @@ -150,7 +154,7 @@ public Configuration getConfiguration() { @Override public Setting getSetting() { - return provisionRequest.getSetting(); + return setting; } @Override diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/PersistedStateImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/PersistedStateImpl.java index 13c9eff95e6..ae70db467de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/PersistedStateImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/PersistedStateImpl.java @@ -23,7 +23,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import javax.inject.Inject; import javax.inject.Singleton; import org.apache.ambari.server.AmbariException; @@ -50,12 +52,12 @@ import org.apache.ambari.server.orm.entities.TopologyRequestEntity; import org.apache.ambari.server.stack.NoSuchStackException; import org.apache.ambari.server.state.Host; +import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.topology.tasks.TopologyTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; -import com.google.inject.Inject; import com.google.inject.persist.Transactional; /** @@ -91,9 +93,6 @@ public class PersistedStateImpl implements PersistedState { @Inject private HostRoleCommandDAO hostRoleCommandDAO; - @Inject - private HostRoleCommandDAO physicalTaskDAO; - @Inject private BlueprintFactory blueprintFactory; @@ -255,6 +254,8 @@ public Map> getAllRequests() { private TopologyRequestEntity toEntity(BaseClusterRequest request) { TopologyRequestEntity entity = new TopologyRequestEntity(); + entity.setRawRequestBody(request.getRawRequestBody()); + //todo: this isn't set for a scaling operation because we had intended to allow multiple //todo: bp's to be used to scale a cluster although this isn't currently supported by //todo: new topology infrastructure @@ -330,7 +331,7 @@ private TopologyHostRequestEntity toEntity(HostRequest request, TopologyLogicalR logicalTaskEntity.setTopologyHostTaskEntity(topologyTaskEntity); Long physicalId = request.getPhysicalTaskId(logicalTaskId); if (physicalId != null) { - logicalTaskEntity.setHostRoleCommandEntity(physicalTaskDAO.findByPK(physicalId)); + logicalTaskEntity.setHostRoleCommandEntity(hostRoleCommandDAO.findByPK(physicalId)); } logicalTaskEntity.setTopologyHostTaskEntity(topologyTaskEntity); } @@ -391,6 +392,7 @@ private static class ReplayedTopologyRequest implements TopologyRequest { private final Configuration configuration; private final Map hostGroupInfoMap = new HashMap<>(); private final ProvisionAction provisionAction; + private final Set stackIds; public ReplayedTopologyRequest(TopologyRequestEntity entity, BlueprintFactory blueprintFactory) { clusterId = entity.getClusterId(); @@ -398,6 +400,8 @@ public ReplayedTopologyRequest(TopologyRequestEntity entity, BlueprintFactory bl description = entity.getDescription(); provisionAction = entity.getProvisionAction(); + stackIds = TopologyRequestUtil.getStackIdsFromRequest(entity.getRawRequestBody()); + try { blueprint = blueprintFactory.getBlueprint(entity.getBlueprintName()); } catch (NoSuchStackException e) { @@ -409,6 +413,11 @@ public ReplayedTopologyRequest(TopologyRequestEntity entity, BlueprintFactory bl parseHostGroupInfo(entity); } + @Override + public Set getStackIds() { + return stackIds; + } + @Override public Long getClusterId() { return clusterId; diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequest.java index 94fcf23e3b1..ffdf1c79ef5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequest.java @@ -18,7 +18,12 @@ package org.apache.ambari.server.topology; +import static java.util.Collections.emptySet; + import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.state.StackId; /** * A request which is used to create or modify a cluster topology. @@ -70,4 +75,11 @@ enum Type { PROVISION, SCALE, EXPORT } * @return string description of the request */ String getDescription(); + + /** + * @return a set of stack id's if supported by the TopologyRequest. + */ + default Set getStackIds() { + return emptySet(); + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactory.java index 751e2d7a851..136be393d48 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactory.java @@ -28,6 +28,6 @@ */ public interface TopologyRequestFactory { - ProvisionClusterRequest createProvisionClusterRequest(Map properties, SecurityConfiguration securityConfiguration) throws InvalidTopologyTemplateException; + ProvisionClusterRequest createProvisionClusterRequest(String rawRequestBody, Map properties, SecurityConfiguration securityConfiguration) throws InvalidTopologyTemplateException; // todo: use to create other request types } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactoryImpl.java index 44f0d1f02ac..50d3fa1226e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactoryImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestFactoryImpl.java @@ -29,8 +29,7 @@ public class TopologyRequestFactoryImpl implements TopologyRequestFactory { @Override - public ProvisionClusterRequest createProvisionClusterRequest(Map properties, SecurityConfiguration securityConfiguration) throws InvalidTopologyTemplateException { - return new ProvisionClusterRequest(properties, securityConfiguration); - + public ProvisionClusterRequest createProvisionClusterRequest(String rawRequestBody, Map properties, SecurityConfiguration securityConfiguration) throws InvalidTopologyTemplateException { + return new ProvisionClusterRequest(rawRequestBody, properties, securityConfiguration); } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestUtil.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestUtil.java new file mode 100644 index 00000000000..1b160a41c36 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyRequestUtil.java @@ -0,0 +1,76 @@ +/* + * 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.topology; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toSet; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.utils.JsonUtils; + +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * Utility functions for topology requests. + */ +public class TopologyRequestUtil { + + public static final String NAME = "name"; + public static final String VERSION = "version"; + + + /** + * @param rawRequestJson The topology request in raw JSON format. Null input is handled gracefully. + * @return a Set of stack id's contained in the request + */ + public static Set getStackIdsFromRequest(String rawRequestJson) { + return getStackIdsFromRequest(getPropertyMap(rawRequestJson)); + } + + + /** + * @param rawRequestMap The topology request in raw JSON format. Null input is handled gracefully. + * @return a Set of stack id's contained in the request + */ + public static Set getStackIdsFromRequest(Map rawRequestMap) { + List> mpackInstances = (List>) + rawRequestMap.getOrDefault("mpack_instances", emptyList()); + return mpackInstances.stream().map(m -> { + checkArgument(m.containsKey(NAME), "Missing mpack name"); + checkArgument(m.containsKey(VERSION), "Missing mpack version"); + return new StackId(m.get(NAME), m.get(VERSION)); + }).collect(toSet()); + } + + /** + * @param rawRequestJson The topology request in raw JSON format. Null input is handled gracefully. + * @return the request body parsed as map (null is parsed as empty map) + */ + public static Map getPropertyMap(String rawRequestJson) { + return null == rawRequestJson ? + emptyMap() : + JsonUtils.fromJson(rawRequestJson, new TypeReference>() {}); + } +} diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql index 3b0b5eeea58..a3e9bc0e993 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql @@ -887,6 +887,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body CLOB NOT NULL, cluster_properties VARCHAR(3000), cluster_attributes VARCHAR(3000), description VARCHAR(1024), diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql index 1ca41884288..852024e66e9 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql @@ -904,6 +904,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body LONGTEXT NOT NULL, cluster_properties LONGTEXT, cluster_attributes LONGTEXT, description VARCHAR(1024), diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql index 975d0202d46..29b0376f8f7 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql @@ -136,7 +136,8 @@ CREATE TABLE servicegroups ( stack_id NUMBER(19) NOT NULL, CONSTRAINT PK_servicegroups PRIMARY KEY (id, cluster_id), CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id), - CONSTRAINT FK_servicegroups_stack_id FOREIGN KEY (stack_id) REFERENCES stack (stack_id)); + CONSTRAINT FK_servicegroups_stack_id FOREIGN KEY (stack_id) REFERENCES stack (stack_id), + CONSTRAINT UQ_TEMP_UNTIL_REAL_PK UNIQUE(id)); CREATE TABLE servicegroupdependencies ( id NUMBER(19) NOT NULL, @@ -208,8 +209,7 @@ CREATE TABLE serviceconfig ( CONSTRAINT PK_serviceconfig PRIMARY KEY (service_config_id), CONSTRAINT FK_serviceconfig_stack_id FOREIGN KEY (stack_id) REFERENCES stack(stack_id), CONSTRAINT FK_serviceconfig_clstr_svc FOREIGN KEY (service_id, service_group_id, cluster_id) REFERENCES clusterservices (id, service_group_id, cluster_id), - CONSTRAINT UQ_scv_service_version UNIQUE (cluster_id, service_id, version), - CONSTRAINT UQ_TEMP_UNTIL_REAL_PK UNIQUE(id)); + CONSTRAINT UQ_scv_service_version UNIQUE (cluster_id, service_id, version) ); CREATE TABLE serviceconfighosts ( service_config_id NUMBER(19) NOT NULL, @@ -882,6 +882,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id NUMBER(19) NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body CLOB NOT NULL, cluster_properties CLOB, cluster_attributes CLOB, description VARCHAR(1024), diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql index 2fcfaa72090..255f9f2197d 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql @@ -888,6 +888,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body TEXT NOT NULL, cluster_properties TEXT, cluster_attributes TEXT, description VARCHAR(1024), diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql index 7f0373adef5..ecab751ac7e 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql @@ -882,6 +882,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id NUMERIC(19) NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body TEXT NOT NULL, cluster_properties TEXT, cluster_attributes TEXT, description VARCHAR(1024), diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql index fdf6e470504..64762402a01 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql @@ -147,6 +147,7 @@ CREATE TABLE servicegroups ( id BIGINT NOT NULL, service_group_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, + stack_id BIGINT NOT NULL, CONSTRAINT PK_servicegroups PRIMARY KEY (id, cluster_id), CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id), CONSTRAINT FK_servicegroups_stack_id FOREIGN KEY (stack_id) REFERENCES stack (stack_id), @@ -904,6 +905,7 @@ CREATE TABLE topology_request ( action VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, bp_name VARCHAR(100) NOT NULL, + raw_request_body TEXT NOT NULL, cluster_properties TEXT, cluster_attributes TEXT, description VARCHAR(1024), diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java index 5e1ba49baab..06d95bd660d 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java @@ -20,6 +20,7 @@ import static org.easymock.EasyMock.anyBoolean; import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.anyString; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createNiceMock; @@ -154,7 +155,7 @@ public void testCreateResource_blueprint_With_ProvisionAction() throws Exception expect(securityFactory.createSecurityConfigurationFromRequest(EasyMock.anyObject(), anyBoolean())).andReturn(null) .once(); - expect(topologyFactory.createProvisionClusterRequest(properties, null)).andReturn(topologyRequest).once(); + expect(topologyFactory.createProvisionClusterRequest("{}", properties, null)).andReturn(topologyRequest).once(); expect(topologyManager.provisionCluster(topologyRequest)).andReturn(requestStatusResponse).once(); expect(requestStatusResponse.getRequestId()).andReturn(5150L).anyTimes(); @@ -184,7 +185,7 @@ public void testCreateResource_blueprint_withSecurityConfiguration() throws Exce expect(request.getProperties()).andReturn(requestProperties).anyTimes(); expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties).anyTimes(); - expect(topologyFactory.createProvisionClusterRequest(properties, securityConfiguration)).andReturn(topologyRequest).once(); + expect(topologyFactory.createProvisionClusterRequest(anyString(), eq(properties), eq(securityConfiguration))).andReturn(topologyRequest).once(); expect(securityFactory.createSecurityConfigurationFromRequest(EasyMock.anyObject(), anyBoolean())).andReturn (securityConfiguration).once(); expect(topologyManager.provisionCluster(topologyRequest)).andReturn(requestStatusResponse).once(); @@ -208,7 +209,7 @@ public void testCreateResource_blueprint__InvalidRequest() throws Exception { // set expectations expect(request.getProperties()).andReturn(requestProperties).anyTimes(); // throw exception from topology request factory an assert that the correct exception is thrown from resource provider - expect(topologyFactory.createProvisionClusterRequest(properties, null)).andThrow(new InvalidTopologyException + expect(topologyFactory.createProvisionClusterRequest(null, properties, null)).andThrow(new InvalidTopologyException ("test")); replayAll(); @@ -472,7 +473,7 @@ private void testCreateResource_blueprint(Authentication authentication) throws expect(securityFactory.createSecurityConfigurationFromRequest(EasyMock.anyObject(), anyBoolean())).andReturn(null) .once(); - expect(topologyFactory.createProvisionClusterRequest(properties, null)).andReturn(topologyRequest).once(); + expect(topologyFactory.createProvisionClusterRequest(anyString(), eq(properties), anyObject())).andReturn(topologyRequest).once(); expect(topologyManager.provisionCluster(topologyRequest)).andReturn(requestStatusResponse).once(); expect(requestStatusResponse.getRequestId()).andReturn(5150L).anyTimes(); @@ -803,7 +804,7 @@ public void testCreateResource_blueprint_withRepoVersion() throws Exception { expect(securityFactory.createSecurityConfigurationFromRequest(EasyMock.anyObject(), anyBoolean())).andReturn(null) .once(); - expect(topologyFactory.createProvisionClusterRequest(properties, null)).andReturn(topologyRequest).once(); + expect(topologyFactory.createProvisionClusterRequest("{}", properties, null)).andReturn(topologyRequest).once(); expect(topologyManager.provisionCluster(topologyRequest)).andReturn(requestStatusResponse).once(); expect(requestStatusResponse.getRequestId()).andReturn(5150L).anyTimes(); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequestTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequestTest.java index 5ed582f5c3b..3cc48905829 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequestTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequestTest.java @@ -109,7 +109,7 @@ public void testHostNameSpecified() throws Exception { replay(hostResourceProvider); Map properties = createBlueprintRequestPropertiesNameOnly(CLUSTER_NAME, BLUEPRINT_NAME); - ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(null, properties, null); assertEquals(CLUSTER_NAME, provisionClusterRequest.getClusterName()); assertEquals(TopologyRequest.Type.PROVISION, provisionClusterRequest.getType()); @@ -160,7 +160,7 @@ public void testHostCountSpecified() throws Exception { replay(hostResourceProvider); Map properties = createBlueprintRequestPropertiesCountOnly(CLUSTER_NAME, BLUEPRINT_NAME); - ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(null, properties, null); assertEquals(CLUSTER_NAME, provisionClusterRequest.getClusterName()); assertEquals(TopologyRequest.Type.PROVISION, provisionClusterRequest.getType()); @@ -211,7 +211,7 @@ public void testHostCountSpecified() throws Exception { @Test public void testMultipleGroups() throws Exception { Map properties = createBlueprintRequestProperties(CLUSTER_NAME, BLUEPRINT_NAME); - ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(null, properties, null); assertEquals(CLUSTER_NAME, provisionClusterRequest.getClusterName()); assertEquals(TopologyRequest.Type.PROVISION, provisionClusterRequest.getType()); @@ -286,7 +286,7 @@ public void test_NoHostGroupInfo() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @Test @@ -301,7 +301,7 @@ public void test_Creditentials() throws Exception { credentialsSet.add(credentialHashMap); properties.put("credentials", credentialsSet); - ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(null, properties, null); assertEquals(provisionClusterRequest.getCredentialsMap().get("testAlias").getAlias(), "testAlias"); assertEquals(provisionClusterRequest.getCredentialsMap().get("testAlias").getPrincipal(), "testPrincipal"); @@ -326,7 +326,7 @@ public void test_CreditentialsInvalidType() throws Exception { credentialsSet.add(credentialHashMap); properties.put("credentials", credentialsSet); - ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest provisionClusterRequest = new ProvisionClusterRequest(null, properties, null); } @Test(expected= InvalidTopologyTemplateException.class) @@ -338,7 +338,7 @@ public void test_GroupInfoMissingName() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @Test(expected= InvalidTopologyTemplateException.class) @@ -350,7 +350,7 @@ public void test_NoHostsInfo() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @Test(expected = InvalidTopologyTemplateException.class) @@ -370,7 +370,7 @@ public void test_NoHostNameOrHostCount() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @@ -383,7 +383,7 @@ public void testInvalidPredicateProperty() throws Exception { replay(hostResourceProvider); // should result in an exception due to invalid property in host predicate - new ProvisionClusterRequest(createBlueprintRequestProperties(CLUSTER_NAME, BLUEPRINT_NAME), null); + new ProvisionClusterRequest(null, createBlueprintRequestProperties(CLUSTER_NAME, BLUEPRINT_NAME), null); } @Test(expected = InvalidTopologyTemplateException.class) @@ -395,7 +395,7 @@ public void testHostNameAndCountSpecified() throws Exception { Map properties = createBlueprintRequestPropertiesNameOnly(CLUSTER_NAME, BLUEPRINT_NAME); ((Map) ((List) properties.get("host_groups")).iterator().next()).put("host_count", "5"); // should result in an exception due to both host name and host count being specified - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @Test(expected = InvalidTopologyTemplateException.class) @@ -407,13 +407,13 @@ public void testHostNameAndPredicateSpecified() throws Exception { Map properties = createBlueprintRequestPropertiesNameOnly(CLUSTER_NAME, BLUEPRINT_NAME); ((Map) ((List) properties.get("host_groups")).iterator().next()).put("host_predicate", "Hosts/host_name=myTestHost"); // should result in an exception due to both host name and host count being specified - new ProvisionClusterRequest(properties, null); + new ProvisionClusterRequest(null, properties, null); } @Test public void testQuickLinksProfile_NoDataInRequest() throws Exception { Map properties = createBlueprintRequestProperties(CLUSTER_NAME, BLUEPRINT_NAME); - ProvisionClusterRequest request = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest request = new ProvisionClusterRequest(null, properties, null); assertNull("No quick links profile is expected", request.getQuickLinksProfileJson()); } @@ -424,7 +424,7 @@ public void testQuickLinksProfile_OnlyGlobalFilterDataInRequest() throws Excepti properties.put(ProvisionClusterRequest.QUICKLINKS_PROFILE_FILTERS_PROPERTY, Sets.newHashSet(QuickLinksProfileBuilderTest.filter(null, null, true))); - ProvisionClusterRequest request = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest request = new ProvisionClusterRequest(null, properties, null); assertEquals("Quick links profile doesn't match expected", "{\"filters\":[{\"visible\":true}],\"services\":[]}", request.getQuickLinksProfileJson()); @@ -439,7 +439,7 @@ public void testQuickLinksProfile_OnlyServiceFilterDataInRequest() throws Except Set> services = Sets.newHashSet(hdfs); properties.put(ProvisionClusterRequest.QUICKLINKS_PROFILE_SERVICES_PROPERTY, services); - ProvisionClusterRequest request = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest request = new ProvisionClusterRequest(null, properties, null); assertEquals("Quick links profile doesn't match expected", "{\"filters\":[],\"services\":[{\"name\":\"HDFS\",\"components\":[],\"filters\":[{\"visible\":true}]}]}", request.getQuickLinksProfileJson()); @@ -457,7 +457,7 @@ public void testQuickLinksProfile_BothGlobalAndServiceLevelFilters() throws Exce Set> services = Sets.newHashSet(hdfs); properties.put(ProvisionClusterRequest.QUICKLINKS_PROFILE_SERVICES_PROPERTY, services); - ProvisionClusterRequest request = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest request = new ProvisionClusterRequest(null, properties, null); System.out.println(request.getQuickLinksProfileJson()); assertEquals("Quick links profile doesn't match expected", "{\"filters\":[{\"visible\":true}],\"services\":[{\"name\":\"HDFS\",\"components\":[],\"filters\":[{\"visible\":true}]}]}", @@ -470,7 +470,7 @@ public void testQuickLinksProfile_InvalidRequestData() throws Exception { properties.put(ProvisionClusterRequest.QUICKLINKS_PROFILE_SERVICES_PROPERTY, "Hello World!"); - ProvisionClusterRequest request = new ProvisionClusterRequest(properties, null); + ProvisionClusterRequest request = new ProvisionClusterRequest(null, properties, null); } public static Map createBlueprintRequestProperties(String clusterName, String blueprintName) { diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ScaleClusterRequestTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ScaleClusterRequestTest.java index b9f32a03f67..cc02db4e5c0 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ScaleClusterRequestTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ScaleClusterRequestTest.java @@ -112,7 +112,7 @@ private void addSingleHostByName(Map props) throws InvalidTopolo reset(hostResourceProvider); replay(hostResourceProvider); - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(Collections.singleton(props)); + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", Collections.singleton(props)); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); assertEquals(String.format("Scale Cluster '%s' (+%s hosts)", CLUSTER_NAME, "1"), @@ -150,7 +150,7 @@ private void addMultipleHostsByName(Set> propertySet) throws reset(hostResourceProvider); replay(hostResourceProvider); - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(propertySet); + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", propertySet); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); assertEquals(String.format("Scale Cluster '%s' (+%s hosts)", CLUSTER_NAME, "2"), @@ -177,7 +177,7 @@ public void test_basic_hostCount() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(Collections.singleton( + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", Collections.singleton( createScaleClusterPropertiesGroup1_HostCount(CLUSTER_NAME, BLUEPRINT_NAME))); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); @@ -203,7 +203,7 @@ public void test_basic_hostCount2() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(Collections.singleton( + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", Collections.singleton( createScaleClusterPropertiesGroup1_HostCount2(CLUSTER_NAME, BLUEPRINT_NAME))); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); @@ -225,7 +225,7 @@ public void test_basic_hostCount2() throws Exception { @Test public void test_basic_hostCountAndPredicate() throws Exception { - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(Collections.singleton( + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", Collections.singleton( createScaleClusterPropertiesGroup1_HostCountAndPredicate(CLUSTER_NAME, BLUEPRINT_NAME))); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); @@ -252,7 +252,7 @@ public void testMultipleHostGroups() throws Exception { propertySet.add(createScaleClusterPropertiesGroup1_HostCount(CLUSTER_NAME, BLUEPRINT_NAME)); propertySet.add(createScaleClusterPropertiesGroup1_HostName(CLUSTER_NAME, BLUEPRINT_NAME)); - ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest(propertySet); + ScaleClusterRequest scaleClusterRequest = new ScaleClusterRequest("{}", propertySet); assertEquals(TopologyRequest.Type.SCALE, scaleClusterRequest.getType()); assertEquals(String.format("Scale Cluster '%s' (+%s hosts)", CLUSTER_NAME, "3"), @@ -300,7 +300,7 @@ public void test_GroupInfoMissingName() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception - new ScaleClusterRequest(Collections.singleton(properties)); + new ScaleClusterRequest("{}", Collections.singleton(properties)); } @Test(expected = InvalidTopologyTemplateException.class) @@ -313,7 +313,7 @@ public void test_NoHostNameOrHostCount() throws Exception { reset(hostResourceProvider); replay(hostResourceProvider); // should result in an exception because neither host name or host count are specified - new ScaleClusterRequest(Collections.singleton(properties)); + new ScaleClusterRequest("{}", Collections.singleton(properties)); } @@ -326,7 +326,7 @@ public void testInvalidPredicateProperty() throws Exception { replay(hostResourceProvider); // should result in an exception due to invalid property in host predicate - new ScaleClusterRequest(Collections.singleton( + new ScaleClusterRequest("{}", Collections.singleton( createScaleClusterPropertiesGroup1_HostCountAndPredicate(CLUSTER_NAME, BLUEPRINT_NAME))); } @@ -340,7 +340,7 @@ public void testMultipleBlueprints() throws Exception { propertySet.add(createScaleClusterPropertiesGroup1_HostName2(CLUSTER_NAME, "OTHER_BLUEPRINT")); // should result in an exception due to different blueprints being specified - new ScaleClusterRequest(propertySet); + new ScaleClusterRequest("{}", propertySet); } public static Map createScaleClusterPropertiesGroup1_HostName(String clusterName, String blueprintName) { diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/PersistedStateImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/PersistedStateImplTest.java new file mode 100644 index 00000000000..7f6ee4b169a --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/PersistedStateImplTest.java @@ -0,0 +1,123 @@ +/* + * 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.topology; + + +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.newCapture; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; + +import org.apache.ambari.server.controller.internal.BaseClusterRequest; +import org.apache.ambari.server.controller.internal.ProvisionAction; +import org.apache.ambari.server.controller.internal.ProvisionClusterRequest; +import org.apache.ambari.server.orm.dao.TopologyRequestDAO; +import org.apache.ambari.server.orm.entities.TopologyRequestEntity; +import org.easymock.Capture; +import org.easymock.EasyMockRunner; +import org.easymock.Mock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.google.common.collect.ImmutableMap; + + +@RunWith(EasyMockRunner.class) +public class PersistedStateImplTest { + + private static final String CLUSTER_REQUEST = + "{'blueprint': 'bp', 'host_groups': [{'name': 'group','host_count': '1' }]}".replace('\'', '"'); + + private static final String BLUEPRINT_NAME = "bp"; + + @Mock + private TopologyRequestDAO topologyRequestDAO; + + @Mock + private BlueprintFactory blueprintFactory; + + @Mock + private Blueprint blueprint; + + @Mock + private ProvisionClusterRequest + request; + + private PersistedStateImpl persistedState; + + @Before + public void init() throws Exception { + expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).anyTimes(); + expect(blueprint.getConfiguration()).andReturn(new Configuration()).anyTimes(); + expect(blueprintFactory.getBlueprint(BLUEPRINT_NAME)).andReturn(blueprint).anyTimes(); + + expect(request.getBlueprint()).andReturn(blueprint).anyTimes(); + expect(request.getRawRequestBody()).andReturn(CLUSTER_REQUEST).anyTimes(); + expect(request.getType()).andReturn(TopologyRequest.Type.PROVISION).anyTimes(); + expect(request.getConfiguration()).andReturn(new Configuration()).anyTimes(); + expect(request.getClusterId()).andReturn(1L).anyTimes(); + expect(request.getDescription()).andReturn("").anyTimes(); + expect(request.getProvisionAction()).andReturn(ProvisionAction.INSTALL_AND_START).anyTimes(); + HostGroupInfo hostGroupInfo = new HostGroupInfo("hostgroup1"); + hostGroupInfo.setConfiguration(new Configuration()); + expect(request.getHostGroupInfo()).andReturn(ImmutableMap.of("hostgroup1", hostGroupInfo)).anyTimes(); + + replay(blueprint, blueprintFactory, request); + + Field blueprintFactoryField = BaseClusterRequest.class.getDeclaredField("blueprintFactory"); + blueprintFactoryField.setAccessible(true); + blueprintFactoryField.set(null, blueprintFactory); + + persistedState = new PersistedStateImpl(); + Field topologyRequestDAOField = PersistedStateImpl.class.getDeclaredField("topologyRequestDAO"); + topologyRequestDAOField.setAccessible(true); + topologyRequestDAOField.set(persistedState, topologyRequestDAO); + } + + @After + public void tearDown() { + reset(topologyRequestDAO, blueprintFactory, blueprint, request); + } + + @Test + public void testPersistTopologyRequest_RawRequestIsSaved() throws Exception { + // Given + Capture entityCapture = newCapture(); + topologyRequestDAO.create(capture(entityCapture)); + expectLastCall().andAnswer(() -> { + entityCapture.getValue().setId(1L); + return null; + }); + replay(topologyRequestDAO); + + // When + persistedState.persistTopologyRequest(request); + + // Then + assertEquals(CLUSTER_REQUEST, entityCapture.getValue().getRawRequestBody()); + } + +} \ No newline at end of file diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java index 9f3a1f04825..89f2f4f7f62 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java @@ -584,7 +584,7 @@ public void testScaleHosts__alreadyExistingHost() throws InvalidTopologyTemplate expect(persistedState.getAllRequests()).andReturn(Collections.emptyMap()).anyTimes(); replayAll(); topologyManager.provisionCluster(request); - topologyManager.scaleHosts(new ScaleClusterRequest(propertySet)); + topologyManager.scaleHosts(new ScaleClusterRequest("{}", propertySet)); Assert.fail("InvalidTopologyException should have been thrown"); } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyRequestUtilTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyRequestUtilTest.java new file mode 100644 index 00000000000..db4046ac277 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyRequestUtilTest.java @@ -0,0 +1,60 @@ +/* + * 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.topology; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; + +import org.apache.ambari.server.state.StackId; +import org.junit.Test; + +import com.google.common.collect.ImmutableSet; + +public class TopologyRequestUtilTest { + + private static final String REQUEST_WITH_MPACK_INSTANCES = + "{ 'mpack_instances' : [ {'name': 'HDPCORE', 'version': '1.0.0-b98'}, {'name': 'EDW', 'version': '1.0.0'} ] }".replace('\'', '"'); + + private static final String REQUEST_WITH_INVALID_MPACK_INSTANCE = + "{ 'mpack_instances' : [ {'name': 'HDPCORE', 'version': '1.0.0-b98'}, {'name': 'EDW'} ] }".replace('\'', '"'); + + private static final String REQUEST_WITHOUT_MPACK_INSTANCE = "{}"; + + + @Test + public void testGetStackIdsFromRawRequest_normalCase() { + assertEquals( + ImmutableSet.of(new StackId("HDPCORE", "1.0.0-b98"), new StackId("EDW", "1.0.0")), + TopologyRequestUtil.getStackIdsFromRequest(REQUEST_WITH_MPACK_INSTANCES)); + } + + @Test + public void testGetStackIdsFromRawRequest_noMpackInstances() { + assertEquals( + Collections.emptySet(), + TopologyRequestUtil.getStackIdsFromRequest(REQUEST_WITHOUT_MPACK_INSTANCE)); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetStackIdsFromRawRequest_wrongMpackInstance() { + TopologyRequestUtil.getStackIdsFromRequest(REQUEST_WITH_INVALID_MPACK_INSTANCE); + } + +} \ No newline at end of file