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/11/17 21:22:02 UTC

ambari git commit: AMBARI-22325 Cluster template object initial version (benyoka)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714-blueprintv2 b91ad4867 -> cf82733b8


AMBARI-22325 Cluster template object initial version (benyoka)


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

Branch: refs/heads/branch-feature-AMBARI-14714-blueprintv2
Commit: cf82733b81eec8d5b141508fa35149c923b1b7b3
Parents: b91ad48
Author: Balazs Bence Sari <be...@apache.org>
Authored: Fri Nov 17 22:20:20 2017 +0100
Committer: Balazs Bence Sari <be...@apache.org>
Committed: Fri Nov 17 22:21:27 2017 +0100

----------------------------------------------------------------------
 .../server/topology/BlueprintV2Factory.java     |  53 ++---
 .../ambari/server/topology/Credential.java      |   8 +-
 .../topology/ProvisionClusterTemplate.java      | 198 +++++++++++++++++++
 .../ProvisionClusterTemplateFactory.java        |  48 +++++
 .../server/topology/BlueprintImplV2Test.java    | 173 ++++++++++++++++
 .../topology/ProvisionClusterTemplateTest.java  |  30 +++
 .../validators/BlueprintImplV2Test.java         | 175 ----------------
 .../blueprintv2/cluster_template_v2.json        |  66 +++++++
 8 files changed, 552 insertions(+), 199 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/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 e16ba86..3262c54 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
@@ -56,33 +56,35 @@ public class BlueprintV2Factory {
 
   // Host Groups
   protected static final String HOST_GROUP_PROPERTY_ID = "host_groups";
-  protected static final String HOST_GROUP_NAME_PROPERTY_ID = "name";
-  protected static final String HOST_GROUP_CARDINALITY_PROPERTY_ID = "cardinality";
+//  protected static final String HOST_GROUP_NAME_PROPERTY_ID = "name";
+//  protected static final String HOST_GROUP_CARDINALITY_PROPERTY_ID = "cardinality";
 
   // Host Group Components
-  protected static final String COMPONENT_PROPERTY_ID ="components";
+//  protected static final String COMPONENT_PROPERTY_ID ="components";
   protected static final String COMPONENT_NAME_PROPERTY_ID ="name";
-  protected static final String COMPONENT_PROVISION_ACTION_PROPERTY_ID = "provision_action";
+//  protected static final String COMPONENT_PROVISION_ACTION_PROPERTY_ID = "provision_action";
 
   // Configurations
-  protected static final String CONFIGURATION_PROPERTY_ID = "configurations";
+//  protected static final String CONFIGURATION_PROPERTY_ID = "configurations";
   protected static final String PROPERTIES_PROPERTY_ID = "properties";
-  protected static final String PROPERTIES_ATTRIBUTES_PROPERTY_ID = "properties_attributes";
+//  protected static final String PROPERTIES_ATTRIBUTES_PROPERTY_ID = "properties_attributes";
 
-  protected static final String SETTINGS_PROPERTY_ID = "settings";
+//  protected static final String SETTINGS_PROPERTY_ID = "settings";
 
-  private boolean prettyPrintJson = false;
   private static BlueprintV2DAO blueprintDAO;
   private static RepositoryVersionDAO repositoryVersionDAO;
 
   private StackV2Factory stackFactory;
 
-  protected BlueprintV2Factory() {
+  private ObjectMapper objectMapper;
 
+  protected BlueprintV2Factory() {
+    createObjectMapper();
   }
 
   protected BlueprintV2Factory(StackV2Factory stackFactory) {
     this.stackFactory = stackFactory;
+    createObjectMapper();
   }
 
   public static BlueprintV2Factory create(AmbariManagementController controller) {
@@ -100,7 +102,7 @@ public class BlueprintV2Factory {
   }
 
   public BlueprintV2 convertFromJson(String json) throws IOException {
-    BlueprintImplV2 blueprintV2 = createObjectMapper().readValue(json, BlueprintImplV2.class);
+    BlueprintImplV2 blueprintV2 = getObjectMapper().readValue(json, BlueprintImplV2.class);
     blueprintV2.postDeserialization();
     updateStacks(blueprintV2);
     return blueprintV2;
@@ -119,7 +121,7 @@ public class BlueprintV2Factory {
   }
 
   public Map<String, Object> convertToMap(BlueprintV2Entity entity) throws IOException {
-    return createObjectMapper().readValue(entity.getContent(), new TypeReference<Map<String, Object>>(){});
+    return getObjectMapper().readValue(entity.getContent(), new TypeReference<Map<String, Object>>(){});
   }
 
   private StackV2 parseStack(StackId stackId, String repositoryVersion) {
@@ -143,7 +145,7 @@ public class BlueprintV2Factory {
   }
 
   public String convertToJson(BlueprintV2 blueprint) throws JsonProcessingException {
-    return createObjectMapper().writeValueAsString(blueprint);
+    return getObjectMapper().writeValueAsString(blueprint);
 
   }
 
@@ -161,7 +163,7 @@ public class BlueprintV2Factory {
       //todo: should throw a checked exception from here
       throw new IllegalArgumentException("Blueprint name must be provided");
     }
-    ObjectMapper om = createObjectMapper();
+    ObjectMapper om = getObjectMapper();
     String json = om.writeValueAsString(properties);
     BlueprintImplV2 blueprint = om.readValue(json, BlueprintImplV2.class);
     blueprint.postDeserialization();
@@ -171,25 +173,30 @@ public class BlueprintV2Factory {
   }
 
   public boolean isPrettyPrintJson() {
-    return prettyPrintJson;
+    return objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT);;
   }
 
   public void setPrettyPrintJson(boolean prettyPrintJson) {
-    this.prettyPrintJson = prettyPrintJson;
+    if (prettyPrintJson) {
+      objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+    }
+    else {
+      objectMapper.disable(SerializationFeature.INDENT_OUTPUT);
+    }
   }
 
-  public ObjectMapper createObjectMapper() {
-    ObjectMapper mapper = new ObjectMapper();
+  public ObjectMapper getObjectMapper() {
+    return objectMapper;
+  }
+
+  private void createObjectMapper() {
+    objectMapper = new ObjectMapper();
     SimpleModule module = new SimpleModule("CustomModel", Version.unknownVersion());
     SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
     resolver.addMapping(HostGroupV2.class, HostGroupV2Impl.class);
     module.setAbstractTypes(resolver);
-    mapper.registerModule(module);
-    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
-    if (prettyPrintJson) {
-      mapper.enable(SerializationFeature.INDENT_OUTPUT);
-    }
-    return mapper;
+    objectMapper.registerModule(module);
+    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/main/java/org/apache/ambari/server/topology/Credential.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/Credential.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/Credential.java
index 3146e2f..25b9521 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/Credential.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/Credential.java
@@ -19,6 +19,8 @@
 
 package org.apache.ambari.server.topology;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.ambari.server.security.encryption.CredentialStoreType;
 
 /**
@@ -46,7 +48,11 @@ public class Credential {
    */
   private CredentialStoreType type;
 
-  public Credential(String alias, String principal, String key, CredentialStoreType type) {
+  @JsonCreator
+  public Credential(@JsonProperty("alias") String alias,
+                    @JsonProperty("principal") String principal,
+                    @JsonProperty("key") String key,
+                    @JsonProperty("type") CredentialStoreType type) {
     this.alias = alias;
     this.principal = principal;
     this.key = key;

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplate.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplate.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplate.java
new file mode 100644
index 0000000..60f0fc2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplate.java
@@ -0,0 +1,198 @@
+package org.apache.ambari.server.topology;
+
+import java.util.Collection;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.ambari.server.controller.internal.ProvisionAction;
+
+public class ProvisionClusterTemplate {
+
+  private String blueprint;
+  @JsonProperty("default_password")
+  private String defaultPassword;
+  @JsonProperty("config_recommendation_strategy")
+  private ConfigRecommendationStrategy configRecommendationStrategy;
+  @JsonProperty("provision_action")
+  private ProvisionAction provisionAction;
+  private Collection<ProvisionClusterTemplate.Service> services;
+  @JsonProperty("host_groups")
+  private Collection<ProvisionClusterTemplate.HostGroup> hostGroups;
+  private Collection<Credential> credentials;
+  @JsonProperty("security")
+  private SecurityConfiguration securityConfiguration;
+
+  public String getBlueprint() {
+    return blueprint;
+  }
+
+  public void setBlueprint(String blueprint) {
+    this.blueprint = blueprint;
+  }
+
+  public String getDefaultPassword() {
+    return defaultPassword;
+  }
+
+  public void setDefaultPassword(String defaultPassword) {
+    this.defaultPassword = defaultPassword;
+  }
+
+  public Collection<Service> getServices() {
+    return services;
+  }
+
+  public void setServices(Collection<Service> services) {
+    this.services = services;
+  }
+
+  public Collection<Credential> getCredentials() {
+    return credentials;
+  }
+
+  public void setCredentials(Collection<Credential> credentials) {
+    this.credentials = credentials;
+  }
+
+  public SecurityConfiguration getSecurityConfiguration() {
+    return securityConfiguration;
+  }
+
+  public void setSecurityConfiguration(SecurityConfiguration securityConfiguration) {
+    this.securityConfiguration = securityConfiguration;
+  }
+
+  public ConfigRecommendationStrategy getConfigRecommendationStrategy() {
+    return configRecommendationStrategy;
+  }
+
+  public void setConfigRecommendationStrategy(ConfigRecommendationStrategy configRecommendationStrategy) {
+    this.configRecommendationStrategy = configRecommendationStrategy;
+  }
+
+  public ProvisionAction getProvisionAction() {
+    return provisionAction;
+  }
+
+  public void setProvisionAction(ProvisionAction provisionAction) {
+    this.provisionAction = provisionAction;
+  }
+
+  public Collection<HostGroup> getHostGroups() {
+    return hostGroups;
+  }
+
+  public void setHostGroups(Collection<HostGroup> hostGroups) {
+    this.hostGroups = hostGroups;
+  }
+
+  public static class HostGroup implements Configurable {
+    private String name;
+    @JsonIgnore
+    private Configuration configuration;
+    private Collection<Host> hosts;
+    @JsonProperty("host_count")
+    private Integer hostCount;
+    @JsonProperty("host_predicate")
+    private String hostPredicate;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+      return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Configuration configuration) {
+      this.configuration = configuration;
+    }
+
+    public Collection<Host> getHosts() {
+      return hosts;
+    }
+
+    public void setHosts(Collection<Host> hosts) {
+      this.hosts = hosts;
+    }
+
+    public Integer getHostCount() {
+      return hostCount;
+    }
+
+    public void setHostCount(Integer hostCount) {
+      this.hostCount = hostCount;
+    }
+
+    public String getHostPredicate() {
+      return hostPredicate;
+    }
+
+    public void setHostPredicate(String hostPredicate) {
+      this.hostPredicate = hostPredicate;
+    }
+  }
+
+  public static class Service implements Configurable {
+    private String name;
+    @JsonProperty("service_group")
+    private String serviceGroup;
+    @JsonIgnore
+    private Configuration configuration;
+
+    @Override
+    public Configuration getConfiguration() {
+      return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Configuration configuration) {
+      this.configuration = configuration;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    public String getServiceGroup() {
+      return serviceGroup;
+    }
+
+    public void setServiceGroup(String serviceGroup) {
+      this.serviceGroup = serviceGroup;
+    }
+  }
+
+  public static class Host {
+    private String fqdn;
+    @JsonProperty("rack_info")
+    private String  rackInfo;
+
+    public String getFqdn() {
+      return fqdn;
+    }
+
+    public void setFqdn(String fqdn) {
+      this.fqdn = fqdn;
+    }
+
+    public String getRackInfo() {
+      return rackInfo;
+    }
+
+    public void setRackInfo(String rackInfo) {
+      this.rackInfo = rackInfo;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplateFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplateFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplateFactory.java
new file mode 100644
index 0000000..c66b6f6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionClusterTemplateFactory.java
@@ -0,0 +1,48 @@
+package org.apache.ambari.server.topology;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class ProvisionClusterTemplateFactory {
+
+  private ObjectMapper objectMapper;
+
+  public ProvisionClusterTemplateFactory() {
+    createObjectMapper();
+  }
+
+  public boolean isPrettyPrintJson() {
+    return objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT);;
+  }
+
+  public void setPrettyPrintJson(boolean prettyPrintJson) {
+    if (prettyPrintJson) {
+      objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+    }
+    else {
+      objectMapper.disable(SerializationFeature.INDENT_OUTPUT);
+    }
+  }
+
+  public ObjectMapper getObjectMapper() {
+    return objectMapper;
+  }
+
+  private void createObjectMapper() {
+    objectMapper = new ObjectMapper();
+//    SimpleModule module = new SimpleModule("CustomModel", Version.unknownVersion());
+//    SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
+//    resolver.addMapping(HostGroupV2.class, HostGroupV2Impl.class);
+//    module.setAbstractTypes(resolver);
+//    objectMapper.registerModule(module);
+    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+  }
+
+  public ProvisionClusterTemplate convertFromJson(String clusterTemplateJson) throws IOException {
+    return objectMapper.readValue(clusterTemplateJson, ProvisionClusterTemplate.class);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplV2Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplV2Test.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplV2Test.java
new file mode 100644
index 0000000..548ee18
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/BlueprintImplV2Test.java
@@ -0,0 +1,173 @@
+/*
+ * 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 static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.StackV2;
+import org.apache.ambari.server.controller.StackV2Factory;
+import org.apache.ambari.server.state.StackId;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Resources;
+
+public class BlueprintImplV2Test {
+
+  static String BLUEPRINTV2_JSON;
+  static String BLUEPRINTV2_2_JSON;
+
+  BlueprintV2Factory blueprintFactory;
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    BLUEPRINTV2_JSON = Resources.toString(Resources.getResource("blueprintv2/blueprintv2.json"), Charsets.UTF_8);
+    BLUEPRINTV2_2_JSON = Resources.toString(Resources.getResource("blueprintv2/blueprintv2_2.json"), Charsets.UTF_8);
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    StackV2Factory stackFactory = mock(StackV2Factory.class);
+    when(stackFactory.create(any(StackId.class))).thenAnswer(invocation -> {
+      StackId stackId = invocation.getArgumentAt(0, StackId.class);
+      StackV2 stack = new StackV2(stackId.getStackName(), stackId.getStackVersion(), stackId.getStackVersion() + ".0-1",
+        new HashMap<>(), new HashMap<>(), new HashMap<>(),
+        new HashMap<>(), new HashMap<>(), new HashMap<>(),
+        new HashMap<>(), new HashMap<>(), new HashMap<>());
+      return stack;
+    });
+    blueprintFactory = BlueprintV2Factory.create(stackFactory);
+    blueprintFactory.setPrettyPrintJson(true);
+  }
+
+  @Test
+  public void testSerialization_parseJsonAsBlueprint() throws Exception {
+    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_JSON);
+    assertEquals(new StackId("HDPCORE", "3.0.0"),
+      bp.getServiceGroups().iterator().next().getServices().iterator().next().getStack().getStackId());
+    assertEquals(2, bp.getStackIds().size());
+    assertEquals(7, bp.getAllServiceIds().size());
+    assertEquals(2, bp.getServiceGroups().size());
+  }
+
+  @Test
+  public void testSerialization_parseJsonAsMap() throws Exception {
+    ObjectMapper mapper = blueprintFactory.getObjectMapper();
+    Map<String, Object> blueprintAsMap = mapper.readValue(BLUEPRINTV2_JSON, HashMap.class);
+    assertEquals(2, getAsMap(blueprintAsMap, "cluster_settings").size());
+    assertEquals(2, getAsMap(blueprintAsMap, "Blueprints").size());
+    assertEquals("blueprint-def", getByPath(blueprintAsMap,
+      ImmutableList.of("Blueprints", "blueprint_name")));
+    assertEquals(2, getAsList(blueprintAsMap, "service_groups").size());
+    assertEquals("StreamSG", getByPath(blueprintAsMap,
+      ImmutableList.of("service_groups", 1, "name")));
+    assertEquals(2, getAsList(blueprintAsMap, "repository_versions").size());
+    assertEquals(1, getAsList(blueprintAsMap, "host_groups").size());
+    assertEquals("host_group_1", getByPath(blueprintAsMap,
+      ImmutableList.of("host_groups", 0, "name")));
+    System.out.println(blueprintAsMap);
+  }
+
+  @Test
+  public void testSerialization_serializeBlueprint() throws Exception {
+    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_JSON);
+    String serialized = blueprintFactory.convertToJson(bp);
+    // Test that serialized blueprint can be read again
+    bp = blueprintFactory.convertFromJson(serialized);
+    assertEquals(2, bp.getStackIds().size());
+    assertEquals(7, bp.getAllServiceIds().size());
+    assertEquals(2, bp.getServiceGroups().size());
+  }
+
+  @Test
+  public void testSerialization2_parseJsonAsBlueprint() throws Exception {
+    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_2_JSON);
+    assertEquals(new StackId("HDP", "3.0.0"),
+      bp.getServiceGroups().iterator().next().getServices().iterator().next().getStack().getStackId());
+    assertEquals(1, bp.getStackIds().size());
+    assertEquals(4, bp.getAllServiceIds().size());
+    assertEquals(1, bp.getServiceGroups().size());
+  }
+
+  @Test
+  public void testSerialization2_parseJsonAsMap() throws Exception {
+    ObjectMapper mapper = blueprintFactory.getObjectMapper();
+    Map<String, Object> blueprintAsMap = mapper.readValue(BLUEPRINTV2_2_JSON, HashMap.class);
+    assertEquals(2, getAsMap(blueprintAsMap, "cluster_settings").size());
+    assertEquals(2, getAsMap(blueprintAsMap, "Blueprints").size());
+    assertEquals("blueprint-def", getByPath(blueprintAsMap,
+      ImmutableList.of("Blueprints", "blueprint_name")));
+    assertEquals(1, getAsList(blueprintAsMap, "service_groups").size());
+    assertEquals("CoreSG", getByPath(blueprintAsMap,
+      ImmutableList.of("service_groups", 0, "name")));
+    assertEquals(1, getAsList(blueprintAsMap, "repository_versions").size());
+    assertEquals(1, getAsList(blueprintAsMap, "host_groups").size());
+    assertEquals("host_group_1", getByPath(blueprintAsMap,
+      ImmutableList.of("host_groups", 0, "name")));
+    System.out.println(blueprintAsMap);
+  }
+
+  @Test
+  public void testSerialization2_serializeBlueprint() throws Exception {
+    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_2_JSON);
+    String serialized = blueprintFactory.convertToJson(bp);
+    // Test that serialized blueprint can be read again
+    bp = blueprintFactory.convertFromJson(serialized);
+    assertEquals(1, bp.getStackIds().size());
+    assertEquals(4, bp.getAllServiceIds().size());
+    assertEquals(1, bp.getServiceGroups().size());
+  }
+
+  private static Map<String, Object> getAsMap(Map<String, Object> parentMap, String key) {
+    return (Map<String, Object>)parentMap.get(key);
+  }
+
+  private static List<Object> getAsList(Map<String, Object> parentMap, String key) {
+    return (List<Object>)parentMap.get(key);
+  }
+
+  private static Object getByPath(Map<String, Object> initialMap, List<Object> path) {
+    Object returnValue = initialMap;
+    for(Object key: path) {
+      if (key instanceof String) { // this element is a map
+        returnValue = ((Map<String, Object>)returnValue).get(key);
+        Preconditions.checkNotNull(returnValue, "No value for key: " + key);
+      }
+      else if (key instanceof Integer) { // this element is an arraylist
+        returnValue = ((List<Object>)returnValue).get((Integer)key);
+      }
+      else {
+        throw new IllegalArgumentException("Invalid path element: " + key);
+      }
+    }
+    return returnValue;
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/test/java/org/apache/ambari/server/topology/ProvisionClusterTemplateTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/ProvisionClusterTemplateTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/ProvisionClusterTemplateTest.java
new file mode 100644
index 0000000..b9179b6
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/ProvisionClusterTemplateTest.java
@@ -0,0 +1,30 @@
+package org.apache.ambari.server.topology;
+
+import java.io.IOException;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.junit.Test;
+
+public class ProvisionClusterTemplateTest {
+
+  public static final String CLUSTER_TEMPLATE = getResource("blueprintv2/cluster_template_v2.json");
+
+
+  @Test
+  public void testProvisionClusterTemplate() throws Exception {
+    ProvisionClusterTemplateFactory factory = new ProvisionClusterTemplateFactory();
+    ProvisionClusterTemplate template = factory.convertFromJson(CLUSTER_TEMPLATE);
+    System.out.println(template);
+  }
+
+
+  private static String getResource(String fileName) {
+    try {
+      return Resources.toString(Resources.getResource(fileName), Charsets.UTF_8);
+    }
+    catch (IOException ex) {
+      throw new RuntimeException(ex);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/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
deleted file mode 100644
index ee2ea1c..0000000
--- a/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/BlueprintImplV2Test.java
+++ /dev/null
@@ -1,175 +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.topology.validators;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.ambari.server.controller.StackV2;
-import org.apache.ambari.server.controller.StackV2Factory;
-import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.topology.BlueprintV2;
-import org.apache.ambari.server.topology.BlueprintV2Factory;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.Charsets;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Resources;
-
-public class BlueprintImplV2Test {
-
-  static String BLUEPRINTV2_JSON;
-  static String BLUEPRINTV2_2_JSON;
-
-  BlueprintV2Factory blueprintFactory;
-
-  @BeforeClass
-  public static void setUpClass() throws Exception {
-    BLUEPRINTV2_JSON = Resources.toString(Resources.getResource("blueprintv2/blueprintv2.json"), Charsets.UTF_8);
-    BLUEPRINTV2_2_JSON = Resources.toString(Resources.getResource("blueprintv2/blueprintv2_2.json"), Charsets.UTF_8);
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    StackV2Factory stackFactory = mock(StackV2Factory.class);
-    when(stackFactory.create(any(StackId.class))).thenAnswer(invocation -> {
-      StackId stackId = invocation.getArgumentAt(0, StackId.class);
-      StackV2 stack = new StackV2(stackId.getStackName(), stackId.getStackVersion(), stackId.getStackVersion() + ".0-1",
-        new HashMap<>(), new HashMap<>(), new HashMap<>(),
-        new HashMap<>(), new HashMap<>(), new HashMap<>(),
-        new HashMap<>(), new HashMap<>(), new HashMap<>());
-      return stack;
-    });
-    blueprintFactory = BlueprintV2Factory.create(stackFactory);
-    blueprintFactory.setPrettyPrintJson(true);
-  }
-
-  @Test
-  public void testSerialization_parseJsonAsBlueprint() throws Exception {
-    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_JSON);
-    assertEquals(new StackId("HDPCORE", "3.0.0"),
-      bp.getServiceGroups().iterator().next().getServices().iterator().next().getStack().getStackId());
-    assertEquals(2, bp.getStackIds().size());
-    assertEquals(7, bp.getAllServiceIds().size());
-    assertEquals(2, bp.getServiceGroups().size());
-  }
-
-  @Test
-  public void testSerialization_parseJsonAsMap() throws Exception {
-    ObjectMapper mapper = blueprintFactory.createObjectMapper();
-    Map<String, Object> blueprintAsMap = mapper.readValue(BLUEPRINTV2_JSON, HashMap.class);
-    assertEquals(2, getAsMap(blueprintAsMap, "cluster_settings").size());
-    assertEquals(2, getAsMap(blueprintAsMap, "Blueprints").size());
-    assertEquals("blueprint-def", getByPath(blueprintAsMap,
-      ImmutableList.of("Blueprints", "blueprint_name")));
-    assertEquals(2, getAsList(blueprintAsMap, "service_groups").size());
-    assertEquals("StreamSG", getByPath(blueprintAsMap,
-      ImmutableList.of("service_groups", 1, "name")));
-    assertEquals(2, getAsList(blueprintAsMap, "repository_versions").size());
-    assertEquals(1, getAsList(blueprintAsMap, "host_groups").size());
-    assertEquals("host_group_1", getByPath(blueprintAsMap,
-      ImmutableList.of("host_groups", 0, "name")));
-    System.out.println(blueprintAsMap);
-  }
-
-  @Test
-  public void testSerialization_serializeBlueprint() throws Exception {
-    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_JSON);
-    String serialized = blueprintFactory.convertToJson(bp);
-    // Test that serialized blueprint can be read again
-    bp = blueprintFactory.convertFromJson(serialized);
-    assertEquals(2, bp.getStackIds().size());
-    assertEquals(7, bp.getAllServiceIds().size());
-    assertEquals(2, bp.getServiceGroups().size());
-  }
-
-  @Test
-  public void testSerialization2_parseJsonAsBlueprint() throws Exception {
-    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_2_JSON);
-    assertEquals(new StackId("HDP", "3.0.0"),
-      bp.getServiceGroups().iterator().next().getServices().iterator().next().getStack().getStackId());
-    assertEquals(1, bp.getStackIds().size());
-    assertEquals(4, bp.getAllServiceIds().size());
-    assertEquals(1, bp.getServiceGroups().size());
-  }
-
-  @Test
-  public void testSerialization2_parseJsonAsMap() throws Exception {
-    ObjectMapper mapper = blueprintFactory.createObjectMapper();
-    Map<String, Object> blueprintAsMap = mapper.readValue(BLUEPRINTV2_2_JSON, HashMap.class);
-    assertEquals(2, getAsMap(blueprintAsMap, "cluster_settings").size());
-    assertEquals(2, getAsMap(blueprintAsMap, "Blueprints").size());
-    assertEquals("blueprint-def", getByPath(blueprintAsMap,
-      ImmutableList.of("Blueprints", "blueprint_name")));
-    assertEquals(1, getAsList(blueprintAsMap, "service_groups").size());
-    assertEquals("CoreSG", getByPath(blueprintAsMap,
-      ImmutableList.of("service_groups", 0, "name")));
-    assertEquals(1, getAsList(blueprintAsMap, "repository_versions").size());
-    assertEquals(1, getAsList(blueprintAsMap, "host_groups").size());
-    assertEquals("host_group_1", getByPath(blueprintAsMap,
-      ImmutableList.of("host_groups", 0, "name")));
-    System.out.println(blueprintAsMap);
-  }
-
-  @Test
-  public void testSerialization2_serializeBlueprint() throws Exception {
-    BlueprintV2 bp = blueprintFactory.convertFromJson(BLUEPRINTV2_2_JSON);
-    String serialized = blueprintFactory.convertToJson(bp);
-    // Test that serialized blueprint can be read again
-    bp = blueprintFactory.convertFromJson(serialized);
-    assertEquals(1, bp.getStackIds().size());
-    assertEquals(4, bp.getAllServiceIds().size());
-    assertEquals(1, bp.getServiceGroups().size());
-  }
-
-  private static Map<String, Object> getAsMap(Map<String, Object> parentMap, String key) {
-    return (Map<String, Object>)parentMap.get(key);
-  }
-
-  private static List<Object> getAsList(Map<String, Object> parentMap, String key) {
-    return (List<Object>)parentMap.get(key);
-  }
-
-  private static Object getByPath(Map<String, Object> initialMap, List<Object> path) {
-    Object returnValue = initialMap;
-    for(Object key: path) {
-      if (key instanceof String) { // this element is a map
-        returnValue = ((Map<String, Object>)returnValue).get(key);
-        Preconditions.checkNotNull(returnValue, "No value for key: " + key);
-      }
-      else if (key instanceof Integer) { // this element is an arraylist
-        returnValue = ((List<Object>)returnValue).get((Integer)key);
-      }
-      else {
-        throw new IllegalArgumentException("Invalid path element: " + key);
-      }
-    }
-    return returnValue;
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf82733b/ambari-server/src/test/resources/blueprintv2/cluster_template_v2.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/blueprintv2/cluster_template_v2.json b/ambari-server/src/test/resources/blueprintv2/cluster_template_v2.json
new file mode 100644
index 0000000..1fb0b04
--- /dev/null
+++ b/ambari-server/src/test/resources/blueprintv2/cluster_template_v2.json
@@ -0,0 +1,66 @@
+{
+  "blueprint": "blueprint-name",
+  "default_password": "super-secret-password",
+  "services": [
+    {
+      "service_group": "CORE_SG",
+      "name": "ZK1",
+      "configurations": [
+        {
+          "zoo.cfg": {
+            "properties": {
+              "dataDir": "/zookeeper2"
+            }
+          }
+        }
+      ]
+    },
+    {
+      "service_group": "CORE_SG",
+      "name": "HDFS",
+      "configurations": [
+        {
+          "hdfs-site": {
+            "properties": {
+              "property-name": "property-value"
+            }
+          }
+        }
+      ]
+    }
+
+  ],
+  "host_groups": [
+    {
+      "name": "host-group-1",
+      "configurations": [
+        {
+          "yarn-site": {
+            "properties": {
+              "property-name": "property-value"
+            }
+          }
+        }
+      ],
+      "hosts": [
+        {
+          "fqdn": "host.domain.com"
+        },
+        {
+          "fqdn": "host2.domain.com"
+        }
+      ]
+    }
+  ],
+  "credentials": [
+    {
+      "alias": "kdc.admin.credential",
+      "principal": "principal",
+      "key": "key",
+      "type": "TEMPORARY"
+    }
+  ],
+  "security": {
+    "type": "NONE"
+  }
+}