Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714 16913b201 -> adc7060a6


AMBARI-22198. Implement read only API for getting stack level settings.


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: adc7060a6cf6b0e318e6d94ac973dfdc27eeb45f
Parents: 16913b2
Author: Swapan Shridhar <[email protected]>
Authored: Mon Oct 23 16:40:45 2017 -0700
Committer: Swapan Shridhar <[email protected]>
Committed: Thu Nov 2 12:24:39 2017 -0700

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../RootStackSettingsResourceDefinition.java    |  51 ++++++
 .../server/api/services/AmbariMetaInfo.java     |  60 +++++--
 .../api/services/RootClusterSettingService.java |   2 +-
 .../server/api/services/StacksService.java      |  89 ++++++++++
 .../controller/AmbariManagementController.java  |   8 +
 .../AmbariManagementControllerImpl.java         |  44 ++++-
 .../server/controller/ControllerModule.java     |   4 +-
 .../AbstractControllerResourceProvider.java     |   6 +-
 .../RootStackSettingsResourceProvider.java      | 177 +++++++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../ResourceLevelClusterSettingManager.java     | 168 ------------------
 ...sourceLevelClusterSettingManagerFactory.java |  34 ----
 .../resources/RootLevelSettingsManager.java     | 174 ++++++++++++++++++
 .../RootLevelSettingsManagerFactory.java        |  36 ++++
 .../apache/ambari/server/stack/StackModule.java |  20 ++-
 .../apache/ambari/server/state/StackInfo.java   |  37 ++++
 .../stacks/HDP/3.0/configuration/settings.xml   |  91 ++++++++++
 18 files changed, 784 insertions(+), 223 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 c009cbb..6096fa5 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
@@ -205,6 +205,10 @@ public class ResourceInstanceFactoryImpl implements 
ResourceInstanceFactory {
         resourceDefinition = new StackLevelConfigurationResourceDefinition();
         break;
 
+      case RootStackSetting:
+        resourceDefinition = new RootStackSettingsResourceDefinition();
+        break;
+
       case StackService:
         resourceDefinition = new StackServiceResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootStackSettingsResourceDefinition.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootStackSettingsResourceDefinition.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootStackSettingsResourceDefinition.java
new file mode 100644
index 0000000..0991ace
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootStackSettingsResourceDefinition.java
@@ -0,0 +1,51 @@
+/*
+ * 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.Type;
+
+public class RootStackSettingsResourceDefinition extends 
BaseResourceDefinition {
+
+  public RootStackSettingsResourceDefinition(Type resourceType) {
+    super(resourceType);
+  }
+
+  public RootStackSettingsResourceDefinition() {
+    super(Type.RootStackSetting);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "rootStackSettings";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "rootStackSetting";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    Set<SubResourceDefinition> subs = new HashSet<>();
+    return subs;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 1c0a555..c410ce4 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
@@ -63,8 +63,8 @@ import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.MpackEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
-import org.apache.ambari.server.resources.ResourceLevelClusterSettingManager;
-import 
org.apache.ambari.server.resources.ResourceLevelClusterSettingManagerFactory;
+import org.apache.ambari.server.resources.RootLevelSettingsManager;
+import org.apache.ambari.server.resources.RootLevelSettingsManagerFactory;
 import org.apache.ambari.server.stack.StackManager;
 import org.apache.ambari.server.stack.StackManagerFactory;
 import org.apache.ambari.server.state.Cluster;
@@ -143,8 +143,8 @@ public class AmbariMetaInfo {
 
   private final ActionDefinitionManager adManager = new 
ActionDefinitionManager();
   private String serverVersion = "undefined";
-  private String clusterSettingFileName = "cluster-settings.xml";
-
+  private final String clusterSettingsTypeName = "cluster-settings";
+  private final String clusterSettingFileName = clusterSettingsTypeName + 
".xml";
   private File resourcesRoot;
   private File stackRoot;
   private File commonServicesRoot;
@@ -226,16 +226,15 @@ public class AmbariMetaInfo {
   private MpackManager mpackManager;
 
   /**
-   * Factory for injecting {@link ResourceLevelClusterSettingManager} 
instances.
+   * Factory for injecting {@link RootLevelSettingsManager} instances.
    */
   @Inject
-  private ResourceLevelClusterSettingManagerFactory 
resourceLevelClusterSettingManagerFactory;
+  private RootLevelSettingsManagerFactory rootLevelSettingsManagerFactory;
 
   /**
    * Singleton instance of Resource Level 'Cluster Setting' Manager
    */
-  private ResourceLevelClusterSettingManager 
resourceLevelClusterSettingManager;
-
+  private RootLevelSettingsManager rootLevelClusterSettingManager;
 
   private Configuration conf;
 
@@ -298,7 +297,9 @@ public class AmbariMetaInfo {
 
     mpackManager = mpackManagerFactory.create(mpacksV2Staging, stackRoot);
 
-    resourceLevelClusterSettingManager = 
resourceLevelClusterSettingManagerFactory.create(conf.getResourceDirPath());
+    // Manager for cluster's read-only default settings
+    rootLevelClusterSettingManager = 
rootLevelSettingsManagerFactory.create(conf.getResourceDirPath(),
+            clusterSettingFileName, clusterSettingsTypeName);
 
     getCustomActionDefinitions(customActionRoot);
   }
@@ -813,14 +814,14 @@ public class AmbariMetaInfo {
  Returns Resource Level read only 'Cluster Properties'.
  */
   public Set<PropertyInfo> getClusterProperties() {
-    return new 
HashSet<>(resourceLevelClusterSettingManager.getClusterSettingsMap());
+    return new 
HashSet<>(rootLevelClusterSettingManager.getClusterSettingsMap());
   }
 
   /*
    Returns specific Resource Level read only 'Cluster Property'.
    */
   public Set<PropertyInfo> getClusterPropertiesByName(String propertyName) 
throws AmbariException {
-    HashSet<PropertyInfo> properties = new 
HashSet<>(resourceLevelClusterSettingManager.getClusterSettingsMap());
+    HashSet<PropertyInfo> properties = new 
HashSet<>(rootLevelClusterSettingManager.getClusterSettingsMap());
     if (properties.size() == 0) {
       throw new PropertyNotFoundException("'" + propertyName + "', in " + 
clusterSettingFileName);
     }
@@ -838,6 +839,43 @@ public class AmbariMetaInfo {
     return propertyResult;
   }
 
+  /*
+  Returns read only 'Stack Settings'.
+  */
+  public Set<PropertyInfo> getStackSettings(String stackName, String version)
+          throws AmbariException {
+    return new HashSet<>(getStack(stackName, version).getStackSettings());
+  }
+
+  /*
+  Returns specific read only 'Stack Setting'.
+  */
+  public Set<PropertyInfo> getStackSettingsByName(String stackName, String 
version, String settingName)
+          throws AmbariException {
+    Set<PropertyInfo> settings = getStackSettings(stackName, version);
+    if (settings.size() == 0) {
+      throw new StackAccessException("stackName=" + stackName
+              + ", stackVersion=" + version
+              + ", settingName=" + settingName);
+    }
+
+    Set<PropertyInfo> settingResult = new HashSet<>();
+
+    for (PropertyInfo setting : settings) {
+      if (setting.getName().equals(settingName)) {
+        settingResult.add(setting);
+      }
+    }
+
+    if (settingResult.isEmpty()) {
+      throw new StackAccessException("stackName=" + stackName
+              + ", stackVersion=" + version
+              + ", settingName=" + settingName);
+    }
+
+    return settingResult;
+  }
+
   public Set<PropertyInfo> getStackPropertiesByName(String stackName, String 
version, String propertyName)
       throws AmbariException {
     Set<PropertyInfo> properties = getStackProperties(stackName, version);

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
index d77b347..bd2fb91 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
@@ -46,7 +46,7 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 /**
- * Service responsible for services resource requests.
+ * Service responsible for 'root cluster settings' resource requests.
  */
 @Path("/cluster_settings/")
 @Api(value = "ClusterSettings", description = "Endpoint for fetching read only 
'cluster settings'")

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 aef7fc1..4b0208f 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
@@ -46,6 +46,7 @@ import 
org.apache.ambari.server.controller.StackServiceComponentResponse;
 import org.apache.ambari.server.controller.StackServiceResponse;
 import org.apache.ambari.server.controller.StackVersionResponse;
 import org.apache.ambari.server.controller.ThemeResponse;
+import 
org.apache.ambari.server.controller.internal.RootClusterSettingsResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.http.HttpStatus;
 
@@ -1051,5 +1052,93 @@ public class StacksService extends BaseService {
         Collections.singletonMap(Resource.Type.Stack, stackName));
 
   }
+
+  /**
+   * Handles: GET /stack_settings
+   * Get all stack-settings for a given stack.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return        stack settings collection resource representation
+   */
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/settings")
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Get all stack-settings for a given stack",
+          nickname = "StacksService#getClusterSettings",
+          notes = "Returns all stack-settings for a given stack.",
+          response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class,
+          responseContainer = RESPONSE_CONTAINER_LIST)
+  @ApiImplicitParams({
+          @ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned 
attributes",
+                  defaultValue = "StackSettingsInfo/property_name,",
+                  dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_SORT, value = "Sort stack settings 
(asc | desc)",
+                  defaultValue = "StackSettingsInfo/property_name.asc,",
+                  dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_PAGE_SIZE, value = 
QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = 
DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, 
defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_STRING, paramType = 
PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, 
dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY)
+  })
+  @ApiResponses(value = {
+          @ApiResponse(code = HttpStatus.SC_OK, message = 
MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = 
MSG_RESOURCE_NOT_FOUND),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = 
MSG_SERVER_ERROR)
+  })
+  public Response getStackSettings(String body,
+                                     @Context HttpHeaders headers,
+                                     @Context UriInfo ui,
+                                     @ApiParam @PathParam("stackName") String 
stackName,
+                                     @ApiParam @PathParam("stackVersion") 
String stackVersion) {
+    return handleRequest(headers, body, ui, Request.Type.GET, 
createStackSettingsResource(stackName, stackVersion, null));
+  }
+
+  /**
+   * Handles GET /stack_settings/{settingName}
+   * Get specific read-only default stack setting.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return stack settings collection resource representation
+   */
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/settings/{settingName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Returns information about specific read only 'stack 
setting'",
+          response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class)
+  @ApiImplicitParams({
+          @ApiImplicitParam(name = QUERY_FIELDS, value = 
QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING,
+                  paramType = PARAM_TYPE_QUERY, defaultValue = 
RootClusterSettingsResourceProvider.ALL_PROPERTIES),
+  })
+  @ApiResponses({
+          @ApiResponse(code = HttpStatus.SC_OK, message = 
MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = 
MSG_RESOURCE_NOT_FOUND),
+          @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = 
MSG_NOT_AUTHENTICATED),
+          @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = 
MSG_PERMISSION_DENIED),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = 
MSG_SERVER_ERROR),
+  })
+  public Response getStackSetting(String body,
+                                    @Context HttpHeaders headers,
+                                    @Context UriInfo ui,
+                                    @ApiParam @PathParam("stackName") String 
stackName,
+                                    @ApiParam @PathParam("stackVersion") 
String stackVersion,
+                                    @PathParam("settingName") String 
settingName) {
+    return handleRequest(headers, body, ui, Request.Type.GET, 
createStackSettingsResource(stackName, stackVersion, settingName));
+  }
+
+  /**
+   * Create a 'stack setting' resource instance.
+   *
+   * @return 'stack setting' resource instance
+   */
+  ResourceInstance createStackSettingsResource(String stackName,
+                                                 String stackVersion, String 
settingName) {
+    Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+    mapIds.put(Resource.Type.RootStackSetting, settingName);
+
+    return createResource(Resource.Type.RootStackSetting, mapIds);
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 0a75595..358b1bf 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
@@ -846,6 +846,14 @@ public interface AmbariManagementController {
   Set<ReadOnlyConfigurationResponse> 
getStackLevelConfigurations(Set<StackLevelConfigurationRequest> requests) 
throws AmbariException;
 
   /**
+   * Get initial settings for a given stack (!not a service).
+   * @param requests
+   * @return
+   * @throws AmbariException
+   */
+  Set<ReadOnlyConfigurationResponse> 
getReadOnlyStackSettings(Set<StackConfigurationRequest> requests) throws 
AmbariException;
+
+  /**
    * Get initial settings for a cluster (!not a service).
    * @param requests
    * @return

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 5eb18c3..370f735 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
@@ -156,7 +156,6 @@ import org.apache.ambari.server.stack.ExtensionHelper;
 import org.apache.ambari.server.stack.RepoUtil;
 import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
-
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.CommandScriptDefinition;
@@ -4872,8 +4871,8 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
           Set<RootClusterSettingRequest> requests) throws AmbariException {
     Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
     for (RootClusterSettingRequest request : requests) {
-      Set<ReadOnlyConfigurationResponse> stackConfigurations = 
getResourceLevelClusterSettings(request);
-      response.addAll(stackConfigurations);
+      Set<ReadOnlyConfigurationResponse> clusterSettings = 
getResourceLevelClusterSettings(request);
+      response.addAll(clusterSettings);
     }
 
     return response;
@@ -4896,6 +4895,45 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     return response;
   }
 
+  @Override
+  public Set<ReadOnlyConfigurationResponse> getReadOnlyStackSettings(
+          Set<StackConfigurationRequest> requests) throws AmbariException {
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
+    for (StackConfigurationRequest request : requests) {
+      String stackName    = request.getStackName();
+      String stackVersion = request.getStackVersion();
+      Set<ReadOnlyConfigurationResponse> stackSettings = 
getReadOnlyStackSettings(request);
+
+      for (ReadOnlyConfigurationResponse stackSetting : stackSettings) {
+        stackSetting.setStackName(stackName);
+        stackSetting.setStackVersion(stackVersion);
+      }
+      response.addAll(stackSettings);
+    }
+
+    return response;
+  }
+
+  private Set<ReadOnlyConfigurationResponse> getReadOnlyStackSettings(
+          StackConfigurationRequest request) throws AmbariException {
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
+
+    String stackName = request.getStackName();
+    String stackVersion = request.getStackVersion();
+    String settingName = request.getPropertyName();
+
+    Set<PropertyInfo> settings;
+    if (settingName != null) {
+      settings = ambariMetaInfo.getStackSettingsByName(stackName, 
stackVersion, settingName);
+    } else {
+      settings = ambariMetaInfo.getStackSettings(stackName, stackVersion);
+    }
+
+    for (PropertyInfo setting : settings) {
+      response.add(setting.convertToResponse());
+    }
+    return response;
+  }
 
   @Override
   public Set<ReadOnlyConfigurationResponse> getStackConfigurations(

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index cb19099..3db55d4 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -111,7 +111,7 @@ import org.apache.ambari.server.registry.RegistryFactory;
 import org.apache.ambari.server.registry.RegistryFactoryImpl;
 import org.apache.ambari.server.registry.RegistryManager;
 import org.apache.ambari.server.registry.RegistryManagerImpl;
-import 
org.apache.ambari.server.resources.ResourceLevelClusterSettingManagerFactory;
+import org.apache.ambari.server.resources.RootLevelSettingsManagerFactory;
 import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
 import org.apache.ambari.server.security.SecurityHelper;
@@ -516,7 +516,7 @@ public class ControllerModule extends AbstractModule {
     install(new 
FactoryModuleBuilder().build(MetricPropertyProviderFactory.class));
     install(new FactoryModuleBuilder().build(UpgradeContextFactory.class));
     install(new FactoryModuleBuilder().build(MpackManagerFactory.class));
-    install(new 
FactoryModuleBuilder().build(ResourceLevelClusterSettingManagerFactory.class));
+    install(new 
FactoryModuleBuilder().build(RootLevelSettingsManagerFactory.class));
 
     bind(RegistryFactory.class).to(RegistryFactoryImpl.class);
     bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 123f2fe..9050e3d 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
@@ -152,6 +152,8 @@ public abstract class AbstractControllerResourceProvider 
extends AbstractAuthori
     switch (type.getInternalType()) {
       case Cluster:
         return new ClusterResourceProvider(managementController);
+      case RootClusterSetting:
+        return new RootClusterSettingsResourceProvider(managementController);
       case Service:
         return 
resourceProviderFactory.getServiceResourceProvider(managementController);
       case ServiceGroup:
@@ -198,8 +200,6 @@ public abstract class AbstractControllerResourceProvider 
extends AbstractAuthori
         return new RegistryMpackVersionResourceProvider(managementController);
       case Mpack:
         return new MpackResourceProvider(managementController);
-      case RootClusterSetting:
-        return new RootClusterSettingsResourceProvider(managementController);
       case StackVersion:
         return new StackVersionResourceProvider(managementController);
       case ClusterStackVersion:
@@ -212,6 +212,8 @@ public abstract class AbstractControllerResourceProvider 
extends AbstractAuthori
         return new StackServiceComponentResourceProvider(propertyIds, 
keyPropertyIds, managementController);
       case StackConfiguration:
         return new StackConfigurationResourceProvider(propertyIds, 
keyPropertyIds, managementController);
+      case RootStackSetting:
+        return new RootStackSettingsResourceProvider(managementController);
       case StackConfigurationDependency:
         return new StackConfigurationDependencyResourceProvider(propertyIds, 
keyPropertyIds, managementController);
       case StackLevelConfiguration:

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootStackSettingsResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootStackSettingsResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootStackSettingsResourceProvider.java
new file mode 100644
index 0000000..81baec6
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootStackSettingsResourceProvider.java
@@ -0,0 +1,177 @@
+/*
+ * 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.HashMap;
+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.ReadOnlyConfigurationResponse;
+import org.apache.ambari.server.controller.StackConfigurationRequest;
+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;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.inject.assistedinject.Assisted;
+
+public class RootStackSettingsResourceProvider extends 
ReadOnlyResourceProvider {
+
+  public static final String RESPONSE_KEY = "StackSettingsInfo";
+  public static final String ALL_PROPERTIES = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "*";
+  public static final String STACK_NAME_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "stack_name";
+  public static final String STACK_VERSION_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "stack_version";
+  public static final String PROPERTY_NAME_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "property_name";
+  public static final String PROPERTY_DISPLAY_NAME_PROPERTY_ID = RESPONSE_KEY 
+ PropertyHelper.EXTERNAL_PATH_SEP + "property_display_name";
+  public static final String PROPERTY_VALUE_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "property_value";
+  public static final String PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID = 
RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "property_value_attributes";
+  public static final String DEPENDS_ON_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "property_depends_on";
+  public static final String PROPERTY_DESCRIPTION_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "property_description";
+  public static final String PROPERTY_PROPERTY_TYPE_PROPERTY_ID = RESPONSE_KEY 
+ PropertyHelper.EXTERNAL_PATH_SEP + "property_type";
+  public static final String PROPERTY_TYPE_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "type";
+  public static final String PROPERTY_FINAL_PROPERTY_ID = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "final";
+
+  private static Set<String> pkPropertyIds = new HashSet<>(Arrays.asList(new 
String[]{PROPERTY_NAME_PROPERTY_ID}));
+
+  /**
+   * The key property ids for stack's 'settings' resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new 
HashMap<>();
+
+  /**
+   * The property ids for an stack's 'settings' resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(STACK_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(STACK_VERSION_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_DISPLAY_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_VALUE_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID);
+    PROPERTY_IDS.add(DEPENDS_ON_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_DESCRIPTION_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_PROPERTY_TYPE_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_TYPE_PROPERTY_ID);
+    PROPERTY_IDS.add(PROPERTY_FINAL_PROPERTY_ID);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Type.Stack, STACK_NAME_PROPERTY_ID);
+    KEY_PROPERTY_IDS.put(Type.StackVersion, STACK_VERSION_PROPERTY_ID);
+    KEY_PROPERTY_IDS.put(Type.RootStackSetting, PROPERTY_NAME_PROPERTY_ID);
+  }
+
+  protected RootStackSettingsResourceProvider(@Assisted 
AmbariManagementController managementController) {
+    super(Resource.Type.RootStackSetting, PROPERTY_IDS, KEY_PROPERTY_IDS, 
managementController);
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+          throws SystemException, UnsupportedPropertyException,
+          NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<StackConfigurationRequest> requests = new HashSet<>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ReadOnlyConfigurationResponse> responses = getResources(new 
Command<Set<ReadOnlyConfigurationResponse>>() {
+      @Override
+      public Set<ReadOnlyConfigurationResponse> invoke() throws 
AmbariException {
+        return getManagementController().getReadOnlyStackSettings(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<>();
+
+    for (ReadOnlyConfigurationResponse response : responses) {
+      Resource resource = new ResourceImpl(Type.RootStackSetting);
+
+      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_VALUE_ATTRIBUTES_PROPERTY_ID, 
response.getPropertyValueAttributes(), requestedIds);
+      setResourceProperty(resource, DEPENDS_ON_PROPERTY_ID, 
response.getDependsOnProperties(), requestedIds);
+      setResourceProperty(resource, PROPERTY_DESCRIPTION_PROPERTY_ID, 
response.getPropertyDescription(), requestedIds);
+
+      //should not be returned if empty
+      if (StringUtils.isNotEmpty(response.getPropertyDisplayName())) {
+        setResourceProperty(resource, PROPERTY_DISPLAY_NAME_PROPERTY_ID, 
response.getPropertyDisplayName(), requestedIds);
+      }
+
+      setResourceProperty(resource, PROPERTY_PROPERTY_TYPE_PROPERTY_ID, 
response.getPropertyType(), 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(RESPONSE_KEY, 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 StackConfigurationRequest getRequest(Map<String, Object> properties) 
{
+    return new StackConfigurationRequest(
+            (String) properties.get(STACK_NAME_PROPERTY_ID),
+            (String) properties.get(STACK_VERSION_PROPERTY_ID),
+            null, // Call is at stack version level (and not service level).
+            (String) properties.get(PROPERTY_NAME_PROPERTY_ID));
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 3699cd0..bd6d7bb 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
@@ -101,6 +101,7 @@ public interface Resource {
     RegistryMpackVersion,
     Mpack,
     Stack,
+    RootStackSetting,
     StackVersion,
     ExtensionLink,
     Extension,
@@ -233,6 +234,7 @@ public interface Resource {
     public static final Type RegistryMpackVersion = 
InternalType.RegistryMpackVersion.getType();
     public static final Type Mpack = InternalType.Mpack.getType();
     public static final Type Stack = InternalType.Stack.getType();
+    public static final Type RootStackSetting = 
InternalType.RootStackSetting.getType();
     public static final Type StackVersion = 
InternalType.StackVersion.getType();
     public static final Type ExtensionLink = 
InternalType.ExtensionLink.getType();
     public static final Type Extension = InternalType.Extension.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManager.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManager.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManager.java
deleted file mode 100644
index 4cb6cd9..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManager.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.resources;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.xml.namespace.QName;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.stack.ConfigurationInfo;
-import org.apache.ambari.server.stack.ConfigurationModule;
-import org.apache.ambari.server.stack.ModuleFileUnmarshaller;
-import org.apache.ambari.server.state.PropertyInfo;
-import org.apache.ambari.server.state.stack.ConfigurationXml;
-import org.apache.ambari.server.utils.XmlUtils;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.inject.assistedinject.Assisted;
-import com.google.inject.assistedinject.AssistedInject;
-
-public class ResourceLevelClusterSettingManager {
-  /**
-   * Used to unmarshal a configuration file to an object representation
-   */
-  private static ModuleFileUnmarshaller unmarshaller = new 
ModuleFileUnmarshaller();
-
-  private String clusterSettingsPath;
-  private static final String CLUSTER_SETTINGS_FILE_NAME = 
"cluster-settings.xml";
-  private static final String clusterSettingsConfigType = "cluster-settings";
-  private static File clusterSettingsFile;
-  private final static Logger LOG = 
LoggerFactory.getLogger(ResourceLevelClusterSettingManager.class);
-  private Map<String, Map<String, PropertyInfo>> clusterSettingsMap = new 
ConcurrentHashMap<>();
-  private Map<String, ConfigurationModule> configurationModules = new 
HashMap<>();
-
-  @AssistedInject
-  public ResourceLevelClusterSettingManager(@Assisted("resourcesDirPath") 
String resourcesDirPath) {
-    clusterSettingsPath = resourcesDirPath;
-    clusterSettingsFile = new File(clusterSettingsPath + File.separator + 
CLUSTER_SETTINGS_FILE_NAME);
-    populateClusterSettingsXml();
-  }
-
-  public Collection<PropertyInfo> getClusterSettingsMap() {
-    return 
configurationModules.get("cluster-settings").getModuleInfo().getProperties();
-  }
-
-  /**
-   * Obtain a collection of of configuration modules representing each 
configuration
-   * file contained in this configuration directory.
-   *
-   * @return collection of configuration modules
-   */
-  public Collection<ConfigurationModule> getConfigurationModules() {
-    return configurationModules.values();
-  }
-
-  /**
-   * Parses 'cluster-settings.xml' during ambari-server boostrap and (re)start
-   * Reads from /var/lib/ambari-server/resources
-   *
-   * @throws java.io.IOException
-   */
-  private void populateClusterSettingsXml() {
-    ConfigurationXml config = null;
-    try {
-      config = unmarshaller.unmarshal(ConfigurationXml.class, 
clusterSettingsFile);
-      ConfigurationInfo configInfo = new 
ConfigurationInfo(parseProperties(config, clusterSettingsFile.getName()),
-              parseAttributes(config));
-      ConfigurationModule module = new 
ConfigurationModule(clusterSettingsConfigType, configInfo);
-      configurationModules.put(clusterSettingsConfigType, module);
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-
-  }
-
-  /**
-   * Parse a configurations type attributes.
-   *
-   * @param configuration object representation of a configuration file
-   * @return collection of attributes for the configuration type
-   */
-  private Map<String, String> parseAttributes(ConfigurationXml configuration) {
-    Map<String, String> attributes = new HashMap<>();
-    for (Map.Entry<QName, String> attribute : 
configuration.getAttributes().entrySet()) {
-      attributes.put(attribute.getKey().getLocalPart(), attribute.getValue());
-    }
-    return attributes;
-  }
-
-  /**
-   * Parse a configurations properties.
-   *
-   * @param configuration object representation of a configuration file
-   * @param fileName      configuration file name
-   * @return collection of properties
-   */
-  private Collection<PropertyInfo> parseProperties(ConfigurationXml 
configuration, String fileName)
-          throws FileNotFoundException, RuntimeException {
-    List<PropertyInfo> props = new ArrayList<>();
-    for (PropertyInfo pi : configuration.getProperties()) {
-      pi.setFilename(fileName);
-      if 
(pi.getPropertyTypes().contains(PropertyInfo.PropertyType.VALUE_FROM_PROPERTY_FILE))
 {
-        if (clusterSettingsPath != null || clusterSettingsPath.isEmpty()) {
-          String propertyFileType = 
pi.getPropertyValueAttributes().getPropertyFileType();
-          if (clusterSettingsFile.exists() && clusterSettingsFile.isFile()) {
-            try {
-              String propertyValue = 
FileUtils.readFileToString(clusterSettingsFile);
-              boolean valid = true;
-              switch (propertyFileType.toLowerCase()) {
-                case "xml":
-                  if (!XmlUtils.isValidXml(propertyValue)) {
-                    valid = false;
-                    LOG.error("Failed to load value from property file. 
Property file {} is not a valid XML file",
-                            clusterSettingsFile);
-                  }
-                  break;
-                case "json": // Not supporting JSON as of now.
-                case "text": // fallthrough
-                default:
-                  throw new AmbariException("'" + propertyFileType + "' type 
file not supported for '"
-                          + clusterSettingsConfigType + "'. File Path : " + 
clusterSettingsFile.getAbsolutePath());
-              }
-              if (valid) {
-                pi.setValue(propertyValue);
-              }
-            } catch (IOException e) {
-              LOG.error("Failed to load value from property file {}. Error 
Message {}",
-                      clusterSettingsFile.getAbsolutePath(), e.getMessage());
-            }
-          } else {
-            throw new FileNotFoundException("Failed to find '" + 
CLUSTER_SETTINGS_FILE_NAME + "' file with path : "
-                    + clusterSettingsFile);
-          }
-        } else {
-          throw new RuntimeException("Failed to load value from property file. 
Properties directory {} does not exist"
-                  + clusterSettingsFile.getAbsolutePath());
-        }
-      }
-      props.add(pi);
-    }
-    return props;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManagerFactory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManagerFactory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManagerFactory.java
deleted file mode 100644
index fcda654..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManagerFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.resources;
-
-import com.google.inject.assistedinject.Assisted;
-import com.google.inject.assistedinject.AssistedInject;
-
-/**
- * The {@link ResourceLevelClusterSettingManagerFactory} is used along with 
{@link AssistedInject} to
- * build instances of {@link ResourceLevelClusterSettingManager}.
- */
-public interface ResourceLevelClusterSettingManagerFactory {
-
-  /**
-   * @return a ResourceLevelClusterSetting manager instance.
-   */
-  ResourceLevelClusterSettingManager create(@Assisted("resourcesDirPath") 
String resourcesDirPath);
-}
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManager.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManager.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManager.java
new file mode 100644
index 0000000..3b74e69
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManager.java
@@ -0,0 +1,174 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.resources;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.stack.ConfigurationInfo;
+import org.apache.ambari.server.stack.ConfigurationModule;
+import org.apache.ambari.server.stack.ModuleFileUnmarshaller;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.stack.ConfigurationXml;
+import org.apache.ambari.server.utils.XmlUtils;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+public class RootLevelSettingsManager {
+  /**
+   * Used to unmarshal a configuration file to an object representation
+   */
+  private static ModuleFileUnmarshaller unmarshaller = new 
ModuleFileUnmarshaller();
+
+  private String clusterSettingsPath;
+  private String clusterSettingsFileName;
+  private String clusterSettingsConfigType;
+  private static File clusterSettingsFile;
+  private final static Logger LOG = 
LoggerFactory.getLogger(RootLevelSettingsManager.class);
+  private Map<String, Map<String, PropertyInfo>> clusterSettingsMap = new 
ConcurrentHashMap<>();
+  private Map<String, ConfigurationModule> configurationModules = new 
HashMap<>();
+
+  @AssistedInject
+  public RootLevelSettingsManager(@Assisted("directoryPath") String 
directoryPath,
+                                            @Assisted("settingsFileName") 
String settingsFileName,
+                                            @Assisted("settingsTypeName") 
String settingsTypeName) {
+    clusterSettingsPath = directoryPath;
+    clusterSettingsFileName = settingsFileName;
+    clusterSettingsConfigType = settingsTypeName;
+    clusterSettingsFile = new File(clusterSettingsPath + File.separator + 
clusterSettingsFileName);
+    LOG.info("\n\n\n\n SWAP - clusterSettingsPath = "+clusterSettingsPath+" - 
clusterSettingsFileName = "+clusterSettingsFileName
+            +" - clusterSettingsConfigType = "+clusterSettingsFile + 
"clusterSettingsFile = "+clusterSettingsFile);
+    populateClusterSettingsXml();
+  }
+
+  public Collection<PropertyInfo> getClusterSettingsMap() {
+    return 
configurationModules.get(clusterSettingsConfigType).getModuleInfo().getProperties();
+  }
+
+  /**
+   * Obtain a collection of of configuration modules representing each 
configuration
+   * file contained in this configuration directory.
+   *
+   * @return collection of configuration modules
+   */
+  public Collection<ConfigurationModule> getConfigurationModules() {
+    return configurationModules.values();
+  }
+
+  /**
+   * Parses 'cluster-settings.xml' during ambari-server boostrap and (re)start
+   * Reads from /var/lib/ambari-server/resources
+   *
+   * @throws java.io.IOException
+   */
+  private void populateClusterSettingsXml() {
+    ConfigurationXml config = null;
+    try {
+      config = unmarshaller.unmarshal(ConfigurationXml.class, 
clusterSettingsFile);
+      ConfigurationInfo configInfo = new 
ConfigurationInfo(parseProperties(config, clusterSettingsFile.getName()),
+              parseAttributes(config));
+      ConfigurationModule module = new 
ConfigurationModule(clusterSettingsConfigType, configInfo);
+      configurationModules.put(clusterSettingsConfigType, module);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  /**
+   * Parse a configurations type attributes.
+   *
+   * @param configuration object representation of a configuration file
+   * @return collection of attributes for the configuration type
+   */
+  private Map<String, String> parseAttributes(ConfigurationXml configuration) {
+    Map<String, String> attributes = new HashMap<>();
+    for (Map.Entry<QName, String> attribute : 
configuration.getAttributes().entrySet()) {
+      attributes.put(attribute.getKey().getLocalPart(), attribute.getValue());
+    }
+    return attributes;
+  }
+
+  /**
+   * Parse a configurations properties.
+   *
+   * @param configuration object representation of a configuration file
+   * @param fileName      configuration file name
+   * @return collection of properties
+   */
+  private Collection<PropertyInfo> parseProperties(ConfigurationXml 
configuration, String fileName)
+          throws FileNotFoundException, RuntimeException {
+    List<PropertyInfo> props = new ArrayList<>();
+    for (PropertyInfo pi : configuration.getProperties()) {
+      pi.setFilename(fileName);
+      if 
(pi.getPropertyTypes().contains(PropertyInfo.PropertyType.VALUE_FROM_PROPERTY_FILE))
 {
+        if (clusterSettingsPath != null || clusterSettingsPath.isEmpty()) {
+          String propertyFileType = 
pi.getPropertyValueAttributes().getPropertyFileType();
+          if (clusterSettingsFile.exists() && clusterSettingsFile.isFile()) {
+            try {
+              String propertyValue = 
FileUtils.readFileToString(clusterSettingsFile);
+              boolean valid = true;
+              switch (propertyFileType.toLowerCase()) {
+                case "xml":
+                  if (!XmlUtils.isValidXml(propertyValue)) {
+                    valid = false;
+                    LOG.error("Failed to load value from property file. 
Property file {} is not a valid XML file",
+                            clusterSettingsFile);
+                  }
+                  break;
+                case "json": // Not supporting JSON as of now.
+                case "text": // fallthrough
+                default:
+                  throw new AmbariException("'" + propertyFileType + "' type 
file not supported for '"
+                          + clusterSettingsConfigType + "'. File Path : " + 
clusterSettingsFile.getAbsolutePath());
+              }
+              if (valid) {
+                pi.setValue(propertyValue);
+              }
+            } catch (IOException e) {
+              LOG.error("Failed to load value from property file {}. Error 
Message {}",
+                      clusterSettingsFile.getAbsolutePath(), e.getMessage());
+            }
+          } else {
+            throw new FileNotFoundException("Failed to find '" + 
clusterSettingsFileName + "' file with path : "
+                    + clusterSettingsFile);
+          }
+        } else {
+          throw new RuntimeException("Failed to load value from property file. 
Properties directory {} does not exist"
+                  + clusterSettingsFile.getAbsolutePath());
+        }
+      }
+      props.add(pi);
+    }
+    return props;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManagerFactory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManagerFactory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManagerFactory.java
new file mode 100644
index 0000000..5a94b12
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/RootLevelSettingsManagerFactory.java
@@ -0,0 +1,36 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.resources;
+
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+/**
+ * The {@link RootLevelSettingsManagerFactory} is used along with {@link 
AssistedInject} to
+ * build instances of {@link RootLevelSettingsManager}.
+ */
+public interface RootLevelSettingsManagerFactory {
+
+  /**
+   * @return a ResourceLevelClusterSetting manager instance.
+   */
+  RootLevelSettingsManager create(@Assisted("directoryPath") String 
directoryPath,
+                                            @Assisted("settingsFileName") 
String settingsFileName,
+                                            @Assisted("settingsTypeName") 
String settingsTypeName);
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
index 878415b..dc16ae2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
@@ -650,6 +650,10 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
    */
   private void populateConfigurationModules() {
     //todo: can't exclude types in stack config
+    // TODO : Correct naming for 'SERVICE_CONFIG_FOLDER_NAME' and 
'SERVICE_PROPERTIES_FOLDER_NAME',
+    // as we are currently in stack version folder (not in services). It's 
reuse of macros,
+    // which is misleading given that both stack's version and services dirs 
can have 'configurations' and 'properties'
+    // folder.
     ConfigurationDirectory configDirectory = 
stackDirectory.getConfigurationDirectory(
         StackDirectory.SERVICE_CONFIG_FOLDER_NAME, 
StackDirectory.SERVICE_PROPERTIES_FOLDER_NAME);
 
@@ -659,8 +663,20 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
           stackInfo.setValid(config.isValid());
           stackInfo.addErrors(config.getErrors());
         }
-        
stackInfo.getProperties().addAll(config.getModuleInfo().getProperties());
-        stackInfo.setConfigTypeAttributes(config.getConfigType(), 
config.getModuleInfo().getAttributes());
+        // TODO : Remove this switch case as part of removing case 
"cluster-env" as part of AMBARI-22197, where we are
+        // phasing out cluster-env entirely.
+        switch(config.getConfigType()) {
+          case "settings":
+            stackInfo.setStackSettings((List<PropertyInfo>) 
config.getModuleInfo().getProperties());
+            
stackInfo.setStackSettingsConfigTypeAttributes(config.getConfigType(), 
config.getModuleInfo().getAttributes());
+            break;
+          case "cluster-env":
+            
stackInfo.getProperties().addAll(config.getModuleInfo().getProperties());
+            stackInfo.setConfigTypeAttributes(config.getConfigType(), 
config.getModuleInfo().getAttributes());
+            break;
+          default:
+            break;
+        }
         configurationModules.put(config.getConfigType(), config);
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/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 07d28ce..df0d2dc 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
@@ -60,6 +60,11 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable {
   // stack-level properties
   private List<PropertyInfo> properties;
   private Map<String, Map<String, Map<String, String>>> configTypes;
+
+  // Gets information from stacks/<stack-name>/<version>/settings.xml
+  private List<PropertyInfo> stackSettings;
+  private Map<String, Map<String, Map<String, String>>> 
stackSettingsConfigTypes;
+
   private Map<String, UpgradePack> upgradePacks;
   private ConfigUpgradePack configUpgradePack;
   private StackRoleCommandOrder roleCommandOrder;
@@ -245,6 +250,12 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable {
     this.properties = properties;
   }
 
+  public List<PropertyInfo> getStackSettings() { return stackSettings; }
+
+  public void setStackSettings(List<PropertyInfo> stackSettings) {
+    this.stackSettings = stackSettings;
+  }
+
   /**
    * Obtain the config types associated with this stack.
    * The returned map is an unmodifiable view.
@@ -272,6 +283,32 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable {
   }
 
   /**
+   * Obtain the config types associated with this stack's settings.
+   * The returned map is an unmodifiable view.
+   * @return copy of the map of config types associated with this stack's 
settings
+   */
+  public synchronized Map<String, Map<String, Map<String, String>>> 
getStackSettingsConfigTypeAttributes() {
+    return stackSettingsConfigTypes == null ?
+            Collections.emptyMap() :
+            Collections.unmodifiableMap(stackSettingsConfigTypes);
+  }
+
+
+  /**
+   * Add the given type and set it's attributes.
+   *
+   * @param type            configuration type
+   * @param typeAttributes  attributes associated with the type
+   */
+  public synchronized void setStackSettingsConfigTypeAttributes(String type, 
Map<String, Map<String, String>> typeAttributes) {
+    if (this.stackSettingsConfigTypes == null) {
+      stackSettingsConfigTypes = new HashMap<>();
+    }
+    // todo: no exclusion mechanism for stack config types
+    stackSettingsConfigTypes.put(type, typeAttributes);
+  }
+
+  /**
    * Set all types and associated attributes.  Any previously existing types 
and
    * attributes are removed prior to setting the new values.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/adc7060a/ambari-server/src/main/resources/stacks/HDP/3.0/configuration/settings.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/3.0/configuration/settings.xml 
b/ambari-server/src/main/resources/stacks/HDP/3.0/configuration/settings.xml
new file mode 100644
index 0000000..97e4063
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/3.0/configuration/settings.xml
@@ -0,0 +1,91 @@
+<?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>
+    <!-- Define stack_name property in the base stack. DO NOT override this 
property for each stack version -->
+    <property>
+        <name>stack_name</name>
+        <value>HDP</value>
+        <description>The name of the stack.</description>
+        <value-attributes>
+            <read-only>true</read-only>
+            <overridable>false</overridable>
+            <visible>false</visible>
+        </value-attributes>
+        <on-ambari-upgrade add="true"/>
+    </property>
+    <!-- Define stack_tools property in the base stack. DO NOT override this 
property for each stack version -->
+    <property>
+        <name>stack_tools</name>
+        <value/>
+        <description>Stack specific tools</description>
+        <property-type>VALUE_FROM_PROPERTY_FILE</property-type>
+        <value-attributes>
+            <property-file-name>stack_tools.json</property-file-name>
+            <property-file-type>json</property-file-type>
+            <read-only>true</read-only>
+            <overridable>false</overridable>
+            <visible>false</visible>
+        </value-attributes>
+        <on-ambari-upgrade add="true"/>
+    </property>
+    <!-- Define stack_features property in the base stack. DO NOT override 
this property for each stack version -->
+    <property>
+        <name>stack_features</name>
+        <value/>
+        <description>List of features supported by the stack</description>
+        <property-type>VALUE_FROM_PROPERTY_FILE</property-type>
+        <value-attributes>
+            <property-file-name>stack_features.json</property-file-name>
+            <property-file-type>json</property-file-type>
+            <read-only>true</read-only>
+            <overridable>false</overridable>
+            <visible>false</visible>
+        </value-attributes>
+        <on-ambari-upgrade add="true"/>
+    </property>
+    <!-- Define stack_packages property in the base stack. DO NOT override 
this property for each stack version -->
+    <property>
+        <name>stack_packages</name>
+        <value/>
+        <description>Associations between component and stack-select 
tools.</description>
+        <property-type>VALUE_FROM_PROPERTY_FILE</property-type>
+        <value-attributes>
+            <property-file-name>stack_packages.json</property-file-name>
+            <property-file-type>json</property-file-type>
+            <read-only>true</read-only>
+            <overridable>false</overridable>
+            <visible>false</visible>
+        </value-attributes>
+        <on-ambari-upgrade add="true"/>
+    </property>
+    <property>
+        <name>stack_root</name>
+        <value>{"HDP":"/usr/hdp"}</value>
+        <description>JSON which defines the stack root by stack 
name</description>
+        <value-attributes>
+            <read-only>true</read-only>
+            <overridable>false</overridable>
+            <visible>false</visible>
+        </value-attributes>
+        <on-ambari-upgrade add="true"/>
+    </property>
+</configuration>
\ No newline at end of file

Reply via email to