You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2015/03/27 02:18:07 UTC

ambari git commit: AMBARI-10221. Support separate themes for services defined in same metainfo.xml and multiple themes for service (mpapyrkovskyy via srimanth)

Repository: ambari
Updated Branches:
  refs/heads/trunk 6bceddf17 -> fb763311e


AMBARI-10221. Support separate themes for services defined in same metainfo.xml and multiple themes for service (mpapyrkovskyy via srimanth)


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

Branch: refs/heads/trunk
Commit: fb763311e25fe8a5f7ac42ac82b934e5d381dea7
Parents: 6bceddf
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Thu Mar 26 18:17:22 2015 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Thu Mar 26 18:17:22 2015 -0700

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../server/api/services/AmbariMetaInfo.java     |   6 +-
 .../server/api/services/StacksService.java      |  36 +++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/StackArtifactResourceProvider.java |  63 ------
 .../internal/ThemeArtifactResourceProvider.java | 203 +++++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   4 +-
 .../orm/entities/RepositoryVersionEntity.java   |   3 +
 .../ambari/server/stack/ServiceDirectory.java   |   3 -
 .../ambari/server/stack/ServiceModule.java      |  33 ++-
 .../apache/ambari/server/stack/ThemeModule.java |  23 +-
 .../apache/ambari/server/state/ServiceInfo.java |  67 ++++--
 .../apache/ambari/server/state/ThemeInfo.java   |  41 +++-
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |   8 +
 .../stacks/HDP/2.2/services/YARN/theme.json     | 221 -------------------
 .../HDP/2.2/services/YARN/themes/theme.json     | 221 +++++++++++++++++++
 16 files changed, 615 insertions(+), 323 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index c306281..7183fa7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -358,6 +358,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new SimpleResourceDefinition(Resource.Type.Artifact, "artifact", "artifacts");
         break;
 
+      case Theme:
+        resourceDefinition = new SimpleResourceDefinition(Resource.Type.Theme, "theme", "themes");
+        break;
+
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index a3b2f3a..8952153 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -90,6 +90,7 @@ public class AmbariMetaInfo {
 
 
   public static final String SERVICE_CONFIG_FOLDER_NAME = "configuration";
+  public static final String SERVICE_THEMES_FOLDER_NAME = "themes";
   public static final String SERVICE_CONFIG_FILE_NAME_POSTFIX = ".xml";
   public static final String RCO_FILE_NAME = "role_command_order.json";
   public static final String SERVICE_METRIC_FILE_NAME = "metrics.json";
@@ -101,11 +102,6 @@ public class AmbariMetaInfo {
   public static final String KERBEROS_DESCRIPTOR_FILE_NAME = "kerberos.json";
 
   /**
-   * Filename for theme file at service layer
-   */
-  public static final String SERVICE_THEME_FILE_NAME = "theme.json";
-
-  /**
    * This string is used in placeholder in places that are common for
    * all operating systems or in situations where os type is not important.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
index 0624dc1..dd7ec10 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
@@ -179,6 +179,31 @@ public class StacksService extends BaseService {
   }
 
   @GET
+  @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/themes")
+  @Produces("text/plain")
+  public Response getStackServiceThemes(String body, @Context HttpHeaders headers,
+                                           @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                           @PathParam("stackVersion") String stackVersion,
+                                           @PathParam("serviceName") String serviceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createStackServiceThemesResource(stackName, stackVersion, serviceName, null));
+  }
+
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/themes/{themeName}")
+  @Produces("text/plain")
+  public Response getStackServiceTheme(String body, @Context HttpHeaders headers,
+                                           @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                           @PathParam("stackVersion") String stackVersion,
+                                           @PathParam("serviceName") String serviceName,
+                                           @PathParam("themeName") String themeName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createStackServiceThemesResource(stackName, stackVersion, serviceName, themeName));
+  }
+
+  @GET
   @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/artifacts/{artifactName}")
   @Produces("text/plain")
   public Response getStackServiceArtifact(String body, @Context HttpHeaders headers,
@@ -390,6 +415,17 @@ public class StacksService extends BaseService {
     return createResource(Resource.Type.StackArtifact, mapIds);
   }
 
+  ResourceInstance createStackServiceThemesResource(String stackName, String stackVersion, String serviceName,
+                                                    String themeName) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+    mapIds.put(Resource.Type.StackService, serviceName);
+    mapIds.put(Resource.Type.Theme, themeName);
+
+    return createResource(Resource.Type.Theme, mapIds);
+  }
+
   ResourceInstance createStackResource(String stackName) {
 
     return createResource(Resource.Type.Stack,

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/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 7ba8ea9..113087c 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
@@ -155,6 +155,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return resourceProviderFactory.getRepositoryVersionResourceProvider();
       case StackArtifact:
         return new StackArtifactResourceProvider(managementController);
+      case Theme:
+        return new ThemeArtifactResourceProvider(managementController);
 
       default:
         throw new IllegalArgumentException("Unknown type " + type);

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
index 44828fa..b7530a0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
@@ -123,11 +123,6 @@ public class StackArtifactResourceProvider extends AbstractControllerResourcePro
   public static final String KERBEROS_DESCRIPTOR_NAME = "kerberos_descriptor";
 
   /**
-   * Name of theme artifact
-   */
-  public static final String THEME_ARTIFACT_NAME = "theme";
-
-  /**
    * name of the metrics descriptor artifact.
    */
   public static final String METRICS_DESCRIPTOR_NAME = "metrics_descriptor";
@@ -190,7 +185,6 @@ public class StackArtifactResourceProvider extends AbstractControllerResourcePro
 
     resources.addAll(getKerberosDescriptors(request, predicate));
     resources.addAll(getMetricsDescriptors(request, predicate));
-    resources.addAll(getThemes(request, predicate));
     // add other artifacts types here
 
     if (resources.isEmpty()) {
@@ -290,63 +284,6 @@ public class StackArtifactResourceProvider extends AbstractControllerResourcePro
     return resources;
   }
 
-  private Set<Resource> getThemes(Request request, Predicate predicate) throws NoSuchParentResourceException,
-    NoSuchResourceException, UnsupportedPropertyException, SystemException {
-
-    Set<Resource> resources = new HashSet<Resource>();
-    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
-      String artifactName = (String) properties.get(ARTIFACT_NAME_PROPERTY_ID);
-      if (artifactName == null || artifactName.equals(THEME_ARTIFACT_NAME)) {
-        String stackName = (String) properties.get(STACK_NAME_PROPERTY_ID);
-        String stackVersion = (String) properties.get(STACK_VERSION_PROPERTY_ID);
-        String stackService = (String) properties.get(STACK_SERVICE_NAME_PROPERTY_ID);
-
-        StackInfo stackInfo;
-        try {
-          stackInfo = getManagementController().getAmbariMetaInfo().getStack(stackName, stackVersion);
-        } catch (AmbariException e) {
-          throw new NoSuchParentResourceException(String.format(
-            "Parent stack resource doesn't exist: stackName='%s', stackVersion='%s'", stackName, stackVersion));
-        }
-
-        List<ServiceInfo> serviceInfoList = new ArrayList<ServiceInfo>();
-
-        if (stackService == null) {
-          serviceInfoList.addAll(stackInfo.getServices());
-        } else {
-          ServiceInfo service = stackInfo.getService(stackService);
-          if (service == null) {
-            throw new NoSuchParentResourceException(String.format(
-              "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
-              stackName, stackVersion, stackService));
-          }
-          serviceInfoList.add(service);
-        }
-
-        for (ServiceInfo serviceInfo : serviceInfoList) {
-          ThemeInfo themeInfo = serviceInfo.getThemeInfo();
-          LOG.info("Theme for stackName={}, stackVersion={}, serviceName={}, themeInfo={}", stackName, stackVersion, stackService, themeInfo);
-          if (themeInfo != null) {
-            Map<String, Object> themeMap = serviceInfo.getThemeInfo().getThemeMap();
-            if (themeMap != null) {
-              Resource resource = new ResourceImpl(Resource.Type.StackArtifact);
-              Set<String> requestedIds = getRequestPropertyIds(request, predicate);
-              setResourceProperty(resource, ARTIFACT_NAME_PROPERTY_ID, THEME_ARTIFACT_NAME, requestedIds);
-              setResourceProperty(resource, ARTIFACT_DATA_PROPERTY_ID, themeMap, requestedIds);
-              setResourceProperty(resource, STACK_NAME_PROPERTY_ID, stackName, requestedIds);
-              setResourceProperty(resource, STACK_VERSION_PROPERTY_ID, stackVersion, requestedIds);
-              setResourceProperty(resource, STACK_SERVICE_NAME_PROPERTY_ID, serviceInfo.getName(), requestedIds);
-
-              resources.add(resource);
-            }
-          }
-
-        }
-      }
-    }
-    return resources;
-  }
-
   /**
    * Get all stack and stack service metrics descriptor resources.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ThemeArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ThemeArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ThemeArtifactResourceProvider.java
new file mode 100644
index 0000000..4b5c95d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ThemeArtifactResourceProvider.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.AmbariException;
+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.state.ServiceInfo;
+import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.ThemeInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ThemeArtifactResourceProvider extends AbstractControllerResourceProvider {
+
+  public static final String STACK_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "stack_name");
+  public static final String STACK_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "stack_version");
+  public static final String STACK_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "service_name");
+  public static final String THEME_FILE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "file_name");
+  public static final String THEME_DEFAULT_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "default");
+  public static final String THEME_DATA_PROPERTY_ID = PropertyHelper.getPropertyId("ThemeInfo", "theme_data");
+
+  /**
+   * primary key fields
+   */
+  public static Set<String> pkPropertyIds = new HashSet<String>();
+  /**
+   * map of resource type to fk field
+   */
+  public static Map<Resource.Type, String> keyPropertyIds =
+    new HashMap<Resource.Type, String>();
+
+  /**
+   * resource properties
+   */
+  public static Set<String> propertyIds = new HashSet<String>();
+
+  static {
+    keyPropertyIds.put(Resource.Type.Theme, THEME_FILE_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.Stack, STACK_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.StackVersion, STACK_VERSION_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.StackService, STACK_SERVICE_NAME_PROPERTY_ID);
+
+    pkPropertyIds.add(THEME_FILE_NAME_PROPERTY_ID);
+
+    // resource properties
+    propertyIds.add(STACK_NAME_PROPERTY_ID);
+    propertyIds.add(STACK_VERSION_PROPERTY_ID);
+    propertyIds.add(STACK_SERVICE_NAME_PROPERTY_ID);
+    propertyIds.add(THEME_FILE_NAME_PROPERTY_ID);
+    propertyIds.add(THEME_DEFAULT_PROPERTY_ID);
+    propertyIds.add(THEME_DATA_PROPERTY_ID);
+  }
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param managementController the management controller
+   */
+  protected ThemeArtifactResourceProvider(AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Creating of themes is not supported");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+
+    Set<Resource> resources = new LinkedHashSet<Resource>();
+
+    resources.addAll(getThemes(request, predicate));
+    // add other artifacts types here
+
+    if (resources.isEmpty()) {
+      throw new NoSuchResourceException(
+        "The requested resource doesn't exist: Themes not found, " + predicate);
+    }
+
+    return resources;
+
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Updating of themes is not supported");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Deleting of themes is not supported");
+  }
+
+  private Set<Resource> getThemes(Request request, Predicate predicate) throws NoSuchParentResourceException,
+    NoSuchResourceException, UnsupportedPropertyException, SystemException {
+
+    Set<Resource> resources = new LinkedHashSet<Resource>();
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      String themeFileName = (String) properties.get(THEME_FILE_NAME_PROPERTY_ID);
+
+
+      String stackName = (String) properties.get(STACK_NAME_PROPERTY_ID);
+      String stackVersion = (String) properties.get(STACK_VERSION_PROPERTY_ID);
+      String stackService = (String) properties.get(STACK_SERVICE_NAME_PROPERTY_ID);
+
+      StackInfo stackInfo;
+      try {
+        stackInfo = getManagementController().getAmbariMetaInfo().getStack(stackName, stackVersion);
+      } catch (AmbariException e) {
+        throw new NoSuchParentResourceException(String.format(
+          "Parent stack resource doesn't exist: stackName='%s', stackVersion='%s'", stackName, stackVersion));
+      }
+
+      List<ServiceInfo> serviceInfoList = new ArrayList<ServiceInfo>();
+
+      if (stackService == null) {
+        serviceInfoList.addAll(stackInfo.getServices());
+      } else {
+        ServiceInfo service = stackInfo.getService(stackService);
+        if (service == null) {
+          throw new NoSuchParentResourceException(String.format(
+            "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
+            stackName, stackVersion, stackService));
+        }
+        serviceInfoList.add(service);
+      }
+
+      for (ServiceInfo serviceInfo : serviceInfoList) {
+        List<ThemeInfo> serviceThemes = new ArrayList<ThemeInfo>();
+        if (themeFileName != null) {
+          LOG.debug("Getting themes from service {}, themes = {}", serviceInfo.getName(), serviceInfo.getThemesMap());
+          serviceThemes.add(serviceInfo.getThemesMap().get(themeFileName));
+        } else {
+          for (ThemeInfo themeInfo : serviceInfo.getThemesMap().values()) {
+            if (themeInfo.getIsDefault()) {
+              serviceThemes.add(0, themeInfo);
+            } else {
+              serviceThemes.add(themeInfo);
+            }
+          }
+        }
+
+        List<Resource> serviceResources = new ArrayList<Resource>();
+        for (ThemeInfo themeInfo : serviceThemes) {
+          Resource resource = new ResourceImpl(Resource.Type.Theme);
+          Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+          setResourceProperty(resource, THEME_FILE_NAME_PROPERTY_ID, themeInfo.getFileName(), requestedIds);
+          setResourceProperty(resource, THEME_DEFAULT_PROPERTY_ID, themeInfo.getIsDefault(), requestedIds);
+          setResourceProperty(resource, THEME_DATA_PROPERTY_ID, themeInfo.getThemeMap(), requestedIds);
+          setResourceProperty(resource, STACK_NAME_PROPERTY_ID, stackName, requestedIds);
+          setResourceProperty(resource, STACK_VERSION_PROPERTY_ID, stackVersion, requestedIds);
+          setResourceProperty(resource, STACK_SERVICE_NAME_PROPERTY_ID, serviceInfo.getName(), requestedIds);
+          serviceResources.add(resource);
+        }
+
+        resources.addAll(serviceResources);
+
+      }
+    }
+    return resources;
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index aa5cf64..6e5db3a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -137,7 +137,8 @@ public interface Resource {
     PreUpgradeCheck,
     Stage,
     StackArtifact,
-    Artifact;
+    Artifact,
+    Theme;
 
     /**
      * Get the {@link Type} that corresponds to this InternalType.
@@ -236,6 +237,7 @@ public interface Resource {
     public static final Type Stage = InternalType.Stage.getType();
     public static final Type StackArtifact = InternalType.StackArtifact.getType();
     public static final Type Artifact = InternalType.Artifact.getType();
+    public static final Type Theme = InternalType.Theme.getType();
 
     /**
      * The type name.

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
index 0c52a0b..23c121e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
@@ -20,14 +20,17 @@ package org.apache.ambari.server.orm.entities;
 import java.util.Collections;
 import java.util.List;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Lob;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 import javax.persistence.UniqueConstraint;

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
index 7f2ff68..e7f27ee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
@@ -109,9 +109,6 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory {
         + File.separator + AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME);
     kerberosDescriptorFile = kdf.exists() ? kdf : null;
 
-    File themeFile = new File(directory.getAbsolutePath() + File.separator + AmbariMetaInfo.SERVICE_THEME_FILE_NAME);
-    this.themeFile = themeFile.exists() ? themeFile : null;
-
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
index f0cb1b8..ef16e88 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.stack;
 
+import java.io.File;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -32,6 +33,7 @@ import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.CustomCommandDefinition;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.ThemeInfo;
 
 /**
  * Service module which provides all functionality related to parsing and fully
@@ -172,6 +174,9 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
     if (serviceInfo.getKerberosDescriptorFile() == null) {
       serviceInfo.setKerberosDescriptorFile(parent.getKerberosDescriptorFile());
     }
+    if (serviceInfo.getThemesMap().isEmpty()) {
+      serviceInfo.setThemesMap(parent.getThemesMap());
+    }
 
     mergeCustomCommands(parent.getCustomCommands(), serviceInfo.getCustomCommands());
     mergeConfigDependencies(parent);
@@ -285,11 +290,18 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
 
   private void populateThemeModules() {
 
-    ThemeModule themeModule = new ThemeModule(serviceDirectory.getThemeFile());
+    if (serviceInfo.getThemesDir() == null) {
+      serviceInfo.setThemesDir(AmbariMetaInfo.SERVICE_THEMES_FOLDER_NAME);
+    }
+
+    String themesDir = serviceDirectory.getAbsolutePath() + File.separator + serviceInfo.getThemesDir();
 
-    if (themeModule.isValid()) {
-      serviceInfo.setThemeInfo(themeModule.getModuleInfo());
-      themeModules.put(themeModule.getId(), themeModule);
+    if (serviceInfo.getThemes() != null) {
+      for (ThemeInfo themeInfo : serviceInfo.getThemes()) {
+        File themeFile = new File(themesDir + File.separator + themeInfo.getFileName());
+        ThemeModule module = new ThemeModule(themeFile, themeInfo);
+        themeModules.put(module.getId(), module);
+      }
     }
 
     //lets not fail if theme contain errors
@@ -300,7 +312,18 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
    */
   private void mergeThemes(ServiceModule parent, Map<String, StackModule> allStacks,
                            Map<String, ServiceModule> commonServices) throws AmbariException {
-    mergeChildModules(allStacks, commonServices, themeModules, parent.themeModules);
+    Collection<ThemeModule> mergedModules = mergeChildModules(allStacks, commonServices, themeModules, parent.themeModules);
+
+    for (ThemeModule mergedModule : mergedModules) {
+      themeModules.put(mergedModule.getId(), mergedModule);
+      ThemeInfo moduleInfo = mergedModule.getModuleInfo();
+      if (!moduleInfo.isDeleted()) {
+        serviceInfo.getThemesMap().put(moduleInfo.getFileName(), moduleInfo);
+      } else {
+        serviceInfo.getThemesMap().remove(moduleInfo.getFileName());
+      }
+
+    }
 
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java
index 8430ad4..5b22dd9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java
@@ -43,14 +43,18 @@ public class ThemeModule extends BaseModule<ThemeModule, ThemeInfo> implements V
   }
 
 
-  private ThemeInfo moduleInfo = new ThemeInfo();
+  private ThemeInfo moduleInfo;
   private boolean valid = true;
   private Set<String> errors = new HashSet<String>();
 
   public ThemeModule(File themeFile) {
+    this(themeFile, new ThemeInfo());
+  }
 
-    if (themeFile == null) {
-    } else {
+  public ThemeModule(File themeFile, ThemeInfo moduleInfo) {
+    this.moduleInfo = moduleInfo;
+    if (!moduleInfo.isDeleted() && themeFile != null) {
+      LOG.debug("Looking for theme in {}", themeFile.getAbsolutePath());
       FileReader reader = null;
       try {
         reader = new FileReader(themeFile);
@@ -58,10 +62,11 @@ public class ThemeModule extends BaseModule<ThemeModule, ThemeInfo> implements V
         LOG.error("Theme file not found");
       }
       try {
-        TypeReference<HashMap<String,Object>> typeRef = new TypeReference<HashMap<String,Object>>() {};
+        TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
+        };
         Map<String, Object> map = mapper.readValue(reader, typeRef);
         moduleInfo.setThemeMap(map);
-        LOG.info("Loaded theme: {}", moduleInfo);
+        LOG.debug("Loaded theme: {}", moduleInfo);
       } catch (IOException e) {
         LOG.error("Unable to parse theme file ", e);
         setValid(false);
@@ -76,7 +81,11 @@ public class ThemeModule extends BaseModule<ThemeModule, ThemeInfo> implements V
 
   @Override
   public void resolve(ThemeModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException {
-    if (parent.getModuleInfo() != null) {
+    ThemeInfo parentModuleInfo = parent.getModuleInfo();
+
+
+
+    if (parent.getModuleInfo() != null && !moduleInfo.isDeleted()) {
       moduleInfo.setThemeMap(mergedMap(parent.getModuleInfo().getThemeMap(), moduleInfo.getThemeMap()));
     }
   }
@@ -126,7 +135,7 @@ public class ThemeModule extends BaseModule<ThemeModule, ThemeInfo> implements V
 
   @Override
   public String getId() {
-    return "theme";
+    return moduleInfo.getFileName();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
index a366e82..67342e3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
@@ -106,10 +106,8 @@ public class ServiceInfo implements Validable{
   }
 
   @XmlTransient
-  private ThemeInfo themeInfo = null;
-  
-  @XmlTransient
   private File metricsFile = null;
+
   @XmlTransient
   private Map<String, Map<String, List<MetricDefinition>>> metrics = null;
   
@@ -169,6 +167,18 @@ public class ServiceInfo implements Validable{
   @XmlElement(name="configuration-dir")
   private String configDir = AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME;
 
+  @JsonIgnore
+  @XmlElement(name = "themes-dir")
+  private String themesDir = AmbariMetaInfo.SERVICE_THEMES_FOLDER_NAME;
+
+  @JsonIgnore
+  @XmlElementWrapper(name = "themes")
+  @XmlElements(@XmlElement(name = "theme"))
+  private List<ThemeInfo> themes;
+
+  @XmlTransient
+  private volatile Map<String, ThemeInfo> themesMap;
+
 
   /**
    * Map of of os-specific details that is exposed (and initialised from list)
@@ -611,20 +621,6 @@ public class ServiceInfo implements Validable{
     return excludedConfigTypes;
   }
 
-  /**
-   * @return theme description map
-   */
-  public ThemeInfo getThemeInfo() {
-    return themeInfo;
-  }
-
-  /**
-   * @param themeInfo map with theme description
-   */
-  public void setThemeInfo(ThemeInfo themeInfo) {
-    this.themeInfo = themeInfo;
-  }
-
   public void setExcludedConfigTypes(Set<String> excludedConfigTypes) {
     this.excludedConfigTypes = excludedConfigTypes;
   }
@@ -666,4 +662,41 @@ public class ServiceInfo implements Validable{
   public void setRestartRequiredAfterRackChange(Boolean restartRequiredAfterRackChange) {
     this.restartRequiredAfterRackChange = restartRequiredAfterRackChange;
   }
+
+  public String getThemesDir() {
+    return themesDir;
+  }
+
+  public void setThemesDir(String themesDir) {
+    this.themesDir = themesDir;
+  }
+
+  public List<ThemeInfo> getThemes() {
+    return themes;
+  }
+
+  public void setThemes(List<ThemeInfo> themes) {
+    this.themes = themes;
+  }
+
+  public Map<String, ThemeInfo> getThemesMap() {
+    if (themesMap == null) {
+      synchronized (this) {
+      }
+      if (themesMap == null) {
+        Map<String, ThemeInfo> tmp = new TreeMap<String, ThemeInfo>();
+        if (themes != null) {
+          for (ThemeInfo theme : themes) {
+            tmp.put(theme.getFileName(), theme);
+          }
+        }
+        themesMap = tmp;
+      }
+    }
+    return themesMap;
+  }
+
+  public void setThemesMap(Map<String, ThemeInfo> themesMap) {
+    this.themesMap = themesMap;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/java/org/apache/ambari/server/state/ThemeInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ThemeInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ThemeInfo.java
index 4f791a9..355fe25 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ThemeInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ThemeInfo.java
@@ -17,12 +17,24 @@
  */
 package org.apache.ambari.server.state;
 
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
 import java.util.Map;
 
 /**
  * Wrapper for theme description
  */
+@XmlAccessorType(XmlAccessType.FIELD)
 public class ThemeInfo {
+
+  private String fileName;
+  @XmlElement(name = "default")
+  private Boolean isDefault = false;
+  private Boolean deleted = false;
+
+  @XmlTransient
   private Map<String, Object> themeMap = null;
 
   public ThemeInfo() {
@@ -39,7 +51,34 @@ public class ThemeInfo {
   @Override
   public String toString() {
     return "ThemeInfo{" +
-      "themeMap=" + themeMap +
+      "deleted=" + deleted +
+      ", fileName='" + fileName + '\'' +
+      ", isDefault=" + isDefault +
+      ", themeMap=" + themeMap +
       '}';
   }
+
+  public String getFileName() {
+    return fileName;
+  }
+
+  public void setFileName(String fileName) {
+    this.fileName = fileName;
+  }
+
+  public Boolean getIsDefault() {
+    return isDefault;
+  }
+
+  public void setIsDefault(Boolean isDefault) {
+    this.isDefault = isDefault;
+  }
+
+  public Boolean isDeleted() {
+    return deleted;
+  }
+
+  public void setDeleted(Boolean deleted) {
+    this.deleted = deleted;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
index a8fc6ea..39e81cc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
@@ -57,6 +57,13 @@
           </packages>
         </osSpecific>
       </osSpecifics>
+
+      <themes>
+        <theme>
+          <fileName>theme.json</fileName>
+          <default>true</default>
+        </theme>
+      </themes>
     </service>
 
     <service>
@@ -82,6 +89,7 @@
         </osSpecific>
       </osSpecifics>
       <configuration-dir>configuration-mapred</configuration-dir>
+      <themes-dir>themes-mapred</themes-dir>
 
     </service>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/theme.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/theme.json b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/theme.json
deleted file mode 100644
index 1bcd696..0000000
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/theme.json
+++ /dev/null
@@ -1,221 +0,0 @@
-{
-  "Theme": {
-    "name": "default",
-    "description": "Default theme for YARN service",
-    "configuration": {
-      "layouts": [
-        {
-          "name": "default",
-          "tabs": [
-            {
-              "name": "settings",
-              "display-name": "Settings",
-              "layout": {
-                "tab-columns": "3",
-                "tab-rows": "2",
-                "sections": [
-                  {
-                    "name": "section-nm-sizing",
-                    "display-name": "NodeManager Sizing",
-                    "row-index": "0",
-                    "column-index": "0",
-                    "row-span": "1",
-                    "column-span": "2",
-                    "section-columns": "2",
-                    "section-rows": "1",
-                    "subsections": [
-	                  {
-	                    "name": "subsection-nm-sizing-col1",
-	                    "row-index": "0",
-	                    "column-index": "0",
-	                    "row-span": "1",
-	                    "column-span": "1"
-	                  }, {
-	                    "name": "subsection-nm-sizing-col2",
-	                    "row-index": "0",
-	                    "column-index": "1",
-	                    "row-span": "1",
-	                    "column-span": "1"
-	                  }
-	                ]
-                  },
-                  {
-                    "name": "section-yarn-platform-features",
-                    "display-name": "YARN Platform Features",
-                    "row-index": "0",
-                    "column-index": "1",
-                    "row-span": "1",
-                    "column-span": "1",
-                    "section-columns": "1",
-                    "section-rows": "1",
-                    "subsections": [
-                      {
-                        "name": "subsection-yarn-platform-features-col1",
-                        "row-index": "0",
-                        "column-index": "0",
-                        "row-span": "1",
-                        "column-span": "1"
-                      }
-                    ]
-                  },
-                  {
-                    "name": "section-container-sizing",
-                    "display-name": "Container Sizing",
-                    "row-index": "1",
-                    "column-index": "0",
-                    "row-span": "1",
-                    "column-span": "2",
-                    "section-columns": "2",
-                    "section-rows": "1",
-                    "subsections": [
-                      {
-                        "name": "subsection-container-sizing-col1",
-                        "row-index": "0",
-                        "column-index": "0",
-                        "row-span": "1",
-                        "column-span": "1"
-                      }, {
-                        "name": "subsection-container-sizing-col2",
-                        "row-index": "0",
-                        "column-index": "1",
-                        "row-span": "1",
-                        "column-span": "1"
-                      }
-                    ]
-                  }
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    "placement": {
-      "configuration-layout": "default",
-      "configs": [
-        {
-          "config": "yarn-site/yarn.nodemanager.resource.memory-mb",
-          "subsection-name": "subsection-nm-sizing-col1"
-        },
-        {
-          "config": "yarn-site/yarn.nodemanager.vmem-pmem-ratio",
-          "subsection-name": "subsection-nm-sizing-col1"
-        },
-        {
-          "config": "yarn-site/yarn.nodemanager.resource.percentage-physical-cpu-limit",
-          "subsection-name": "subsection-nm-sizing-col2"
-        },
-        {
-          "config": "yarn-site/yarn.nodemanager.resource.cpu-vcores",
-          "subsection-name": "subsection-nm-sizing-col2"
-        },
-        {
-          "config": "yarn-site/yarn.scheduler.minimum-allocation-mb",
-          "subsection-name": "subsection-container-sizing-col1"
-        },
-        {
-          "config": "yarn-site/yarn.scheduler.maximum-allocation-mb",
-          "subsection-name": "subsection-container-sizing-col1"
-        },
-        {
-          "config": "yarn-site/yarn.scheduler.minimum-allocation-vcores",
-          "subsection-name": "subsection-container-sizing-col2"
-        },
-        {
-          "config": "yarn-site/yarn.scheduler.maximum-allocation-vcores",
-          "subsection-name": "subsection-container-sizing-col2"
-        }
-      ]
-    },
-    "widgets":[
-      {
-        "config":"yarn-site/yarn.nodemanager.resource.memory-mb",
-        "widget":{
-          "type":"slider",
-          "units":[
-            {
-              "unit-name":"MB"
-            }
-          ]
-        }
-      },
-      {
-        "config": "yarn-site/yarn.nodemanager.vmem-pmem-ratio",
-        "widget": {
-          "type": "slider",
-          "units": [
-            {
-              "unit-name": "float"
-            }
-          ]
-        }
-      },
-      {
-        "config": "yarn-site/yarn.nodemanager.resource.percentage-physical-cpu-limit",
-        "widget": {
-          "type": "slider",
-          "units": [
-            {
-              "unit-name": "percent"
-            }
-          ]
-        }
-      },
-      {
-        "config": "yarn-site/yarn.nodemanager.resource.cpu-vcores",
-        "widget": {
-          "type": "slider",
-          "units": [
-            {
-              "unit-name": "int"
-            }
-          ]
-        }
-      },
-      {
-        "config":"yarn-site/yarn.scheduler.minimum-allocation-mb",
-        "widget":{
-          "type":"slider",
-          "units":[
-            {
-              "unit-name":"MB"
-            }
-          ]
-        }
-      },
-      {
-        "config":"yarn-site/yarn.scheduler.maximum-allocation-mb",
-        "widget":{
-          "type":"slider",
-          "units":[
-            {
-              "unit-name":"MB"
-            }
-          ]
-        }
-      },
-      {
-        "config":"yarn-site/yarn.scheduler.minimum-allocation-vcores",
-        "widget":{
-          "type":"slider",
-          "units":[
-            {
-              "unit-name":"int"
-            }
-          ]
-        }
-      },
-      {
-        "config":"yarn-site/yarn.scheduler.maximum-allocation-vcores",
-        "widget":{
-          "type":"slider",
-          "units":[
-            {
-              "unit-name":"int"
-            }
-          ]
-        }
-      }
-    ]
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb763311/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes/theme.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes/theme.json b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes/theme.json
new file mode 100644
index 0000000..1bcd696
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes/theme.json
@@ -0,0 +1,221 @@
+{
+  "Theme": {
+    "name": "default",
+    "description": "Default theme for YARN service",
+    "configuration": {
+      "layouts": [
+        {
+          "name": "default",
+          "tabs": [
+            {
+              "name": "settings",
+              "display-name": "Settings",
+              "layout": {
+                "tab-columns": "3",
+                "tab-rows": "2",
+                "sections": [
+                  {
+                    "name": "section-nm-sizing",
+                    "display-name": "NodeManager Sizing",
+                    "row-index": "0",
+                    "column-index": "0",
+                    "row-span": "1",
+                    "column-span": "2",
+                    "section-columns": "2",
+                    "section-rows": "1",
+                    "subsections": [
+	                  {
+	                    "name": "subsection-nm-sizing-col1",
+	                    "row-index": "0",
+	                    "column-index": "0",
+	                    "row-span": "1",
+	                    "column-span": "1"
+	                  }, {
+	                    "name": "subsection-nm-sizing-col2",
+	                    "row-index": "0",
+	                    "column-index": "1",
+	                    "row-span": "1",
+	                    "column-span": "1"
+	                  }
+	                ]
+                  },
+                  {
+                    "name": "section-yarn-platform-features",
+                    "display-name": "YARN Platform Features",
+                    "row-index": "0",
+                    "column-index": "1",
+                    "row-span": "1",
+                    "column-span": "1",
+                    "section-columns": "1",
+                    "section-rows": "1",
+                    "subsections": [
+                      {
+                        "name": "subsection-yarn-platform-features-col1",
+                        "row-index": "0",
+                        "column-index": "0",
+                        "row-span": "1",
+                        "column-span": "1"
+                      }
+                    ]
+                  },
+                  {
+                    "name": "section-container-sizing",
+                    "display-name": "Container Sizing",
+                    "row-index": "1",
+                    "column-index": "0",
+                    "row-span": "1",
+                    "column-span": "2",
+                    "section-columns": "2",
+                    "section-rows": "1",
+                    "subsections": [
+                      {
+                        "name": "subsection-container-sizing-col1",
+                        "row-index": "0",
+                        "column-index": "0",
+                        "row-span": "1",
+                        "column-span": "1"
+                      }, {
+                        "name": "subsection-container-sizing-col2",
+                        "row-index": "0",
+                        "column-index": "1",
+                        "row-span": "1",
+                        "column-span": "1"
+                      }
+                    ]
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    "placement": {
+      "configuration-layout": "default",
+      "configs": [
+        {
+          "config": "yarn-site/yarn.nodemanager.resource.memory-mb",
+          "subsection-name": "subsection-nm-sizing-col1"
+        },
+        {
+          "config": "yarn-site/yarn.nodemanager.vmem-pmem-ratio",
+          "subsection-name": "subsection-nm-sizing-col1"
+        },
+        {
+          "config": "yarn-site/yarn.nodemanager.resource.percentage-physical-cpu-limit",
+          "subsection-name": "subsection-nm-sizing-col2"
+        },
+        {
+          "config": "yarn-site/yarn.nodemanager.resource.cpu-vcores",
+          "subsection-name": "subsection-nm-sizing-col2"
+        },
+        {
+          "config": "yarn-site/yarn.scheduler.minimum-allocation-mb",
+          "subsection-name": "subsection-container-sizing-col1"
+        },
+        {
+          "config": "yarn-site/yarn.scheduler.maximum-allocation-mb",
+          "subsection-name": "subsection-container-sizing-col1"
+        },
+        {
+          "config": "yarn-site/yarn.scheduler.minimum-allocation-vcores",
+          "subsection-name": "subsection-container-sizing-col2"
+        },
+        {
+          "config": "yarn-site/yarn.scheduler.maximum-allocation-vcores",
+          "subsection-name": "subsection-container-sizing-col2"
+        }
+      ]
+    },
+    "widgets":[
+      {
+        "config":"yarn-site/yarn.nodemanager.resource.memory-mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"MB"
+            }
+          ]
+        }
+      },
+      {
+        "config": "yarn-site/yarn.nodemanager.vmem-pmem-ratio",
+        "widget": {
+          "type": "slider",
+          "units": [
+            {
+              "unit-name": "float"
+            }
+          ]
+        }
+      },
+      {
+        "config": "yarn-site/yarn.nodemanager.resource.percentage-physical-cpu-limit",
+        "widget": {
+          "type": "slider",
+          "units": [
+            {
+              "unit-name": "percent"
+            }
+          ]
+        }
+      },
+      {
+        "config": "yarn-site/yarn.nodemanager.resource.cpu-vcores",
+        "widget": {
+          "type": "slider",
+          "units": [
+            {
+              "unit-name": "int"
+            }
+          ]
+        }
+      },
+      {
+        "config":"yarn-site/yarn.scheduler.minimum-allocation-mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"MB"
+            }
+          ]
+        }
+      },
+      {
+        "config":"yarn-site/yarn.scheduler.maximum-allocation-mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"MB"
+            }
+          ]
+        }
+      },
+      {
+        "config":"yarn-site/yarn.scheduler.minimum-allocation-vcores",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"int"
+            }
+          ]
+        }
+      },
+      {
+        "config":"yarn-site/yarn.scheduler.maximum-allocation-vcores",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"int"
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file