Browse Source

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

Andrew Onishuk 11 năm trước cách đây
mục cha
commit
6bd0394a5f
26 tập tin đã thay đổi với 892 bổ sung49 xóa
  1. 0 1
      ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
  2. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
  3. 53 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackLevelConfigurationResourceDefinition.java
  4. 1 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackVersionResourceDefinition.java
  5. 33 1
      ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
  6. 34 1
      ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
  7. 77 28
      ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
  8. 8 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
  9. 44 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
  10. 42 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
  11. 37 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
  12. 13 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java
  13. 2 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
  14. 159 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
  15. 6 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
  16. 3 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
  17. 1 0
      ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
  18. 25 1
      ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
  19. 5 0
      ambari-server/src/main/resources/key_properties.json
  20. 11 0
      ambari-server/src/main/resources/properties.json
  21. 49 0
      ambari-server/src/main/resources/stacks/HDP/1.3.2/configuration/cluster-env.xml
  22. 49 0
      ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
  23. 1 1
      ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
  24. 9 14
      ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java
  25. 45 0
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
  26. 181 0
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProviderTest.java

+ 0 - 1
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);
         mapTemporalInfo.put(propertyId, globalTemporalInfo);
       }
       }
     }
     }
-
     return PropertyHelper.getReadRequest(setProperties, requestInfoProperties, mapTemporalInfo);
     return PropertyHelper.getReadRequest(setProperties, requestInfoProperties, mapTemporalInfo);
   }
   }
 
 

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java

@@ -141,6 +141,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
       case StackVersion:
       case StackVersion:
         resourceDefinition = new StackVersionResourceDefinition();
         resourceDefinition = new StackVersionResourceDefinition();
         break;
         break;
+        
+      case StackLevelConfiguration:
+        resourceDefinition = new StackLevelConfigurationResourceDefinition();
+        break;
 
 
       case StackService:
       case StackService:
         resourceDefinition = new StackServiceResourceDefinition();
         resourceDefinition = new StackServiceResourceDefinition();

+ 53 - 0
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;
+  }
+  */
+}

+ 1 - 0
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.OperatingSystem));
     setChildren.add(new SubResourceDefinition(Resource.Type.StackService));
     setChildren.add(new SubResourceDefinition(Resource.Type.StackService));
+    setChildren.add(new SubResourceDefinition(Resource.Type.StackLevelConfiguration));
 
 
     return setChildren;
     return setChildren;
 
 

+ 33 - 1
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)
   public Set<PropertyInfo> getProperties(String stackName, String version, String serviceName)
       throws AmbariException {
       throws AmbariException {
-
     ServiceInfo serviceInfo = getServiceInfo(stackName, version, serviceName);
     ServiceInfo serviceInfo = getServiceInfo(stackName, version, serviceName);
     List<PropertyInfo> properties = serviceInfo.getProperties();
     List<PropertyInfo> properties = serviceInfo.getProperties();
     Set<PropertyInfo> propertiesResult = new HashSet<PropertyInfo>(properties);
     Set<PropertyInfo> propertiesResult = new HashSet<PropertyInfo>(properties);
 
 
     return propertiesResult;
     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)
   public Set<PropertyInfo> getPropertiesByName(String stackName, String version, String serviceName, String propertyName)
       throws AmbariException {
       throws AmbariException {
@@ -698,6 +706,30 @@ public class AmbariMetaInfo {
 
 
     return propertyResult;
     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;
+  }
 
 
 
 
   /**
   /**

+ 34 - 1
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));
         createStackVersionResource(stackName, stackVersion));
   }
   }
 
 
-
   @GET
   @GET
   @Path("{stackName}/versions/{stackVersion}/operating_systems/{osType}/repositories")
   @Path("{stackName}/versions/{stackVersion}/operating_systems/{osType}/repositories")
   @Produces("text/plain")
   @Produces("text/plain")
@@ -132,6 +131,30 @@ public class StacksService extends BaseService {
     return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.PUT,
     return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.PUT,
         createRepositoryResource(stackName, stackVersion, osType, repoId));
         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
   @GET
@@ -343,6 +366,16 @@ public class StacksService extends BaseService {
 
 
     return createResource(Resource.Type.StackVersion, mapIds);
     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) {
   ResourceInstance createStackResource(String stackName) {
 
 

+ 77 - 28
ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java

@@ -130,6 +130,15 @@ public class StackExtensionHelper {
     stackParentsMap = getParentStacksInOrder(stackVersionMap.values());
     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 mergeServices(ServiceInfo parentService,
                                     ServiceInfo childService) {
                                     ServiceInfo childService) {
@@ -218,12 +227,28 @@ public class StackExtensionHelper {
 
 
     populateComponents(mergedServiceInfo, parentService, childService);
     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
     // Add child properties not deleted
     Map<String, Set<String>> deleteMap = new HashMap<String, Set<String>>();
     Map<String, Set<String>> deleteMap = new HashMap<String, Set<String>>();
     Map<String, Set<String>> appendMap = 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()) {
       if (!propertyInfo.isDeleted()) {
-        mergedServiceInfo.getProperties().add(propertyInfo);
+        mergedProperties.add(propertyInfo);
         if (appendMap.containsKey(propertyInfo.getName())) {
         if (appendMap.containsKey(propertyInfo.getName())) {
           appendMap.get(propertyInfo.getName()).add(propertyInfo.getFilename());
           appendMap.get(propertyInfo.getName()).add(propertyInfo.getFilename());
         } else {
         } else {
@@ -242,24 +267,14 @@ public class StackExtensionHelper {
       }
       }
     }
     }
     // Add all parent properties
     // Add all parent properties
-    for (PropertyInfo parentPropertyInfo : parentService.getProperties()) {
+    for (PropertyInfo parentPropertyInfo : parentProperties) {
       if (!deleteMap.containsKey(parentPropertyInfo.getName()) && !(appendMap
       if (!deleteMap.containsKey(parentPropertyInfo.getName()) && !(appendMap
           .containsKey(parentPropertyInfo.getName())
           .containsKey(parentPropertyInfo.getName())
         && appendMap.get(parentPropertyInfo.getName())
         && appendMap.get(parentPropertyInfo.getName())
           .contains(parentPropertyInfo.getFilename()))) {
           .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()) {
     while(lt.hasPrevious()) {
       StackInfo parentStack = lt.previous();
       StackInfo parentStack = lt.previous();
       List<ServiceInfo> serviceInfoList = parentStack.getServices();
       List<ServiceInfo> serviceInfoList = parentStack.getServices();
+      
+      mergeStacks(parentStack, stackInfo);
+      
       for (ServiceInfo service : serviceInfoList) {
       for (ServiceInfo service : serviceInfoList) {
         ServiceInfo existingService = serviceInfoMap.get(service.getName());
         ServiceInfo existingService = serviceInfoMap.get(service.getName());
         if (service.isDeleted()) {
         if (service.isDeleted()) {
@@ -699,6 +717,8 @@ public class StackExtensionHelper {
               File.separator + AmbariMetaInfo.RCO_FILE_NAME;
               File.separator + AmbariMetaInfo.RCO_FILE_NAME;
       if (new File(rcoFileLocation).exists())
       if (new File(rcoFileLocation).exists())
         stackInfo.setRcoFileLocation(rcoFileLocation);
         stackInfo.setRcoFileLocation(rcoFileLocation);
+      
+      setStackPropertiesFromConfigs(stackInfo);
     }
     }
 
 
     try {
     try {
@@ -711,6 +731,42 @@ public class StackExtensionHelper {
     }
     }
     return stackInfo;
     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) {
   private List<PropertyInfo> getProperties(ConfigurationXml configuration, String fileName) {
     List<PropertyInfo> list = new ArrayList<PropertyInfo>();
     List<PropertyInfo> list = new ArrayList<PropertyInfo>();
@@ -730,33 +786,27 @@ public class StackExtensionHelper {
     serviceInfo.getProperties().addAll(getProperties(configuration, fileName));
     serviceInfo.getProperties().addAll(getProperties(configuration, fileName));
     int extIndex = fileName.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
     int extIndex = fileName.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
     String configType = fileName.substring(0, extIndex);
     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 (Map.Entry<QName, String> attribute : configuration.getAttributes().entrySet()) {
       for (Supports supportsProperty : Supports.values()) {
       for (Supports supportsProperty : Supports.values()) {
         String attributeName = attribute.getKey().getLocalPart();
         String attributeName = attribute.getKey().getLocalPart();
         String attributeValue = attribute.getValue();
         String attributeValue = attribute.getValue();
         if (attributeName.equals(supportsProperty.getXmlAttributeName())) {
         if (attributeName.equals(supportsProperty.getXmlAttributeName())) {
-          addConfigTypeProperty(serviceInfo, configType, Supports.KEYWORD,
+          addConfigTypeProperty(configTypes, configType, Supports.KEYWORD,
               supportsProperty.getPropertyName(), Boolean.valueOf(attributeValue).toString());
               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>>());
     configTypes.put(configType, new HashMap<String, Map<String, String>>());
     
     
-    
     Map<String, Map<String, String>> properties = configTypes.get(configType);
     Map<String, Map<String, String>> properties = configTypes.get(configType);
     Map<String, String> supportsProperties = new HashMap<String, String>();
     Map<String, String> supportsProperties = new HashMap<String, String>();
     for (Supports supportsProperty : Supports.values()) {
     for (Supports supportsProperty : Supports.values()) {
@@ -793,9 +843,8 @@ public class StackExtensionHelper {
   /**
   /**
    * Put new property entry to ServiceInfo#configTypes collection for specified configType
    * 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) {
       String propertiesGroupName, String key, String value) {
-   Map<String, Map<String, Map<String, String>>> configTypes = serviceInfo.getConfigTypes();
    if (configTypes != null && configTypes.containsKey(configType)) {
    if (configTypes != null && configTypes.containsKey(configType)) {
       Map<String, Map<String, String>> configDependencyProperties = configTypes.get(configType);
       Map<String, Map<String, String>> configDependencyProperties = configTypes.get(configType);
       if (!configDependencyProperties.containsKey(propertiesGroupName)) {
       if (!configDependencyProperties.containsKey(propertiesGroupName)) {

+ 8 - 0
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
    * @throws AmbariException if synchronization data was invalid
    */
    */
   public void synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups) throws AmbariException;
   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;
 }
 }
 
 

+ 44 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -3286,6 +3286,50 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     }
     }
     return response;
     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
   @Override
   public Set<StackConfigurationResponse> getStackConfigurations(
   public Set<StackConfigurationResponse> getStackConfigurations(

+ 42 - 0
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;
+  }
+
+}

+ 37 - 0
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);
+  }
+}

+ 13 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/StackVersionResponse.java

@@ -18,6 +18,8 @@
 
 
 package org.apache.ambari.server.controller;
 package org.apache.ambari.server.controller;
 
 
+import java.util.Map;
+
 
 
 public class StackVersionResponse {
 public class StackVersionResponse {
 
 
@@ -26,13 +28,16 @@ public class StackVersionResponse {
   private String minUpgradeVersion;
   private String minUpgradeVersion;
   private boolean active;
   private boolean active;
   private String parentVersion;
   private String parentVersion;
+  private Map<String, Map<String, Map<String, String>>> configTypes;
 
 
   public StackVersionResponse(String stackVersion, String minUpgradeVersion,
   public StackVersionResponse(String stackVersion, String minUpgradeVersion,
-                              boolean active, String parentVersion) {
+                              boolean active, String parentVersion, 
+                              Map<String, Map<String, Map<String, String>>> configTypes) {
     setStackVersion(stackVersion);
     setStackVersion(stackVersion);
     setMinUpgradeVersion(minUpgradeVersion);
     setMinUpgradeVersion(minUpgradeVersion);
     setActive(active);
     setActive(active);
     setParentVersion(parentVersion);
     setParentVersion(parentVersion);
+    setConfigTypes(configTypes);
   }
   }
 
 
   public String getStackName() {
   public String getStackName() {
@@ -74,4 +79,11 @@ public class StackVersionResponse {
   public void setParentVersion(String parentVersion) {
   public void setParentVersion(String parentVersion) {
     this.parentVersion = 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;
+  }
 }
 }

+ 2 - 0
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);
         return new StackConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case OperatingSystem:
       case OperatingSystem:
         return new OperatingSystemResourceProvider(propertyIds, keyPropertyIds, managementController);
         return new OperatingSystemResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case StackLevelConfiguration:
+        return new StackLevelConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Repository:
       case Repository:
         return new RepositoryResourceProvider(propertyIds, keyPropertyIds, managementController);
         return new RepositoryResourceProvider(propertyIds, keyPropertyIds, managementController);
       case RootService:
       case RootService:

+ 159 - 0
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;
+  }
+
+}

+ 6 - 0
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
   private static final String STACK_ACTIVE_PROPERTY_ID = PropertyHelper
       .getPropertyId("Versions", "active");
       .getPropertyId("Versions", "active");
+  
+  private static final String STACK_CONFIG_TYPES = PropertyHelper
+      .getPropertyId("Versions", "config_types");
 
 
   private static Set<String> pkPropertyIds = new HashSet<String>(
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
@@ -109,6 +112,9 @@ public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
 
 
       setResourceProperty(resource, STACK_PARENT_PROPERTY_ID,
       setResourceProperty(resource, STACK_PARENT_PROPERTY_ID,
         response.getParentVersion(), requestedIds);
         response.getParentVersion(), requestedIds);
+      
+      setResourceProperty(resource, STACK_CONFIG_TYPES,
+          response.getConfigTypes(), requestedIds);
 
 
       resources.add(resource);
       resources.add(resource);
     }
     }

+ 3 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java

@@ -120,7 +120,8 @@ public interface Resource {
     ViewPrivilege,
     ViewPrivilege,
     ViewPermission,
     ViewPermission,
     Controller,
     Controller,
-    ClientConfig;
+    ClientConfig,
+    StackLevelConfiguration;
 
 
     /**
     /**
      * Get the {@link Type} that corresponds to this InternalType.
      * 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 ViewPermission = InternalType.ViewPermission.getType();
     public static final Type Controller = InternalType.Controller.getType();
     public static final Type Controller = InternalType.Controller.getType();
     public static final Type ClientConfig = InternalType.ClientConfig.getType();
     public static final Type ClientConfig = InternalType.ClientConfig.getType();
+    public static final Type StackLevelConfiguration = InternalType.StackLevelConfiguration.getType();
 
 
     /**
     /**
      * The type name.
      * The type name.

+ 1 - 0
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() {
   public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
+    if (configTypes == null) configTypes = new HashMap<String, Map<String, Map<String, String>>>();
     return configTypes;
     return configTypes;
   }
   }
 
 

+ 25 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java

@@ -19,7 +19,9 @@
 package org.apache.ambari.server.state;
 package org.apache.ambari.server.state;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 import org.apache.ambari.server.controller.StackVersionResponse;
 import org.apache.ambari.server.controller.StackVersionResponse;
 
 
@@ -32,6 +34,9 @@ public class StackInfo implements Comparable<StackInfo>{
   private List<RepositoryInfo> repositories;
   private List<RepositoryInfo> repositories;
   private List<ServiceInfo> services;
   private List<ServiceInfo> services;
   private String parentStackVersion;
   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
    * 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) {
   public synchronized void setServices(List<ServiceInfo> services) {
     this.services = 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
   @Override
   public String toString() {
   public String toString() {
@@ -117,7 +141,7 @@ public class StackInfo implements Comparable<StackInfo>{
   public StackVersionResponse convertToResponse() {
   public StackVersionResponse convertToResponse() {
 
 
     return new StackVersionResponse(getVersion(), getMinUpgradeVersion(),
     return new StackVersionResponse(getVersion(), getMinUpgradeVersion(),
-      isActive(), getParentStackVersion());
+      isActive(), getParentStackVersion(), getConfigTypes());
   }
   }
 
 
   public String getMinUpgradeVersion() {
   public String getMinUpgradeVersion() {

+ 5 - 0
ambari-server/src/main/resources/key_properties.json

@@ -157,5 +157,10 @@
     "Service": "ServiceComponentInfo/service_name",
     "Service": "ServiceComponentInfo/service_name",
     "Component": "ServiceComponentInfo/component_name",
     "Component": "ServiceComponentInfo/component_name",
     "Host": "HostRoles/host_name"
     "Host": "HostRoles/host_name"
+  },
+  "StackLevelConfiguration": {
+    "Stack": "StackLevelConfigurations/stack_name",
+    "StackVersion": "StackLevelConfigurations/stack_version",
+    "StackLevelConfiguration": "StackLevelConfigurations/property_name"  
   }
   }
 }
 }

+ 11 - 0
ambari-server/src/main/resources/properties.json

@@ -202,6 +202,7 @@
         "Versions/min_upgrade_version",
         "Versions/min_upgrade_version",
         "Versions/active",
         "Versions/active",
         "Versions/parent_stack_version",
         "Versions/parent_stack_version",
+        "Versions/config_types",
         "_"
         "_"
     ],
     ],
     "OperatingSystem":[
     "OperatingSystem":[
@@ -444,5 +445,15 @@
         "ServiceComponentInfo/cluster_name",
         "ServiceComponentInfo/cluster_name",
         "HostRoles/host_name",
         "HostRoles/host_name",
         "_"
         "_"
+    ],
+    "StackLevelConfiguration":[
+        "StackLevelConfigurations/stack_name",
+        "StackLevelConfigurations/stack_version",
+        "StackLevelConfigurations/property_name",
+        "StackLevelConfigurations/property_value",
+        "StackLevelConfigurations/property_description",
+        "StackLevelConfigurations/type",
+        "StackLevelConfigurations/final",
+        "_"
     ]
     ]
 }
 }

+ 49 - 0
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>

+ 49 - 0
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>

+ 1 - 1
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("StackVersion:1", versionNode.getName());
     Assert.assertEquals(Resource.Type.StackVersion, versionNode.getObject().getType());
     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");
     TreeNode<Resource> opSystemsNode = versionNode.getChild("operatingSystems");
     Assert.assertEquals(3, opSystemsNode.getChildren().size());
     Assert.assertEquals(3, opSystemsNode.getChildren().size());
 
 

+ 9 - 14
ambari-server/src/test/java/org/apache/ambari/server/api/util/StackExtensionHelperTest.java

@@ -364,7 +364,7 @@ public class StackExtensionHelperTest {
     replay(serviceInfo);
     replay(serviceInfo);
 
 
     // eval
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
 
     // verification
     // verification
     verify(serviceInfo);
     verify(serviceInfo);
@@ -382,7 +382,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
     serviceInfo.setConfigTypes(configTypes);
 
 
     // eval
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
 
     // assert
     // assert
     configTypes = serviceInfo.getConfigTypes();
     configTypes = serviceInfo.getConfigTypes();
@@ -408,7 +408,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
     serviceInfo.setConfigTypes(configTypes);
 
 
     // eval
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "no_such_dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "no_such_dep", "group", "key", "value");
 
 
     // assert
     // assert
     configTypes = serviceInfo.getConfigTypes();
     configTypes = serviceInfo.getConfigTypes();
@@ -433,7 +433,7 @@ public class StackExtensionHelperTest {
     serviceInfo.setConfigTypes(configTypes);
     serviceInfo.setConfigTypes(configTypes);
 
 
     // eval
     // eval
-    helper.addConfigTypeProperty(serviceInfo, "dep", "group", "key", "value");
+    helper.addConfigTypeProperty(serviceInfo.getConfigTypes(), "dep", "group", "key", "value");
 
 
     // assert
     // assert
     configTypes = serviceInfo.getConfigTypes();
     configTypes = serviceInfo.getConfigTypes();
@@ -522,18 +522,14 @@ public class StackExtensionHelperTest {
     // expectations
     // expectations
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getProperties()).andReturn(properties).times(1);
     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
     // eval
     helper.populateServiceProperties(config, serviceInfo);
     helper.populateServiceProperties(config, serviceInfo);
 
 
     // verification
     // verification
-    verify(properties, serviceInfo, helper);
+    verify(properties, serviceInfo);
   }
   }
 
 
   @Test
   @Test
@@ -543,14 +539,13 @@ public class StackExtensionHelperTest {
     StackExtensionHelper helper = new StackExtensionHelper(injector, stackRoot);
     StackExtensionHelper helper = new StackExtensionHelper(injector, stackRoot);
     File config = new File(stackRootStr
     File config = new File(stackRootStr
         + "HDP/2.1.1/services/PIG/configuration/pig-properties.xml".replaceAll("/", File.separator));
         + "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
     // expectations
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getConfigTypes()).andReturn(new HashMap<String, Map<String, Map<String, String>>>()).times(2);
     expect(serviceInfo.getProperties()).andReturn(properties).times(1);
     expect(serviceInfo.getProperties()).andReturn(properties).times(1);
     expect(properties.addAll((Collection) anyObject())).andReturn(true).times(1);
     expect(properties.addAll((Collection) anyObject())).andReturn(true).times(1);
-    expect(serviceInfo.getConfigTypes()).andReturn(null).times(1);
     replay(properties);
     replay(properties);
     replay(serviceInfo);
     replay(serviceInfo);
 
 

+ 45 - 0
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.RequestStatusResponse;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.StackConfigurationRequest;
 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.TaskStatusRequest;
 import org.apache.ambari.server.controller.UserRequest;
 import org.apache.ambari.server.controller.UserRequest;
 import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
 import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
@@ -362,6 +363,13 @@ public class AbstractResourceProviderTest {
       EasyMock.reportMatcher(new StackConfigurationRequestSetMatcher(stackName, stackVersion, serviceName, propertyName));
       EasyMock.reportMatcher(new StackConfigurationRequestSetMatcher(stackName, stackVersion, serviceName, propertyName));
       return null;
       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(")");
       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.
    * A test observer that records the last event.

+ 181 - 0
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);
+  } 
+
+}