You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/08/28 19:50:13 UTC

[38/45] git commit: AMBARI-7056. Need for a separate config file that comprises of cluster specific properties (aonishuk)

AMBARI-7056. Need for a separate config file that comprises of cluster specific properties (aonishuk)


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

Branch: refs/heads/branch-alerts-dev
Commit: 6bd0394a5f2254da2421f066473f680dc32772a1
Parents: 1b017b7
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Thu Aug 28 18:05:43 2014 +0300
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Thu Aug 28 18:05:43 2014 +0300

----------------------------------------------------------------------
 .../ambari/server/api/query/QueryImpl.java      |   1 -
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 ...ackLevelConfigurationResourceDefinition.java |  53 ++++++
 .../StackVersionResourceDefinition.java         |   1 +
 .../server/api/services/AmbariMetaInfo.java     |  34 +++-
 .../server/api/services/StacksService.java      |  35 +++-
 .../server/api/util/StackExtensionHelper.java   | 105 ++++++++---
 .../controller/AmbariManagementController.java  |   8 +
 .../AmbariManagementControllerImpl.java         |  44 +++++
 .../StackLevelConfigurationRequest.java         |  42 +++++
 .../StackLevelConfigurationResponse.java        |  37 ++++
 .../server/controller/StackVersionResponse.java |  14 +-
 .../AbstractControllerResourceProvider.java     |   2 +
 ...StackLevelConfigurationResourceProvider.java | 159 ++++++++++++++++
 .../internal/StackVersionResourceProvider.java  |   6 +
 .../ambari/server/controller/spi/Resource.java  |   4 +-
 .../apache/ambari/server/state/ServiceInfo.java |   1 +
 .../apache/ambari/server/state/StackInfo.java   |  26 ++-
 .../src/main/resources/key_properties.json      |   5 +
 .../src/main/resources/properties.json          |  11 ++
 .../HDP/1.3.2/configuration/cluster-env.xml     |  49 +++++
 .../HDP/2.0.6/configuration/cluster-env.xml     |  49 +++++
 .../ambari/server/api/query/QueryImplTest.java  |   2 +-
 .../api/util/StackExtensionHelperTest.java      |  23 +--
 .../internal/AbstractResourceProviderTest.java  |  45 +++++
 ...kLevelConfigurationResourceProviderTest.java | 181 +++++++++++++++++++
 26 files changed, 892 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
index 261559a..6dfdb49 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
@@ -895,7 +895,6 @@ public class QueryImpl implements Query, ResourceInstance {
         mapTemporalInfo.put(propertyId, globalTemporalInfo);
       }
     }
-
     return PropertyHelper.getReadRequest(setProperties, requestInfoProperties, mapTemporalInfo);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 13fff1d..f85c0ea 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
@@ -141,6 +141,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
       case StackVersion:
         resourceDefinition = new StackVersionResourceDefinition();
         break;
+        
+      case StackLevelConfiguration:
+        resourceDefinition = new StackLevelConfigurationResourceDefinition();
+        break;
 
       case StackService:
         resourceDefinition = new StackServiceResourceDefinition();

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackLevelConfigurationResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackLevelConfigurationResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackLevelConfigurationResourceDefinition.java
new file mode 100644
index 0000000..9265234
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackLevelConfigurationResourceDefinition.java
@@ -0,0 +1,53 @@
+/**
+ * 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.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+
+public class StackLevelConfigurationResourceDefinition extends BaseStacksResourceDefinition {
+
+  public StackLevelConfigurationResourceDefinition(Type resourceType) {
+    super(Resource.Type.StackLevelConfiguration);
+  }
+
+  public StackLevelConfigurationResourceDefinition() {
+    super(Resource.Type.StackLevelConfiguration);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "configurations";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "configuration";
+  }
+  /*
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    return setChildren;
+  }
+  */
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java
index d641e4c..5bf3bac 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java
@@ -51,6 +51,7 @@ public class StackVersionResourceDefinition extends BaseStacksResourceDefinition
     
     setChildren.add(new SubResourceDefinition(Resource.Type.OperatingSystem));
     setChildren.add(new SubResourceDefinition(Resource.Type.StackService));
+    setChildren.add(new SubResourceDefinition(Resource.Type.StackLevelConfiguration));
 
     return setChildren;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 56b866d..cb27100 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
@@ -665,13 +665,21 @@ public class AmbariMetaInfo {
 
   public Set<PropertyInfo> getProperties(String stackName, String version, String serviceName)
       throws AmbariException {
-
     ServiceInfo serviceInfo = getServiceInfo(stackName, version, serviceName);
     List<PropertyInfo> properties = serviceInfo.getProperties();
     Set<PropertyInfo> propertiesResult = new HashSet<PropertyInfo>(properties);
 
     return propertiesResult;
   }
+  
+  public Set<PropertyInfo> getStackProperties(String stackName, String version)
+      throws AmbariException {
+    StackInfo stackInfo = getStackInfo(stackName, version);
+    List<PropertyInfo> properties = stackInfo.getProperties();
+    Set<PropertyInfo> propertiesResult = new HashSet<PropertyInfo>(properties);
+
+    return propertiesResult;
+  }
 
   public Set<PropertyInfo> getPropertiesByName(String stackName, String version, String serviceName, String propertyName)
       throws AmbariException {
@@ -698,6 +706,30 @@ public class AmbariMetaInfo {
 
     return propertyResult;
   }
+  
+  public Set<PropertyInfo> getStackPropertiesByName(String stackName, String version, String propertyName)
+      throws AmbariException {
+    Set<PropertyInfo> properties = getStackProperties(stackName, version);
+
+    if (properties.size() == 0)
+      throw new StackAccessException("stackName=" + stackName
+          + ", stackVersion=" + version
+          + ", propertyName=" + propertyName);
+
+    Set<PropertyInfo> propertyResult = new HashSet<PropertyInfo>();
+
+    for (PropertyInfo property : properties) {
+      if (property.getName().equals(propertyName))
+        propertyResult.add(property);
+    }
+
+    if (propertyResult.isEmpty())
+      throw new StackAccessException("stackName=" + stackName
+          + ", stackVersion=" + version
+          + ", propertyName=" + propertyName);
+
+    return propertyResult;
+  }
 
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 822199c..3df1eaf 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
@@ -92,7 +92,6 @@ public class StacksService extends BaseService {
         createStackVersionResource(stackName, stackVersion));
   }
 
-
   @GET
   @Path("{stackName}/versions/{stackVersion}/operating_systems/{osType}/repositories")
   @Produces("text/plain")
@@ -132,6 +131,30 @@ public class StacksService extends BaseService {
     return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.PUT,
         createRepositoryResource(stackName, stackVersion, osType, repoId));
   }
+  
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/configurations")
+  @Produces("text/plain")
+  public Response getStackLevelConfigurations(String body, @Context HttpHeaders headers,
+                                   @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                   @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.GET,
+        createStackLevelConfigurationsResource(stackName, stackVersion, null));
+  }
+  
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/configurations/{propertyName}")
+  @Produces("text/plain")
+  public Response getStackLevelConfiguration(String body, @Context HttpHeaders headers,
+                                        @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                        @PathParam("stackVersion") String stackVersion,
+                                        @PathParam("serviceName") String serviceName,
+                                        @PathParam("propertyName") String propertyName) {
+
+    return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.GET,
+        createStackLevelConfigurationsResource(stackName, stackVersion, propertyName));
+  }
 
 
   @GET
@@ -343,6 +366,16 @@ public class StacksService extends BaseService {
 
     return createResource(Resource.Type.StackVersion, mapIds);
   }
+  
+  ResourceInstance createStackLevelConfigurationsResource(String stackName,
+      String stackVersion, String propertyName) {
+    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.StackLevelConfiguration, propertyName);
+
+    return createResource(Resource.Type.StackLevelConfiguration, mapIds);
+  }
 
   ResourceInstance createStackResource(String stackName) {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
index fb3ddc9..c4dd022 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
@@ -130,6 +130,15 @@ public class StackExtensionHelper {
     stackParentsMap = getParentStacksInOrder(stackVersionMap.values());
   }
 
+  void mergeStacks(StackInfo parentStack,
+      StackInfo resultStack) {
+    if(parentStack.getConfigTypes() != null) {
+      resultStack.getConfigTypes().putAll(parentStack.getConfigTypes());
+    }
+    List<PropertyInfo> mergedProperties = new ArrayList<PropertyInfo>();
+    mergeProperties(resultStack.getProperties(), parentStack.getProperties(), mergedProperties);
+    resultStack.setProperties(mergedProperties);
+  }
 
   ServiceInfo mergeServices(ServiceInfo parentService,
                                     ServiceInfo childService) {
@@ -218,12 +227,28 @@ public class StackExtensionHelper {
 
     populateComponents(mergedServiceInfo, parentService, childService);
 
+    mergeProperties(childService.getProperties(), parentService.getProperties(), mergedServiceInfo.getProperties());
+
+    // Add all parent config dependencies
+    if (parentService.getConfigDependencies() != null && !parentService
+        .getConfigDependencies().isEmpty()) {
+      for (String configDep : parentService.getConfigDependencies()) {
+        if (!mergedServiceInfo.getConfigDependencies().contains(configDep)) {
+          mergedServiceInfo.getConfigDependencies().add(configDep);
+        }
+      }
+    }
+    return mergedServiceInfo;
+  }
+  
+  public void mergeProperties(List<PropertyInfo> childProperties, 
+      List<PropertyInfo> parentProperties, List<PropertyInfo> mergedProperties) {
     // Add child properties not deleted
     Map<String, Set<String>> deleteMap = new HashMap<String, Set<String>>();
     Map<String, Set<String>> appendMap = new HashMap<String, Set<String>>();
-    for (PropertyInfo propertyInfo : childService.getProperties()) {
+    for (PropertyInfo propertyInfo : childProperties) {
       if (!propertyInfo.isDeleted()) {
-        mergedServiceInfo.getProperties().add(propertyInfo);
+        mergedProperties.add(propertyInfo);
         if (appendMap.containsKey(propertyInfo.getName())) {
           appendMap.get(propertyInfo.getName()).add(propertyInfo.getFilename());
         } else {
@@ -242,24 +267,14 @@ public class StackExtensionHelper {
       }
     }
     // Add all parent properties
-    for (PropertyInfo parentPropertyInfo : parentService.getProperties()) {
+    for (PropertyInfo parentPropertyInfo : parentProperties) {
       if (!deleteMap.containsKey(parentPropertyInfo.getName()) && !(appendMap
           .containsKey(parentPropertyInfo.getName())
         && appendMap.get(parentPropertyInfo.getName())
           .contains(parentPropertyInfo.getFilename()))) {
-        mergedServiceInfo.getProperties().add(parentPropertyInfo);
+        mergedProperties.add(parentPropertyInfo);
       }
     }
-    // Add all parent config dependencies
-    if (parentService.getConfigDependencies() != null && !parentService
-        .getConfigDependencies().isEmpty()) {
-      for (String configDep : parentService.getConfigDependencies()) {
-        if (!mergedServiceInfo.getConfigDependencies().contains(configDep)) {
-          mergedServiceInfo.getConfigDependencies().add(configDep);
-        }
-      }
-    }
-    return mergedServiceInfo;
   }
 
 
@@ -418,6 +433,9 @@ public class StackExtensionHelper {
     while(lt.hasPrevious()) {
       StackInfo parentStack = lt.previous();
       List<ServiceInfo> serviceInfoList = parentStack.getServices();
+      
+      mergeStacks(parentStack, stackInfo);
+      
       for (ServiceInfo service : serviceInfoList) {
         ServiceInfo existingService = serviceInfoMap.get(service.getName());
         if (service.isDeleted()) {
@@ -699,6 +717,8 @@ public class StackExtensionHelper {
               File.separator + AmbariMetaInfo.RCO_FILE_NAME;
       if (new File(rcoFileLocation).exists())
         stackInfo.setRcoFileLocation(rcoFileLocation);
+      
+      setStackPropertiesFromConfigs(stackInfo);
     }
 
     try {
@@ -711,6 +731,42 @@ public class StackExtensionHelper {
     }
     return stackInfo;
   }
+  
+  private void populateStackProperties(StackInfo stackInfo, File configFile) throws JAXBException {
+    ConfigurationXml configuration = unmarshal(ConfigurationXml.class, configFile);
+    String fileName = configFile.getName();
+    stackInfo.getProperties().addAll(getProperties(configuration, fileName));
+    int extIndex = fileName.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
+    String configType = fileName.substring(0, extIndex);
+
+    addConfigType(stackInfo.getConfigTypes(), configType);
+    setConfigTypeAttributes(stackInfo.getConfigTypes(), configuration, configType);
+  }
+  
+  /**
+   * Get all properties from all "configs/*.xml" files. See {@see AmbariMetaInfo#SERVICE_CONFIG_FILE_NAME_POSTFIX}
+   */
+  void setStackPropertiesFromConfigs(StackInfo stackInfo) {
+    File configsFolder = new File(stackRoot.getAbsolutePath() + File
+        .separator + stackInfo.getName() + File.separator + stackInfo.getVersion()
+        + File.separator + AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME);
+    
+    if (!configsFolder.exists() || !configsFolder.isDirectory())
+      return;
+    
+    File[] configFiles = configsFolder.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+    if (configFiles != null) {
+      for (File configFile : configFiles) {
+        if (configFile.getName().endsWith(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX)) {
+          try {
+            populateStackProperties(stackInfo, configFile);
+          } catch (Exception e) {
+            LOG.error("Could not load configuration for " + configFile, e);
+          }
+        }
+      }
+    }
+  }
 
   private List<PropertyInfo> getProperties(ConfigurationXml configuration, String fileName) {
     List<PropertyInfo> list = new ArrayList<PropertyInfo>();
@@ -730,33 +786,27 @@ public class StackExtensionHelper {
     serviceInfo.getProperties().addAll(getProperties(configuration, fileName));
     int extIndex = fileName.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
     String configType = fileName.substring(0, extIndex);
-   
-    addConfigType(serviceInfo, configType);
-    setConfigTypeAttributes(serviceInfo, configuration, configType);
+
+    addConfigType(serviceInfo.getConfigTypes(), configType);
+    setConfigTypeAttributes(serviceInfo.getConfigTypes(), configuration, configType);
   }
   
-  void setConfigTypeAttributes(ServiceInfo serviceInfo, ConfigurationXml configuration, String configType) {
+  void setConfigTypeAttributes(Map<String, Map<String, Map<String, String>>> configTypes, ConfigurationXml configuration, String configType) {
     for (Map.Entry<QName, String> attribute : configuration.getAttributes().entrySet()) {
       for (Supports supportsProperty : Supports.values()) {
         String attributeName = attribute.getKey().getLocalPart();
         String attributeValue = attribute.getValue();
         if (attributeName.equals(supportsProperty.getXmlAttributeName())) {
-          addConfigTypeProperty(serviceInfo, configType, Supports.KEYWORD,
+          addConfigTypeProperty(configTypes, configType, Supports.KEYWORD,
               supportsProperty.getPropertyName(), Boolean.valueOf(attributeValue).toString());
         }
       }
     }
   }
   
-  void addConfigType(ServiceInfo serviceInfo, String configType) {
-    if(serviceInfo.getConfigTypes() == null) {
-      serviceInfo.setConfigTypes(new HashMap<String, Map<String, Map<String, String>>>());
-    }
-    
-    Map<String, Map<String, Map<String, String>>> configTypes = serviceInfo.getConfigTypes();
+  void addConfigType(Map<String, Map<String, Map<String, String>>> configTypes, String configType) {
     configTypes.put(configType, new HashMap<String, Map<String, String>>());
     
-    
     Map<String, Map<String, String>> properties = configTypes.get(configType);
     Map<String, String> supportsProperties = new HashMap<String, String>();
     for (Supports supportsProperty : Supports.values()) {
@@ -793,9 +843,8 @@ public class StackExtensionHelper {
   /**
    * Put new property entry to ServiceInfo#configTypes collection for specified configType
    */
-  void addConfigTypeProperty(ServiceInfo serviceInfo, String configType,
+  void addConfigTypeProperty(Map<String, Map<String, Map<String, String>>> configTypes, String configType,
       String propertiesGroupName, String key, String value) {
-   Map<String, Map<String, Map<String, String>>> configTypes = serviceInfo.getConfigTypes();
    if (configTypes != null && configTypes.containsKey(configType)) {
       Map<String, Map<String, String>> configDependencyProperties = configTypes.get(configType);
       if (!configDependencyProperties.containsKey(propertiesGroupName)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index bee118e..1a5d933 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -712,5 +712,13 @@ public interface AmbariManagementController {
    * @throws AmbariException if synchronization data was invalid
    */
   public void synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups) throws AmbariException;
+
+  /**
+   * Get configurations which are specific for a cluster (!not a service).
+   * @param requests
+   * @return
+   * @throws AmbariException
+   */
+  public Set<StackConfigurationResponse> getStackLevelConfigurations(Set<StackLevelConfigurationRequest> requests) throws AmbariException;
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index c6b2f9f..cc122f6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -3286,6 +3286,50 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     }
     return response;
   }
+  
+  @Override
+  public Set<StackConfigurationResponse> getStackLevelConfigurations(
+      Set<StackLevelConfigurationRequest> requests) throws AmbariException {
+    Set<StackConfigurationResponse> response = new HashSet<StackConfigurationResponse>();
+    for (StackLevelConfigurationRequest request : requests) {
+
+      String stackName    = request.getStackName();
+      String stackVersion = request.getStackVersion();
+      
+      Set<StackConfigurationResponse> stackConfigurations = getStackLevelConfigurations(request);
+
+      for (StackConfigurationResponse stackConfigurationResponse : stackConfigurations) {
+        stackConfigurationResponse.setStackName(stackName);
+        stackConfigurationResponse.setStackVersion(stackVersion);
+      }
+
+      response.addAll(stackConfigurations);
+    }
+
+    return response;
+  }
+
+  private Set<StackConfigurationResponse> getStackLevelConfigurations(
+      StackLevelConfigurationRequest request) throws AmbariException {
+
+    Set<StackConfigurationResponse> response = new HashSet<StackConfigurationResponse>();
+
+    String stackName = request.getStackName();
+    String stackVersion = request.getStackVersion();
+    String propertyName = request.getPropertyName();
+
+    Set<PropertyInfo> properties;
+    if (propertyName != null) {
+      properties = ambariMetaInfo.getStackPropertiesByName(stackName, stackVersion, propertyName);
+    } else {
+      properties = ambariMetaInfo.getStackProperties(stackName, stackVersion);
+    }
+    for (PropertyInfo property: properties) {
+      response.add(property.convertToResponse());
+    }
+
+    return response;
+  }
 
   @Override
   public Set<StackConfigurationResponse> getStackConfigurations(

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
new file mode 100644
index 0000000..dcace09
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+public class StackLevelConfigurationRequest extends StackVersionRequest {
+
+  private String propertyName;
+
+  public StackLevelConfigurationRequest(String stackName, String stackVersion,
+      String propertyName) {
+    super(stackName, stackVersion);
+    
+    setPropertyName(propertyName);
+
+  }
+
+  public String getPropertyName() {
+    return propertyName;
+  }
+
+  public void setPropertyName(String propertyName) {
+    this.propertyName = propertyName;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
new file mode 100644
index 0000000..7229197
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
@@ -0,0 +1,37 @@
+/**
+ * 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;
+
+
+import java.util.Map;
+
+public class StackLevelConfigurationResponse extends StackConfigurationResponse {
+  public StackLevelConfigurationResponse(String propertyName,
+      String propertyValue, String propertyDescription, String type,
+      Boolean isRequired, String propertyType,
+      Map<String, String> propertyAttributes) {
+    super(propertyName, propertyValue, propertyDescription, type, isRequired,
+        propertyType, propertyAttributes);
+  }
+  
+  public StackLevelConfigurationResponse(String propertyName, String propertyValue, String propertyDescription,
+      String type, Map<String, String> propertyAttributes) {
+    super(propertyName, propertyValue, propertyDescription, type, propertyAttributes);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java
index 84105fc..a338a12 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java
@@ -18,6 +18,8 @@
 
 package org.apache.ambari.server.controller;
 
+import java.util.Map;
+
 
 public class StackVersionResponse {
 
@@ -26,13 +28,16 @@ public class StackVersionResponse {
   private String minUpgradeVersion;
   private boolean active;
   private String parentVersion;
+  private Map<String, Map<String, Map<String, String>>> configTypes;
 
   public StackVersionResponse(String stackVersion, String minUpgradeVersion,
-                              boolean active, String parentVersion) {
+                              boolean active, String parentVersion, 
+                              Map<String, Map<String, Map<String, String>>> configTypes) {
     setStackVersion(stackVersion);
     setMinUpgradeVersion(minUpgradeVersion);
     setActive(active);
     setParentVersion(parentVersion);
+    setConfigTypes(configTypes);
   }
 
   public String getStackName() {
@@ -74,4 +79,11 @@ public class StackVersionResponse {
   public void setParentVersion(String parentVersion) {
     this.parentVersion = parentVersion;
   }
+  public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
+    return configTypes;
+  }
+  public void setConfigTypes(
+      Map<String, Map<String, Map<String, String>>> configTypes) {
+    this.configTypes = configTypes;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 71ddc8d..2fa38c5 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
@@ -127,6 +127,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new StackConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case OperatingSystem:
         return new OperatingSystemResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case StackLevelConfiguration:
+        return new StackLevelConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Repository:
         return new RepositoryResourceProvider(propertyIds, keyPropertyIds, managementController);
       case RootService:

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
new file mode 100644
index 0000000..116f589
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
@@ -0,0 +1,159 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.ambari.server.controller.internal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.StackConfigurationResponse;
+import org.apache.ambari.server.controller.StackLevelConfigurationRequest;
+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.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+public class StackLevelConfigurationResourceProvider extends
+    ReadOnlyResourceProvider {
+
+  public static final String STACK_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "stack_name");
+
+  public static final String STACK_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "stack_version");
+
+  public static final String PROPERTY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "property_name");
+
+  public static final String PROPERTY_VALUE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "property_value");
+
+  public static final String PROPERTY_DESCRIPTION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "property_description");
+
+  public static final String PROPERTY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "type");
+
+  public static final String PROPERTY_FINAL_PROPERTY_ID = PropertyHelper
+      .getPropertyId("StackLevelConfigurations", "final");
+
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
+          STACK_VERSION_PROPERTY_ID, PROPERTY_NAME_PROPERTY_ID }));
+
+  protected StackLevelConfigurationResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<StackLevelConfigurationRequest> requests = new HashSet<StackLevelConfigurationRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<StackConfigurationResponse> responses = getResources(new Command<Set<StackConfigurationResponse>>() {
+      @Override
+      public Set<StackConfigurationResponse> invoke() throws AmbariException {
+        return getManagementController().getStackLevelConfigurations(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+    
+    for (StackConfigurationResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.StackLevelConfiguration);
+
+      setResourceProperty(resource, STACK_NAME_PROPERTY_ID,
+          response.getStackName(), requestedIds);
+
+      setResourceProperty(resource, STACK_VERSION_PROPERTY_ID,
+          response.getStackVersion(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_NAME_PROPERTY_ID,
+          response.getPropertyName(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_VALUE_PROPERTY_ID,
+          response.getPropertyValue(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_DESCRIPTION_PROPERTY_ID,
+          response.getPropertyDescription(), requestedIds);
+      
+      setResourceProperty(resource, PROPERTY_TYPE_PROPERTY_ID,
+          response.getType(), requestedIds);
+
+      setDefaultPropertiesAttributes(resource, requestedIds);
+
+      for (Map.Entry<String, String> attribute : response.getPropertyAttributes().entrySet()) {
+        setResourceProperty(resource, PropertyHelper.getPropertyId("StackLevelConfigurations", attribute.getKey()),
+            attribute.getValue(), requestedIds);
+      }
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  /**
+   * Set default values for properties attributes before applying original ones
+   * to prevent absence in case of empty attributes map
+   */
+  private void setDefaultPropertiesAttributes(Resource resource, Set<String> requestedIds) {
+    setResourceProperty(resource, PROPERTY_FINAL_PROPERTY_ID,
+        "false", requestedIds);
+  }
+
+  private StackLevelConfigurationRequest getRequest(Map<String, Object> properties) {
+    return new StackLevelConfigurationRequest(
+        (String) properties.get(STACK_NAME_PROPERTY_ID),
+        (String) properties.get(STACK_VERSION_PROPERTY_ID),
+        (String) properties.get(PROPERTY_NAME_PROPERTY_ID));
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
index 9cef695..1442a0c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
@@ -58,6 +58,9 @@ public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
 
   private static final String STACK_ACTIVE_PROPERTY_ID = PropertyHelper
       .getPropertyId("Versions", "active");
+  
+  private static final String STACK_CONFIG_TYPES = PropertyHelper
+      .getPropertyId("Versions", "config_types");
 
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
@@ -109,6 +112,9 @@ public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
 
       setResourceProperty(resource, STACK_PARENT_PROPERTY_ID,
         response.getParentVersion(), requestedIds);
+      
+      setResourceProperty(resource, STACK_CONFIG_TYPES,
+          response.getConfigTypes(), requestedIds);
 
       resources.add(resource);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 b10b4bc..a14f1f0 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
@@ -120,7 +120,8 @@ public interface Resource {
     ViewPrivilege,
     ViewPermission,
     Controller,
-    ClientConfig;
+    ClientConfig,
+    StackLevelConfiguration;
 
     /**
      * Get the {@link Type} that corresponds to this InternalType.
@@ -202,6 +203,7 @@ public interface Resource {
     public static final Type ViewPermission = InternalType.ViewPermission.getType();
     public static final Type Controller = InternalType.Controller.getType();
     public static final Type ClientConfig = InternalType.ClientConfig.getType();
+    public static final Type StackLevelConfiguration = InternalType.StackLevelConfiguration.getType();
 
     /**
      * The type name.

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/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 de70620..ae746d6 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
@@ -259,6 +259,7 @@ public class ServiceInfo {
   }
   
   public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
+    if (configTypes == null) configTypes = new HashMap<String, Map<String, Map<String, String>>>();
     return configTypes;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index cc1a45e..242cfcc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -19,7 +19,9 @@
 package org.apache.ambari.server.state;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.ambari.server.controller.StackVersionResponse;
 
@@ -32,6 +34,9 @@ public class StackInfo implements Comparable<StackInfo>{
   private List<RepositoryInfo> repositories;
   private List<ServiceInfo> services;
   private String parentStackVersion;
+  // stack-level properties
+  private List<PropertyInfo> properties;
+  private Map<String, Map<String, Map<String, String>>> configTypes;
 
   /**
    * Meaning: stores subpath from stack root to exact hooks folder for stack. These hooks are
@@ -72,6 +77,25 @@ public class StackInfo implements Comparable<StackInfo>{
   public synchronized void setServices(List<ServiceInfo> services) {
     this.services = services;
   }
+  
+  public List<PropertyInfo> getProperties() {
+    if (properties == null) properties = new ArrayList<PropertyInfo>();
+    return properties;
+  }
+
+  public void setProperties(List<PropertyInfo> properties) {
+    this.properties = properties;
+  }
+  
+  public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
+    if (configTypes == null) configTypes = new HashMap<String, Map<String, Map<String, String>>>();
+    return configTypes;
+  }
+
+  public void setConfigTypes(
+      Map<String, Map<String, Map<String, String>>> configTypes) {
+    this.configTypes = configTypes;
+  }
 
   @Override
   public String toString() {
@@ -117,7 +141,7 @@ public class StackInfo implements Comparable<StackInfo>{
   public StackVersionResponse convertToResponse() {
 
     return new StackVersionResponse(getVersion(), getMinUpgradeVersion(),
-      isActive(), getParentStackVersion());
+      isActive(), getParentStackVersion(), getConfigTypes());
   }
 
   public String getMinUpgradeVersion() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 06ebb61..ef698c5 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -157,5 +157,10 @@
     "Service": "ServiceComponentInfo/service_name",
     "Component": "ServiceComponentInfo/component_name",
     "Host": "HostRoles/host_name"
+  },
+  "StackLevelConfiguration": {
+    "Stack": "StackLevelConfigurations/stack_name",
+    "StackVersion": "StackLevelConfigurations/stack_version",
+    "StackLevelConfiguration": "StackLevelConfigurations/property_name"  
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 785bd24..741ffe6 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -202,6 +202,7 @@
         "Versions/min_upgrade_version",
         "Versions/active",
         "Versions/parent_stack_version",
+        "Versions/config_types",
         "_"
     ],
     "OperatingSystem":[
@@ -444,5 +445,15 @@
         "ServiceComponentInfo/cluster_name",
         "HostRoles/host_name",
         "_"
+    ],
+    "StackLevelConfiguration":[
+        "StackLevelConfigurations/stack_name",
+        "StackLevelConfigurations/stack_version",
+        "StackLevelConfigurations/property_name",
+        "StackLevelConfigurations/property_value",
+        "StackLevelConfigurations/property_description",
+        "StackLevelConfigurations/type",
+        "StackLevelConfigurations/final",
+        "_"
     ]
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/resources/stacks/HDP/1.3.2/configuration/cluster-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3.2/configuration/cluster-env.xml b/ambari-server/src/main/resources/stacks/HDP/1.3.2/configuration/cluster-env.xml
new file mode 100644
index 0000000..a2df35a
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3.2/configuration/cluster-env.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+/**
+ * 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.
+ */
+-->
+
+<configuration>
+    <property>
+        <name>security_enabled</name>
+        <value>false</value>
+        <description>Hadoop Security</description>
+    </property>
+    <property>
+        <name>kerberos_domain</name>
+        <value>EXAMPLE.COM</value>
+        <description>Kerberos realm.</description>
+    </property>
+    <property>
+        <name>ignore_groupsusers_create</name>
+        <value>false</value>
+        <description>Whether to ignore failures on users and group creation</description>
+    </property>
+    <property>
+        <name>smokeuser</name>
+        <value>ambari-qa</value>
+        <description>User executing service checks</description>
+    </property>
+    <property>
+        <name>user_group</name>
+        <value>hadoop</value>
+        <description>Hadoop user group.</description>
+    </property>
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
new file mode 100644
index 0000000..a2df35a
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+/**
+ * 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.
+ */
+-->
+
+<configuration>
+    <property>
+        <name>security_enabled</name>
+        <value>false</value>
+        <description>Hadoop Security</description>
+    </property>
+    <property>
+        <name>kerberos_domain</name>
+        <value>EXAMPLE.COM</value>
+        <description>Kerberos realm.</description>
+    </property>
+    <property>
+        <name>ignore_groupsusers_create</name>
+        <value>false</value>
+        <description>Whether to ignore failures on users and group creation</description>
+    </property>
+    <property>
+        <name>smokeuser</name>
+        <value>ambari-qa</value>
+        <description>User executing service checks</description>
+    </property>
+    <property>
+        <name>user_group</name>
+        <value>hadoop</value>
+        <description>Hadoop user group.</description>
+    </property>
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
index 5596a1e..e5a184b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
@@ -272,7 +272,7 @@ public class QueryImplTest {
     Assert.assertEquals("StackVersion:1", versionNode.getName());
     Assert.assertEquals(Resource.Type.StackVersion, versionNode.getObject().getType());
 
-    Assert.assertEquals(2, versionNode.getChildren().size());
+    Assert.assertEquals(3, versionNode.getChildren().size());
     TreeNode<Resource> opSystemsNode = versionNode.getChild("operatingSystems");
     Assert.assertEquals(3, opSystemsNode.getChildren().size());
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java
index 3a62147..c7af864 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java
@@ -364,7 +364,7 @@ public class StackExtensionHelperTest {
     replay(serviceInfo);
 
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
     // verification
     verify(serviceInfo);
@@ -382,7 +382,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
 
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
     // assert
     configTypes = serviceInfo.getConfigTypes();
@@ -408,7 +408,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
 
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "no_such_dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "no_such_dep", "group", "key", "value");
 
     // assert
     configTypes = serviceInfo.getConfigTypes();
@@ -433,7 +433,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
 
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
     // assert
     configTypes = serviceInfo.getConfigTypes();
@@ -522,18 +522,14 @@ public class StackExtensionHelperTest {
     // expectations
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getProperties()).andReturn(properties).times(1);
-    expect(properties.addAll((Collection) anyObject())).andReturn(true).times(1);
-    helper.addConfigTypeProperty(serviceInfo, "yarn-site", StackExtensionHelper.Supports.KEYWORD,
-        StackExtensionHelper.Supports.FINAL.getPropertyName(), "false");
-    replay(properties);
-    replay(serviceInfo);
-    replay(helper);
+    expect(properties.addAll((Collection) anyObject())).andReturn(true).times(1);    
+    replay(properties, serviceInfo);
 
     // eval
     helper.populateServiceProperties(config, serviceInfo);
 
     // verification
-    verify(properties, serviceInfo, helper);
+    verify(properties, serviceInfo);
   }
 
   @Test
@@ -543,14 +539,13 @@ public class StackExtensionHelperTest {
     StackExtensionHelper helper = new StackExtensionHelper(injector, stackRoot);
     File config = new File(stackRootStr
         + "HDP/2.1.1/services/PIG/configuration/pig-properties.xml".replaceAll("/", File.separator));
-    ServiceInfo serviceInfo = createMock(ServiceInfo.class);
-    List<PropertyInfo> properties = createNiceMock(List.class);
+    ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class);
+    List<PropertyInfo> properties = createMock(List.class);
 
     // expectations
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getProperties()).andReturn(properties).times(1);
     expect(properties.addAll((Collection) anyObject())).andReturn(true).times(1);
-    expect(serviceInfo.getConfigTypes()).andReturn(null).times(1);
     replay(properties);
     replay(serviceInfo);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
index c1f4f5b..2187145 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
@@ -39,6 +39,7 @@ import org.apache.ambari.server.controller.MemberRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.StackConfigurationRequest;
+import org.apache.ambari.server.controller.StackLevelConfigurationRequest;
 import org.apache.ambari.server.controller.TaskStatusRequest;
 import org.apache.ambari.server.controller.UserRequest;
 import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
@@ -362,6 +363,13 @@ public class AbstractResourceProviderTest {
       EasyMock.reportMatcher(new StackConfigurationRequestSetMatcher(stackName, stackVersion, serviceName, propertyName));
       return null;
     }
+    
+    public static Set<StackLevelConfigurationRequest> getStackLevelConfigurationRequestSet(String stackName, String stackVersion,
+        String propertyName)
+    {
+      EasyMock.reportMatcher(new StackLevelConfigurationRequestSetMatcher(stackName, stackVersion, propertyName));
+      return null;
+    }
   }
 
   /**
@@ -721,6 +729,43 @@ public class AbstractResourceProviderTest {
       stringBuffer.append("StackConfigurationRequestSetMatcher(").append(stackConfigurationRequest).append(")");
     }
   }
+  
+  public static class StackLevelConfigurationRequestSetMatcher extends HashSet<StackLevelConfigurationRequest> implements IArgumentMatcher {
+
+    private final StackLevelConfigurationRequest stackLevelConfigurationRequest;
+
+    public StackLevelConfigurationRequestSetMatcher(String stackName, String stackVersion,
+        String propertyName) {
+      this.stackLevelConfigurationRequest = new StackLevelConfigurationRequest(stackName, stackVersion, propertyName);
+      add(this.stackLevelConfigurationRequest);
+    }
+
+    @Override
+    public boolean matches(Object o) {
+
+      if (!(o instanceof Set)) {
+        return false;
+      }
+
+      Set set = (Set) o;
+
+      if (set.size() != 1) {
+        return false;
+      }
+
+      Object request = set.iterator().next();
+
+      return request instanceof StackLevelConfigurationRequest &&
+          eq(((StackLevelConfigurationRequest) request).getPropertyName(), stackLevelConfigurationRequest.getPropertyName()) &&
+          eq(((StackLevelConfigurationRequest) request).getStackName(), stackLevelConfigurationRequest.getStackName()) &&
+          eq(((StackLevelConfigurationRequest) request).getStackVersion(), stackLevelConfigurationRequest.getStackVersion());
+    }
+
+    @Override
+    public void appendTo(StringBuffer stringBuffer) {
+      stringBuffer.append("StackLevelConfigurationRequestSetMatcher(").append(stackLevelConfigurationRequest).append(")");
+    }
+  }
 
   /**
    * A test observer that records the last event.

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bd0394a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProviderTest.java
new file mode 100644
index 0000000..99d4423
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProviderTest.java
@@ -0,0 +1,181 @@
+/**
+ * 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 static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.StackConfigurationResponse;
+import org.apache.ambari.server.controller.StackLevelConfigurationResponse;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StackLevelConfigurationResourceProviderTest {
+  
+  private static final String PROPERTY_NAME = "name";
+  private static final String PROPERTY_VALUE = "value";
+  private static final String PROPERTY_DESC = "Desc";
+  private static final String TYPE = "type.xml";
+
+  @Test
+  public void testGetResources() throws Exception{
+       
+    Map<String, String> attributes = new HashMap<String, String>();
+    attributes.put("final", "true");
+
+    Resource.Type type = Resource.Type.StackLevelConfiguration;
+
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
+    Set<StackConfigurationResponse> allResponse = new HashSet<StackConfigurationResponse>();
+    
+    allResponse.add(new StackConfigurationResponse(PROPERTY_NAME, PROPERTY_VALUE, PROPERTY_DESC, TYPE, attributes));
+   
+    // set expectations
+    expect(managementController.getStackLevelConfigurations(
+        AbstractResourceProviderTest.Matcher.getStackLevelConfigurationRequestSet(null, null, null))).
+        andReturn(allResponse).times(1);
+    // replay
+    replay(managementController);
+
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+        type,
+        PropertyHelper.getPropertyIds(type),
+        PropertyHelper.getKeyPropertyIds(type),
+        managementController);
+
+    Set<String> propertyIds = new HashSet<String>();
+
+    propertyIds.add(StackLevelConfigurationResourceProvider.STACK_NAME_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.STACK_VERSION_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_NAME_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_VALUE_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_DESCRIPTION_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_TYPE_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_FINAL_PROPERTY_ID);
+
+    // create the request
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    // get all ... no predicate
+    Set<Resource> resources = provider.getResources(request, null);
+
+    Assert.assertEquals(allResponse.size(), resources.size());
+    
+    for (Resource resource : resources) {   
+      String propertyName = (String) resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_NAME_PROPERTY_ID);
+      String propertyValue = (String) resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_VALUE_PROPERTY_ID);
+      String propertyDesc = (String) 
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_DESCRIPTION_PROPERTY_ID);
+      String propertyType = (String) 
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_TYPE_PROPERTY_ID);
+      String propertyIsFinal = (String)
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_FINAL_PROPERTY_ID);
+      
+      Assert.assertEquals(PROPERTY_NAME, propertyName);
+      Assert.assertEquals(PROPERTY_VALUE, propertyValue);
+      Assert.assertEquals(PROPERTY_DESC, propertyDesc);
+      Assert.assertEquals(TYPE, propertyType);
+      Assert.assertEquals("true", propertyIsFinal);
+
+    }
+
+    // verify
+    verify(managementController);
+  }
+
+  @Test
+  public void testGetResources_noFinal() throws Exception{
+
+    Map<String, String> attributes = new HashMap<String, String>();
+
+    Resource.Type type = Resource.Type.StackLevelConfiguration;
+
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
+    Set<StackConfigurationResponse> allResponse = new HashSet<StackConfigurationResponse>();
+
+    allResponse.add(new StackConfigurationResponse(PROPERTY_NAME, PROPERTY_VALUE, PROPERTY_DESC, TYPE, attributes));
+
+    // set expectations
+    expect(managementController.getStackLevelConfigurations(
+        AbstractResourceProviderTest.Matcher.getStackLevelConfigurationRequestSet(null, null, null))).
+        andReturn(allResponse).times(1);
+    // replay
+    replay(managementController);
+
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+        type,
+        PropertyHelper.getPropertyIds(type),
+        PropertyHelper.getKeyPropertyIds(type),
+        managementController);
+
+    Set<String> propertyIds = new HashSet<String>();
+
+    propertyIds.add(StackLevelConfigurationResourceProvider.STACK_NAME_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.STACK_VERSION_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_NAME_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_VALUE_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_DESCRIPTION_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_TYPE_PROPERTY_ID);
+    propertyIds.add(StackLevelConfigurationResourceProvider.PROPERTY_FINAL_PROPERTY_ID);
+
+    // create the request
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    // get all ... no predicate
+    Set<Resource> resources = provider.getResources(request, null);
+
+    Assert.assertEquals(allResponse.size(), resources.size());
+
+    for (Resource resource : resources) {
+      String propertyName = (String) resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_NAME_PROPERTY_ID);
+      String propertyValue = (String) resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_VALUE_PROPERTY_ID);
+      String propertyDesc = (String)
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_DESCRIPTION_PROPERTY_ID);
+      String propertyType = (String)
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_TYPE_PROPERTY_ID);
+      String propertyIsFinal = (String)
+          resource.getPropertyValue(StackLevelConfigurationResourceProvider.PROPERTY_FINAL_PROPERTY_ID);
+
+      Assert.assertEquals(PROPERTY_NAME, propertyName);
+      Assert.assertEquals(PROPERTY_VALUE, propertyValue);
+      Assert.assertEquals(PROPERTY_DESC, propertyDesc);
+      Assert.assertEquals(TYPE, propertyType);
+      Assert.assertEquals("false", propertyIsFinal);
+
+    }
+
+    // verify
+    verify(managementController);
+  } 
+
+}