You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by be...@apache.org on 2017/10/27 12:46:01 UTC

[1/2] ambari git commit: AMBARI-22325 Blueprint Service uses Blueprint V2 resource provider (benyoka)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714 d8406d0be -> 93a6dbf94


AMBARI-22325 Blueprint Service uses Blueprint V2 resource provider (benyoka)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 93a6dbf94f9016a101550df20fc9ec4bab1756b3
Parents: 36013fe
Author: Balazs Bence Sari <be...@apache.org>
Authored: Fri Oct 27 14:44:37 2017 +0200
Committer: Balazs Bence Sari <be...@apache.org>
Committed: Fri Oct 27 14:45:44 2017 +0200

----------------------------------------------------------------------
 .../java/org/apache/ambari/server/controller/AmbariServer.java  | 5 +++++
 .../controller/internal/AbstractControllerResourceProvider.java | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/93a6dbf9/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index afe5647..e2553cb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -64,6 +64,7 @@ import org.apache.ambari.server.controller.internal.AbstractControllerResourcePr
 import org.apache.ambari.server.controller.internal.AmbariPrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.BaseClusterRequest;
 import org.apache.ambari.server.controller.internal.BlueprintResourceProvider;
+import org.apache.ambari.server.controller.internal.BlueprintV2ResourceProvider;
 import org.apache.ambari.server.controller.internal.ClusterPrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.ClusterResourceProvider;
 import org.apache.ambari.server.controller.internal.HostResourceProvider;
@@ -82,6 +83,7 @@ import org.apache.ambari.server.metrics.system.MetricsService;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.BlueprintDAO;
+import org.apache.ambari.server.orm.dao.BlueprintV2DAO;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.GroupDAO;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
@@ -921,6 +923,9 @@ public class AmbariServer {
     BlueprintResourceProvider.init(injector.getInstance(BlueprintFactory.class),
         injector.getInstance(BlueprintDAO.class), injector.getInstance(SecurityConfigurationFactory.class),
         injector.getInstance(Gson.class), ambariMetaInfo);
+    BlueprintV2ResourceProvider.init(injector.getInstance(BlueprintV2Factory.class),
+      injector.getInstance(BlueprintV2DAO.class), injector.getInstance(SecurityConfigurationFactory.class),
+      ambariMetaInfo);
     StackDependencyResourceProvider.init(ambariMetaInfo);
     ClusterResourceProvider.init(injector.getInstance(TopologyManager.class),
         injector.getInstance(TopologyRequestFactoryImpl.class), injector.getInstance(SecurityConfigurationFactory

http://git-wip-us.apache.org/repos/asf/ambari/blob/93a6dbf9/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index afca803..4ffd8d1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -233,7 +233,7 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
       case HostComponentProcess:
         return new HostComponentProcessResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Blueprint:
-        return new BlueprintResourceProvider(propertyIds, keyPropertyIds, managementController);
+        return new BlueprintV2ResourceProvider(propertyIds, keyPropertyIds, managementController);
       case KerberosDescriptor:
         return resourceProviderFactory.getKerberosDescriptorResourceProvider(managementController, propertyIds, keyPropertyIds);
       case Recommendation:


[2/2] ambari git commit: AMBARI-22297 BlueprintV2ResourceProvider, fixes in object model, startup logging fix (benyoka)

Posted by be...@apache.org.
AMBARI-22297 BlueprintV2ResourceProvider,fixes in object model, startup logging fix (benyoka)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 36013fe43c297b4e170b9eac23f7f0c8c7131f33
Parents: d8406d0
Author: Balazs Bence Sari <be...@apache.org>
Authored: Fri Oct 27 11:05:14 2017 +0200
Committer: Balazs Bence Sari <be...@apache.org>
Committed: Fri Oct 27 14:45:44 2017 +0200

----------------------------------------------------------------------
 .../ambari/server/controller/AmbariServer.java  |   2 +-
 .../internal/BlueprintV2ResourceProvider.java   | 391 +++++++++++++++++++
 .../server/orm/entities/BlueprintV2Entity.java  |  29 --
 .../ambari/server/topology/BlueprintImplV2.java |  10 +
 .../ambari/server/topology/BlueprintV2.java     |   3 +
 .../server/topology/BlueprintV2Factory.java     |  51 ++-
 .../internal/BlueprintResourceProviderTest.java |   5 +-
 .../validators/BlueprintImplV2Test.java         |   7 +-
 8 files changed, 447 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index f900452..afe5647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -1065,10 +1065,10 @@ public class AmbariServer {
 
   public static void main(String[] args) throws Exception {
     logStartup();
-    Injector injector = Guice.createInjector(new ControllerModule(), new AuditLoggerModule());
 
     AmbariServer server = null;
     try {
+      Injector injector = Guice.createInjector(new ControllerModule(), new AuditLoggerModule());
       LOG.info("Getting the controller");
 
       // check if this instance is the active instance

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintV2ResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintV2ResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintV2ResourceProvider.java
new file mode 100644
index 0000000..ccc9836
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintV2ResourceProvider.java
@@ -0,0 +1,391 @@
+/*
+ * 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.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+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.PropertyHelper;
+import org.apache.ambari.server.orm.dao.BlueprintV2DAO;
+import org.apache.ambari.server.orm.entities.BlueprintV2Entity;
+import org.apache.ambari.server.topology.BlueprintV2;
+import org.apache.ambari.server.topology.BlueprintV2Factory;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.apache.ambari.server.topology.SecurityConfigurationFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.SetMultimap;
+
+
+/**
+ * Resource Provider for Blueprint resources.
+ */
+public class BlueprintV2ResourceProvider extends AbstractControllerResourceProvider {
+
+  // ----- Property ID constants ---------------------------------------------
+
+  // Blueprints
+  public static final String BLUEPRINT_NAME_PROPERTY_ID =
+    PropertyHelper.getPropertyId("Blueprints", "blueprint_name");
+
+  public static final String BLUEPRINT_SECURITY_PROPERTY_ID =
+    PropertyHelper.getPropertyId("Blueprints", "security");
+
+  public static final String BLUEPRINTS_PROPERTY_ID = "Blueprints";
+
+  // Host Groups
+  public static final String HOST_GROUP_PROPERTY_ID = "host_groups";
+  public static final String HOST_GROUP_NAME_PROPERTY_ID = "name";
+  public static final String HOST_GROUP_CARDINALITY_PROPERTY_ID = "cardinality";
+
+  // Host Group Components
+  public static final String COMPONENT_PROPERTY_ID ="components";
+  public static final String COMPONENT_NAME_PROPERTY_ID ="name";
+  public static final String COMPONENT_PROVISION_ACTION_PROPERTY_ID = "provision_action";
+
+  // Configurations
+  public static final String CONFIGURATION_PROPERTY_ID = "configurations";
+
+
+  // Setting
+  public static final String SETTING_PROPERTY_ID = "settings";
+  public static final String CLUSTER_SETTING_PROPERTY_ID = "cluster_settings";
+
+  public static final String PROPERTIES_PROPERTY_ID = "properties";
+  public static final String PROPERTIES_ATTRIBUTES_PROPERTY_ID = "properties_attributes";
+  public static final String SCHEMA_IS_NOT_SUPPORTED_MESSAGE =
+    "Configuration format provided in Blueprint is not supported";
+  public static final String REQUEST_BODY_EMPTY_ERROR_MESSAGE =
+    "Request body for Blueprint create request is empty";
+  public static final String CONFIGURATION_LIST_CHECK_ERROR_MESSAGE =
+    "Configurations property must be a List of Maps";
+  public static final String CONFIGURATION_MAP_CHECK_ERROR_MESSAGE =
+    "Configuration elements must be Maps";
+  public static final String CONFIGURATION_MAP_SIZE_CHECK_ERROR_MESSAGE =
+    "Configuration Maps must hold a single configuration type each";
+
+  // Primary Key Fields
+  private static Set<String> pkPropertyIds =
+    new HashSet<>(Arrays.asList(new String[]{
+      BLUEPRINT_NAME_PROPERTY_ID}));
+
+  /**
+   * Used to create Blueprint instances
+   */
+  private static BlueprintV2Factory blueprintFactory;
+
+  /**
+   * Used to create SecurityConfiguration instances
+   */
+  private static SecurityConfigurationFactory securityConfigurationFactory;
+
+  /**
+   * Blueprint Data Access Object
+   */
+  private static BlueprintV2DAO blueprintDAO;
+
+  // ----- Constructors ----------------------------------------------------
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param propertyIds     the property ids
+   * @param keyPropertyIds  the key property ids
+   * @param controller      management controller
+   */
+  BlueprintV2ResourceProvider(Set<String> propertyIds,
+                            Map<Resource.Type, String> keyPropertyIds,
+                            AmbariManagementController controller) {
+
+    super(propertyIds, keyPropertyIds, controller);
+  }
+
+  /**
+   * Static initialization.
+   *
+   * @param factory   blueprint factory
+   * @param dao       blueprint data access object
+   * @param securityFactory
+   * @param metaInfo
+   */
+  public static void init(BlueprintV2Factory factory, BlueprintV2DAO dao, SecurityConfigurationFactory
+    securityFactory, AmbariMetaInfo metaInfo) {
+    blueprintFactory = factory;
+    blueprintDAO = dao;
+    securityConfigurationFactory = securityFactory;
+    ambariMetaInfo = metaInfo;
+  }
+
+  // ----- ResourceProvider ------------------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  @Override
+  public RequestStatus createResources(Request request)
+    throws SystemException, UnsupportedPropertyException,
+    ResourceAlreadyExistsException, NoSuchParentResourceException {
+
+    for (Map<String, Object> properties : request.getProperties()) {
+      try {
+        createResources(getCreateCommand(properties, request.getRequestInfoProperties()));
+      }catch(IllegalArgumentException e) {
+        LOG.error("Exception while creating blueprint", e);
+        throw e;
+      }
+    }
+    notifyCreate(Resource.Type.Blueprint, request);
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  //todo: continue to use dao/entity directly or use blueprint factory?
+  public Set<Resource> getResources(Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException,
+    NoSuchResourceException, NoSuchParentResourceException {
+
+    List<BlueprintV2Entity> results = null;
+    boolean applyPredicate = false;
+
+    if (predicate != null) {
+      Set<Map<String, Object>> requestProps = getPropertyMaps(predicate);
+      if (requestProps.size() == 1 ) {
+        String name = (String) requestProps.iterator().next().get(
+          BLUEPRINT_NAME_PROPERTY_ID);
+
+        if (name != null) {
+          BlueprintV2Entity entity = blueprintDAO.findByName(name);
+          results = entity == null ? Collections.emptyList() : Collections.singletonList(entity);
+        }
+      }
+    }
+
+    if (results == null) {
+      applyPredicate = true;
+      results = blueprintDAO.findAll();
+    }
+
+    Set<Resource> resources  = new HashSet<>();
+    for (BlueprintV2Entity entity : results) {
+      Resource resource = toResource(entity, getRequestPropertyIds(request, predicate));
+      if (predicate == null || ! applyPredicate || predicate.evaluate(resource)) {
+        resources.add(resource);
+      }
+    }
+
+    if (predicate != null && resources.isEmpty()) {
+      throw new NoSuchResourceException(
+        "The requested resource doesn't exist: Blueprint not found, " + predicate);
+    }
+
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException,
+    NoSuchResourceException, NoSuchParentResourceException {
+
+    // no-op, blueprints are immutable.  Service doesn't support PUT so should never get here.
+    return null;
+  }
+
+  @Override
+  public RequestStatus deleteResources(Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException,
+    NoSuchResourceException, NoSuchParentResourceException {
+
+    //TODO (jspeidel): Revisit concurrency control
+    Set<Resource> setResources = getResources(
+      new RequestImpl(null, null, null, null), predicate);
+
+    for (final Resource resource : setResources) {
+      final String blueprintName =
+        (String) resource.getPropertyValue(BLUEPRINT_NAME_PROPERTY_ID);
+
+      LOG.info("Deleting Blueprint, name = " + blueprintName);
+
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          blueprintDAO.removeByName(blueprintName);
+          return null;
+        }
+      });
+    }
+
+    notifyDelete(Resource.Type.Blueprint, predicate);
+    return getRequestStatus(null);
+  }
+
+  /**
+   * Used to get stack metainfo.
+   */
+  private static AmbariMetaInfo ambariMetaInfo;
+
+  // ----- Instance Methods ------------------------------------------------
+
+  /**
+   * Create a resource instance from a blueprint entity.
+   *
+   * @param entity        blueprint entity
+   * @param requestedIds  requested id's
+   *
+   * @return a new resource instance for the given blueprint entity
+   */
+  protected Resource toResource(BlueprintV2Entity entity, Set<String> requestedIds) throws NoSuchResourceException {
+    try {
+      Resource resource = new ResourceImpl(Resource.Type.Blueprint);
+      Map<String, Object> blueprintAsMap = blueprintFactory.convertToMap(entity);
+      if (!requestedIds.isEmpty()) {
+        Map<String, Object> filteredMap = new HashMap<>();
+        applySelectFilters(requestedIds, blueprintAsMap, filteredMap);
+        blueprintAsMap = filteredMap;
+      }
+      blueprintAsMap.entrySet().forEach( entry -> resource.setProperty(entry.getKey(), entry.getValue()) );
+      return resource;
+    }
+    catch (IOException e) {
+      throw new NoSuchResourceException("Cannot convert blueprint entity to resource. name=" + entity.getBlueprintName(), e);
+    }
+  }
+
+  /**
+   * Recursively applies select filters on an input map. Only properties matchig the filters will be preserved.
+   * @param filters list of filters. Each filter is a string that can contain subfilters sepatated by '/'
+   * @param startingMap The map to filter
+   * @param collectingMap The map to put the results to
+   */
+  private void applySelectFilters(Set<String> filters, Map<String, Object> startingMap, Map<String, Object> collectingMap) {
+    // Identify filters that apply to this level and those that will be applied on lower levels of the recursion
+    Splitter splitter = Splitter.on('/').omitEmptyStrings().trimResults();
+    Joiner joiner = Joiner.on('/');
+    SetMultimap<String, String> lowerLevelFilters = HashMultimap.create();
+    List<String> currentLevelFilters = new ArrayList<>();
+    filters.forEach( filter -> {
+      List<String> filterParts = ImmutableList.copyOf(splitter.split(filter));
+      if (filterParts.size() == 1) {
+        currentLevelFilters.add(filter);
+      }
+      else {
+        lowerLevelFilters.put(filterParts.get(0), joiner.join(filterParts.subList(1, filterParts.size())));
+      }
+    });
+    startingMap.entrySet().forEach( entry -> {
+      if (currentLevelFilters.contains(entry.getKey())) {
+        collectingMap.put(entry.getKey(), entry.getValue());
+      }
+      else if (lowerLevelFilters.containsKey(entry.getKey()) && entry.getValue() instanceof Map) {
+        Map<String, Object> lowerLevelCollector = (Map<String, Object>)collectingMap.get(entry.getKey());
+        if (null == lowerLevelCollector) {
+          lowerLevelCollector = new HashMap<>();
+          collectingMap.put(entry.getKey(), lowerLevelCollector);
+        }
+        applySelectFilters(lowerLevelFilters.get(entry.getKey()), (Map<String, Object>)entry.getValue(), lowerLevelCollector);
+      }
+    });
+  }
+
+
+  /**
+   * Create a create command with all properties set.
+   *
+   * @param properties        properties to be applied to blueprint
+   * @param requestInfoProps  request info properties
+   *
+   * @return a new create command
+   */
+  private Command<Void> getCreateCommand(final Map<String, Object> properties, final Map<String, String> requestInfoProps) {
+    return new Command<Void>() {
+      @SuppressWarnings("rawtypes")
+      @Override
+      public Void invoke() throws AmbariException {
+        String rawRequestBody = requestInfoProps.get(Request.REQUEST_INFO_BODY_PROPERTY);
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(rawRequestBody), REQUEST_BODY_EMPTY_ERROR_MESSAGE);
+
+        BlueprintV2 blueprint = null;
+        try {
+          blueprint = blueprintFactory.convertFromJson(rawRequestBody);
+        }
+        catch (IOException e) {
+            throw new AmbariException("Unable to parse blueprint", e);
+        }
+
+        if (blueprintDAO.findByName(blueprint.getName()) != null) {
+          throw new DuplicateResourceException(
+            "Attempted to create a Blueprint which already exists, blueprint_name=" +
+              blueprint.getName());
+        }
+
+        try {
+          blueprint.validateRequiredProperties();
+        } catch (InvalidTopologyException e) {
+          throw new IllegalArgumentException("Blueprint configuration validation failed: " + e.getMessage(), e);
+        }
+
+        String validateTopology =  requestInfoProps.get("validate_topology");
+        if (validateTopology == null || ! validateTopology.equalsIgnoreCase("false")) {
+          try {
+            blueprint.validateTopology();
+          } catch (InvalidTopologyException e) {
+            throw new IllegalArgumentException("Invalid blueprint topology", e);
+          }
+        }
+
+        // TODO: handle security descriptor
+
+        try {
+          BlueprintV2Entity entity = blueprintFactory.convertToEntity(blueprint);
+          blueprintDAO.create(entity);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+        return null;
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintV2Entity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintV2Entity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintV2Entity.java
index 046c2e5..de9bde4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintV2Entity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintV2Entity.java
@@ -24,9 +24,7 @@ import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
 import javax.persistence.Id;
-import javax.persistence.JoinColumn;
 import javax.persistence.NamedQuery;
-import javax.persistence.OneToOne;
 import javax.persistence.Table;
 
 import org.apache.ambari.server.state.SecurityType;
@@ -58,33 +56,6 @@ public class BlueprintV2Entity {
   @Column(name = "content", nullable = false, insertable = true, updatable = true)
   private String content;
 
-  /**
-   * Unidirectional one-to-one association to {@link StackEntity}
-   */
-  @OneToOne
-  @JoinColumn(name = "stack_id", unique = false, nullable = false, insertable = true, updatable = false)
-  private StackEntity stack;
-
-  /**
-   * Gets the blueprint's stack.
-   *
-   * @return the stack.
-   */
-  public StackEntity getStack() {
-    return stack;
-  }
-
-  /**
-   * Sets the blueprint's stack.
-   *
-   * @param stack
-   *          the stack to set for the blueprint (not {@code null}).
-   */
-  public void setStack(StackEntity stack) {
-    this.stack = stack;
-  }
-
-
   public String getBlueprintName() {
     return blueprintName;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
index 356a72e..f7ee730 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintImplV2.java
@@ -308,6 +308,16 @@ public class BlueprintImplV2 implements BlueprintV2 {
     return this.securityConfiguration;
   }
 
+  @Override
+  public void validateRequiredProperties() throws InvalidTopologyException {
+    // TODO implement
+  }
+
+  @Override
+  public void validateTopology() throws InvalidTopologyException {
+    // TODO implement
+  }
+
 
   @Override
   public boolean isValidConfigType(String configType) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
index 3925c4f..9ca0248 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2.java
@@ -228,6 +228,9 @@ public interface BlueprintV2 {
 
   SecurityConfiguration getSecurity();
 
+  void validateRequiredProperties() throws InvalidTopologyException;
+
+  void validateTopology() throws InvalidTopologyException;
 
   /**
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
index ddb7cf8..4f6e8e6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintV2Factory.java
@@ -23,10 +23,10 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ObjectNotFoundException;
-import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.controller.StackV2;
 import org.apache.ambari.server.controller.StackV2Factory;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -37,6 +37,7 @@ import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.stack.NoSuchStackException;
 import org.apache.ambari.server.state.StackId;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
@@ -88,30 +89,50 @@ public class BlueprintV2Factory {
     return convertFromEntity(entity);
   }
 
-  public BlueprintV2 convertFromEntity(BlueprintV2Entity blueprintEntity) throws NoSuchStackException, IOException {
-    BlueprintImplV2 blueprintV2 = createObjectMapper().readValue(blueprintEntity.getContent(), BlueprintImplV2.class);
+  public BlueprintV2 convertFromJson(String json) throws IOException {
+    BlueprintImplV2 blueprintV2 = createObjectMapper().readValue(json, BlueprintImplV2.class);
     blueprintV2.postDeserialization();
-    Map<StackId, StackV2> stacks = new HashMap<>();
-    for (String stackIdString: blueprintV2.getStackIds()) {
-      StackId stackId = new StackId(stackIdString);
-      stacks.put(stackId, parseStack(stackDao.find(stackId)));
-    }
-    blueprintV2.setStacks(stacks);
+    blueprintV2.setStacks(
+      blueprintV2.getStackIds().stream().collect(Collectors.toMap(
+        stackId -> new StackId(stackId),
+        stackId -> parseStack(new StackId(stackId))
+      ))
+    );
     return blueprintV2;
   }
 
+  public BlueprintV2 convertFromEntity(BlueprintV2Entity blueprintEntity) throws IOException {
+    return convertFromJson(blueprintEntity.getContent());
+  }
 
-  private StackV2 parseStack(StackEntity stackEntity) throws NoSuchStackException {
+  public Map<String, Object> convertToMap(BlueprintV2Entity entity) throws IOException {
+    return createObjectMapper().readValue(entity.getContent(), HashMap.class);
+  }
+
+  private StackV2 parseStack(StackId stackId) {
     try {
-      return stackFactory.create(stackEntity.getStackName(), stackEntity.getStackVersion());
-    } catch (StackAccessException e) {
-      throw new NoSuchStackException(stackEntity.getStackName(), stackEntity.getStackVersion());
+      return stackFactory.create(stackId.getStackName(), stackId.getStackVersion());
     } catch (AmbariException e) {
-      //todo:
-      throw new RuntimeException("An error occurred parsing the stack information.", e);
+      throw new IllegalArgumentException(
+        String.format("Unable to parse stack. name=%s, version=%s", stackId.getStackName(), stackId.getStackVersion()),
+        e);
     }
   }
 
+  private StackV2 parseStack(StackEntity stackEntity) {
+    return parseStack(new StackId(stackEntity.getStackName(), stackEntity.getStackVersion()));
+  }
+
+  public BlueprintV2Entity convertToEntity(BlueprintV2 blueprint) throws JsonProcessingException {
+    BlueprintV2Entity entity = new BlueprintV2Entity();
+    String content = createObjectMapper().writeValueAsString(blueprint);
+    entity.setContent(content);
+    entity.setBlueprintName(blueprint.getName());
+    entity.setSecurityType(blueprint.getSecurity().getType());
+    entity.setSecurityDescriptorReference(blueprint.getSecurity().getDescriptorReference());
+    return entity;
+  }
+
   /**
    * Convert a map of properties to a blueprint entity.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
index f534411..48d6f20 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
@@ -56,6 +56,7 @@ import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
@@ -341,8 +342,8 @@ public class BlueprintResourceProviderTest {
     AbstractResourceProviderTest.TestObserver observer = new AbstractResourceProviderTest.TestObserver();
     ((ObservableResourceProvider)provider).addObserver(observer);
 
-    provider.createResources(request);
-
+    RequestStatus resources = provider.createResources(request);
+    System.out.println(resources);
     ResourceProviderEvent lastEvent = observer.getLastEvent();
     assertNotNull(lastEvent);
     assertEquals(Resource.Type.Blueprint, lastEvent.getResourceType());

http://git-wip-us.apache.org/repos/asf/ambari/blob/36013fe4/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java
index 3bcf31b..ad2cdbd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java
@@ -59,9 +59,9 @@ public class BlueprintImplV2Test {
     bp.postDeserialization();
     // -- add stack --
     StackV2 hdpCore = new StackV2("HDPCORE", "3.0.0", "3.0.0.0-1", new HashMap<>(), new HashMap<>(), new HashMap<>(),
-      new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
+      new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
     StackV2 analytics = new StackV2("ANALYTICS", "1.0.0", "1.0.0.0-1", new HashMap<>(), new HashMap<>(), new HashMap<>(),
-      new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
+      new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
     bp.setStacks(ImmutableMap.of(new StackId("HDPCORE", "3.0.0"), hdpCore, new StackId("ANALYTICS", "1.0.0"), analytics));
     // ---------------
     String bpJson = mapper.writeValueAsString(bp);
@@ -76,5 +76,4 @@ public class BlueprintImplV2Test {
     BlueprintImplV2 bp2 = mapper.readValue(bpJson2, BlueprintImplV2.class);
     System.out.println(bp2);
   }
-
-}
+}
\ No newline at end of file