AMBARI-22196. Refactor non-stack cluster-env configs to cluster settings.

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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 8d8c1a551579b696d1730afcde9c49594a1dc77b
Parents: 5ddb07c
Author: Swapan Shridhar <sshrid...@hortonworks.com>
Authored: Fri Oct 6 01:19:13 2017 -0700
Committer: Swapan Shridhar <sshrid...@hortonworks.com>
Committed: Thu Oct 12 00:43:25 2017 -0700

----------------------------------------------------------------------
 .../server/PropertyNotFoundException.java       |  27 ++
 .../server/ResourcesPathNotFoundException.java  |  25 ++
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../RootClusterSettingsResourceDefinition.java  |  52 +++
 .../server/api/services/AmbariMetaInfo.java     |  49 +++
 .../api/services/RootClusterSettingService.java | 135 ++++++++
 .../server/api/services/StacksService.java      |  10 +-
 .../controller/AmbariManagementController.java  |  12 +-
 .../AmbariManagementControllerImpl.java         |  54 +++-
 .../server/controller/ControllerModule.java     |   2 +
 .../ReadOnlyConfigurationResponse.java          | 272 ++++++++++++++++
 .../controller/RootClusterSettingRequest.java   |  39 +++
 .../controller/StackConfigurationResponse.java  | 266 ---------------
 .../StackLevelConfigurationRequest.java         |   2 +-
 .../StackLevelConfigurationResponse.java        |  20 +-
 .../ambari/server/controller/StackV2.java       |  12 +-
 .../AbstractControllerResourceProvider.java     |   2 +
 .../RootClusterSettingsResourceProvider.java    | 167 ++++++++++
 .../server/controller/internal/Stack.java       |  14 +-
 .../StackConfigurationResourceProvider.java     |   8 +-
 ...StackLevelConfigurationResourceProvider.java |   8 +-
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../ResourceLevelClusterSettingManager.java     | 168 ++++++++++
 ...sourceLevelClusterSettingManagerFactory.java |  34 ++
 .../ambari/server/state/ConfigHelper.java       |   1 +
 .../ambari/server/state/PropertyInfo.java       |   6 +-
 .../src/main/resources/cluster-settings.xml     | 322 +++++++++++++++++++
 27 files changed, 1393 insertions(+), 320 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/PropertyNotFoundException.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/PropertyNotFoundException.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/PropertyNotFoundException.java
new file mode 100644
index 0000000..b036c20
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/PropertyNotFoundException.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+@SuppressWarnings("serial")
+public class PropertyNotFoundException extends ObjectNotFoundException {
+
+  public PropertyNotFoundException(String message) {
+    super(message);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/ResourcesPathNotFoundException.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/ResourcesPathNotFoundException.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/ResourcesPathNotFoundException.java
new file mode 100644
index 0000000..fdc1971
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/ResourcesPathNotFoundException.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+public class ResourcesPathNotFoundException extends ObjectNotFoundException {
+  public ResourcesPathNotFoundException(String resourceDirPath) {
+    super("Resources folder not found. Path passed-in is : "
+            + resourceDirPath);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 7431f9d..737b9b4 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
@@ -104,6 +104,10 @@ public class ResourceInstanceFactoryImpl implements 
ResourceInstanceFactory {
         resourceDefinition = new ClusterResourceDefinition();
         break;
 
+      case RootClusterSetting:
+        resourceDefinition = new RootClusterSettingsResourceDefinition();
+        break;
+
       case ServiceGroup:
         resourceDefinition = new ServiceGroupResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootClusterSettingsResourceDefinition.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootClusterSettingsResourceDefinition.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootClusterSettingsResourceDefinition.java
new file mode 100644
index 0000000..e83c191
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootClusterSettingsResourceDefinition.java
@@ -0,0 +1,52 @@
+/**
+ * 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.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+public class RootClusterSettingsResourceDefinition extends 
BaseResourceDefinition {
+  /**
+   * Constructor.
+   */
+  public RootClusterSettingsResourceDefinition() {
+    super(Resource.Type.RootClusterSetting);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "rootClusterSettings";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "rootClusterSetting";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    Set<SubResourceDefinition> subs = new HashSet<SubResourceDefinition>();
+    return subs;
+  }
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 c07df43..2bb450b 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
@@ -41,6 +41,8 @@ import javax.xml.bind.JAXBException;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.PropertyNotFoundException;
+import org.apache.ambari.server.ResourcesPathNotFoundException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.MpackRequest;
@@ -61,6 +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.stack.StackManager;
 import org.apache.ambari.server.stack.StackManagerFactory;
 import org.apache.ambari.server.state.Cluster;
@@ -139,6 +143,7 @@ public class AmbariMetaInfo {
 
   private final ActionDefinitionManager adManager = new 
ActionDefinitionManager();
   private String serverVersion = "undefined";
+  private String clusterSettingFileName = "cluster-settings.xml";
 
   private File resourcesRoot;
   private File stackRoot;
@@ -220,6 +225,17 @@ public class AmbariMetaInfo {
   */
   private MpackManager mpackManager;
 
+  /**
+   * Factory for injecting {@link ResourceLevelClusterSettingManager} 
instances.
+   */
+  @Inject
+  private ResourceLevelClusterSettingManagerFactory 
resourceLevelClusterSettingManagerFactory;
+
+  /**
+   * Singleton instance of Resource Level 'Cluster Setting' Manager
+   */
+  private ResourceLevelClusterSettingManager 
resourceLevelClusterSettingManager;
+
 
   private Configuration conf;
 
@@ -236,6 +252,8 @@ public class AmbariMetaInfo {
     String resourcesPath = conf.getResourceDirPath();
     if(resourcesPath != null && !resourcesPath.isEmpty()) {
       resourcesRoot = new File(resourcesPath);
+    } else {
+      throw new ResourcesPathNotFoundException(resourcesPath);
     }
 
     String stackPath = conf.getMetadataPath();
@@ -280,6 +298,8 @@ public class AmbariMetaInfo {
 
     mpackManager = mpackManagerFactory.create(mpacksV2Staging, stackRoot);
 
+    resourceLevelClusterSettingManager = 
resourceLevelClusterSettingManagerFactory.create(conf.getResourceDirPath());
+
     getCustomActionDefinitions(customActionRoot);
   }
 
@@ -789,6 +809,35 @@ public class AmbariMetaInfo {
     return propertyResult;
   }
 
+  /*
+ Returns Resource Level read only 'Cluster Properties'.
+ */
+  public Set<PropertyInfo> getClusterProperties() {
+    return new 
HashSet<>(resourceLevelClusterSettingManager.getClusterSettingsMap());
+  }
+
+  /*
+   Returns specific Resource Level read only 'Cluster Property'.
+   */
+  public Set<PropertyInfo> getClusterPropertiesByName(String propertyName) 
throws AmbariException {
+    HashSet<PropertyInfo> properties = new 
HashSet<>(resourceLevelClusterSettingManager.getClusterSettingsMap());
+    if (properties.size() == 0) {
+      throw new PropertyNotFoundException("'" + propertyName + "', in " + 
clusterSettingFileName);
+    }
+    Set<PropertyInfo> propertyResult = new HashSet<>();
+
+    for (PropertyInfo property : properties) {
+      if (property.getName().equals(propertyName)) {
+        propertyResult.add(property);
+      }
+    }
+
+    if (propertyResult.isEmpty()) {
+      throw new PropertyNotFoundException("'" + propertyName + "', in " + 
clusterSettingFileName);
+    }
+    return propertyResult;
+  }
+
   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/8d8c1a55/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
new file mode 100644
index 0000000..d77b347
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootClusterSettingService.java
@@ -0,0 +1,135 @@
+/*
+ * 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.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.ReadOnlyConfigurationResponse;
+import org.apache.ambari.server.controller.internal.MpackResourceProvider;
+import 
org.apache.ambari.server.controller.internal.RootClusterSettingsResourceProvider;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.http.HttpStatus;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * Service responsible for services resource requests.
+ */
+@Path("/cluster_settings/")
+@Api(value = "ClusterSettings", description = "Endpoint for fetching read only 
'cluster settings'")
+public class RootClusterSettingService extends BaseService {
+
+  public RootClusterSettingService() {
+    super();
+  }
+
+  /**
+   * Handles: GET /cluster_settings
+   * Get all default settings for a cluster.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return service collection resource representation
+   */
+  @GET
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Returns information for all the read only 'cluster 
settings'",
+          response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class, 
responseContainer = RESPONSE_CONTAINER_LIST)
+  @ApiImplicitParams({
+          @ApiImplicitParam(name = QUERY_FIELDS, value = 
QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING,
+                  paramType = PARAM_TYPE_QUERY, defaultValue = 
MpackResourceProvider.MPACK_ID),
+          @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION, 
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, 
allowableValues = QUERY_FROM_VALUES,
+                  defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_INT, 
paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, 
allowableValues = QUERY_TO_VALUES,
+                  dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+  })
+  @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 getClusterSettings(String body, @Context HttpHeaders 
headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET, 
createClusterSettingsResource(null));
+  }
+
+  /**
+   * Handles GET /cluster_settings/{settingName}
+   * Get specific default setting for a cluster.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return service collection resource representation
+   */
+  @GET
+  @Path("{settingName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Returns information about specific read only 'cluster 
settings'",
+          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 getClusterSetting(String body, @Context HttpHeaders headers, 
@Context UriInfo ui,
+                                    @PathParam("settingName") String 
settingName) {
+    return handleRequest(headers, body, ui, Request.Type.GET, 
createClusterSettingsResource(settingName));
+  }
+
+  /**
+   * Create a 'cluster setting' resource instance.
+   *
+   * @return 'cluster setting' resource instance
+   */
+  ResourceInstance createClusterSettingsResource(String settingName) {
+    Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.RootClusterSetting, settingName);
+
+    return createResource(Resource.Type.RootClusterSetting, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 67d3a15..aef7fc1 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
@@ -37,9 +37,9 @@ import 
org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.controller.ComponentDependencyResponse;
 import org.apache.ambari.server.controller.ExtensionLinkResponse;
 import org.apache.ambari.server.controller.QuickLinksResponse;
+import org.apache.ambari.server.controller.ReadOnlyConfigurationResponse;
 import org.apache.ambari.server.controller.StackArtifactResponse;
 import 
org.apache.ambari.server.controller.StackConfigurationDependencyResponse;
-import org.apache.ambari.server.controller.StackConfigurationResponse;
 import org.apache.ambari.server.controller.StackResponse;
 import org.apache.ambari.server.controller.StackServiceArtifactResponse;
 import org.apache.ambari.server.controller.StackServiceComponentResponse;
@@ -223,7 +223,7 @@ public class StacksService extends BaseService {
   @ApiOperation(value = "Get all configurations for a stack version",
       nickname = "StacksService#getStackLevelConfigurations",
       notes = "Returns all configurations for a stack version.",
-      response = 
StackConfigurationResponse.StackConfigurationResponseSwagger.class,
+      response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class,
       responseContainer = RESPONSE_CONTAINER_LIST)
   @ApiImplicitParams({
       @ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned 
attributes",
@@ -261,7 +261,7 @@ public class StacksService extends BaseService {
   @ApiOperation(value = "Get configuration details for a given property",
       nickname = "StacksService#getStackLevelConfiguration",
       notes = "Returns the configuration details for a given property.",
-      response = 
StackConfigurationResponse.StackConfigurationResponseSwagger.class)
+      response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class)
   @ApiImplicitParams({
       @ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned 
attributes",
           defaultValue = "StackLevelConfigurations/*",
@@ -611,7 +611,7 @@ public class StacksService extends BaseService {
   @ApiOperation(value = "Get all configurations for a stack service",
       nickname = "StacksService#getStackConfigurations",
       notes = "Returns all configurations for a stack service.",
-      response = 
StackConfigurationResponse.StackConfigurationResponseSwagger.class,
+      response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class,
       responseContainer = RESPONSE_CONTAINER_LIST)
   @ApiImplicitParams({
       @ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned 
attributes",
@@ -653,7 +653,7 @@ public class StacksService extends BaseService {
   @ApiOperation(value = "Get stack service configuration details",
       nickname = "StacksService#getStackConfiguration",
       notes = "Returns the details of a stack service configuration.",
-      response = 
StackConfigurationResponse.StackConfigurationResponseSwagger.class)
+      response = 
ReadOnlyConfigurationResponse.ReadOnlyConfigurationResponseSwagger.class)
   @ApiImplicitParams({
       @ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned 
attributes",
           defaultValue = "StackConfigurations/*",

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 f2c4c52..ce61497 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
@@ -484,7 +484,7 @@ public interface AmbariManagementController {
    *
    * @throws  AmbariException if the resources cannot be read
    */
-  Set<StackConfigurationResponse> 
getStackConfigurations(Set<StackConfigurationRequest> requests) throws 
AmbariException;
+  Set<ReadOnlyConfigurationResponse> 
getStackConfigurations(Set<StackConfigurationRequest> requests) throws 
AmbariException;
 
 
   /**
@@ -843,7 +843,15 @@ public interface AmbariManagementController {
    * @return
    * @throws AmbariException
    */
-  Set<StackConfigurationResponse> 
getStackLevelConfigurations(Set<StackLevelConfigurationRequest> requests) 
throws AmbariException;
+  Set<ReadOnlyConfigurationResponse> 
getStackLevelConfigurations(Set<StackLevelConfigurationRequest> requests) 
throws AmbariException;
+
+  /**
+   * Get initial settings for a cluster (!not a service).
+   * @param requests
+   * @return
+   * @throws AmbariException
+   */
+  Set<ReadOnlyConfigurationResponse> 
getResourceLevelClusterSettings(Set<RootClusterSettingRequest> requests) throws 
AmbariException;
 
   /**
    * @param serviceInfo service info for a given service

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 188d4d3..28b5c28 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
@@ -4812,17 +4812,17 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
   }
 
   @Override
-  public Set<StackConfigurationResponse> getStackLevelConfigurations(
+  public Set<ReadOnlyConfigurationResponse> getStackLevelConfigurations(
       Set<StackLevelConfigurationRequest> requests) throws AmbariException {
-    Set<StackConfigurationResponse> response = new HashSet<>();
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
     for (StackLevelConfigurationRequest request : requests) {
 
       String stackName    = request.getStackName();
       String stackVersion = request.getStackVersion();
 
-      Set<StackConfigurationResponse> stackConfigurations = 
getStackLevelConfigurations(request);
+      Set<ReadOnlyConfigurationResponse> stackConfigurations = 
getStackLevelConfigurations(request);
 
-      for (StackConfigurationResponse stackConfigurationResponse : 
stackConfigurations) {
+      for (ReadOnlyConfigurationResponse stackConfigurationResponse : 
stackConfigurations) {
         stackConfigurationResponse.setStackName(stackName);
         stackConfigurationResponse.setStackVersion(stackVersion);
       }
@@ -4833,10 +4833,10 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     return response;
   }
 
-  private Set<StackConfigurationResponse> getStackLevelConfigurations(
+  private Set<ReadOnlyConfigurationResponse> getStackLevelConfigurations(
       StackLevelConfigurationRequest request) throws AmbariException {
 
-    Set<StackConfigurationResponse> response = new HashSet<>();
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
 
     String stackName = request.getStackName();
     String stackVersion = request.getStackVersion();
@@ -4856,18 +4856,48 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
   }
 
   @Override
-  public Set<StackConfigurationResponse> getStackConfigurations(
+  public Set<ReadOnlyConfigurationResponse> getResourceLevelClusterSettings(
+          Set<RootClusterSettingRequest> requests) throws AmbariException {
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
+    for (RootClusterSettingRequest request : requests) {
+      Set<ReadOnlyConfigurationResponse> stackConfigurations = 
getResourceLevelClusterSettings(request);
+      response.addAll(stackConfigurations);
+    }
+
+    return response;
+  }
+
+  private Set<ReadOnlyConfigurationResponse> getResourceLevelClusterSettings(
+          RootClusterSettingRequest request) throws AmbariException {
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
+    String propertyName = request.getPropertyName();
+
+    Set<PropertyInfo> properties;
+    if (propertyName != null) {
+      properties = ambariMetaInfo.getClusterPropertiesByName(propertyName);
+    } else {
+      properties = ambariMetaInfo.getClusterProperties();
+    }
+    for (PropertyInfo property : properties) {
+      response.add(property.convertToResponse());
+    }
+    return response;
+  }
+
+
+  @Override
+  public Set<ReadOnlyConfigurationResponse> getStackConfigurations(
       Set<StackConfigurationRequest> requests) throws AmbariException {
-    Set<StackConfigurationResponse> response = new HashSet<>();
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
     for (StackConfigurationRequest request : requests) {
 
       String stackName    = request.getStackName();
       String stackVersion = request.getStackVersion();
       String serviceName  = request.getServiceName();
 
-      Set<StackConfigurationResponse> stackConfigurations = 
getStackConfigurations(request);
+      Set<ReadOnlyConfigurationResponse> stackConfigurations = 
getStackConfigurations(request);
 
-      for (StackConfigurationResponse stackConfigurationResponse : 
stackConfigurations) {
+      for (ReadOnlyConfigurationResponse stackConfigurationResponse : 
stackConfigurations) {
         stackConfigurationResponse.setStackName(stackName);
         stackConfigurationResponse.setStackVersion(stackVersion);
         stackConfigurationResponse.setServiceName(serviceName);
@@ -4879,10 +4909,10 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     return response;
   }
 
-  private Set<StackConfigurationResponse> getStackConfigurations(
+  private Set<ReadOnlyConfigurationResponse> getStackConfigurations(
       StackConfigurationRequest request) throws AmbariException {
 
-    Set<StackConfigurationResponse> response = new HashSet<>();
+    Set<ReadOnlyConfigurationResponse> response = new HashSet<>();
 
     String stackName = request.getStackName();
     String stackVersion = request.getStackVersion();

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 a4339ab..3117186 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
@@ -109,6 +109,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.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
 import org.apache.ambari.server.security.SecurityHelper;
@@ -511,6 +512,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));
 
     bind(RegistryFactory.class).to(RegistryFactoryImpl.class);
     bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/ReadOnlyConfigurationResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ReadOnlyConfigurationResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ReadOnlyConfigurationResponse.java
new file mode 100644
index 0000000..0033ea3
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ReadOnlyConfigurationResponse.java
@@ -0,0 +1,272 @@
+/*
+ * 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;
+import java.util.Set;
+
+import org.apache.ambari.server.state.PropertyDependencyInfo;
+import org.apache.ambari.server.state.PropertyInfo.PropertyType;
+import org.apache.ambari.server.state.ValueAttributesInfo;
+
+import io.swagger.annotations.ApiModelProperty;
+
+
+public class ReadOnlyConfigurationResponse {
+
+  /**
+   * Configuration response.
+   *
+   * @param propertyName        Property Key
+   * @param propertyValue       Property Value
+   * @param propertyDescription Property Description
+   * @param type                Configuration type
+   * @param propertyAttributes  Attributes map
+   */
+  public ReadOnlyConfigurationResponse(String propertyName, String 
propertyValue, String propertyDescription,
+                                       String type, Map<String, String> 
propertyAttributes) {
+    setPropertyName(propertyName);
+    setPropertyValue(propertyValue);
+    setPropertyDescription(propertyDescription);
+    setType(type);
+    setPropertyAttributes(propertyAttributes);
+  }
+
+  /**
+   * Configuration response with all properties.
+   *
+   * @param propertyName            Property Key
+   * @param propertyValue           Property Value
+   * @param propertyDescription     Property Description
+   * @param type                    Configuration type
+   * @param isRequired              Is required to be set
+   * @param propertyTypes           Property Types
+   * @param propertyAttributes      Attributes map
+   * @param propertyValueAttributes Value Attributes
+   * @param dependsOnProperties     depends on properties set
+   */
+  public ReadOnlyConfigurationResponse(String propertyName, String 
propertyValue,
+                                       String propertyDescription, String 
propertyDisplayName, String type,
+                                       Boolean isRequired,
+                                       Set<PropertyType> propertyTypes,
+                                       Map<String, String> propertyAttributes,
+                                       ValueAttributesInfo 
propertyValueAttributes,
+                                       Set<PropertyDependencyInfo> 
dependsOnProperties) {
+    setPropertyName(propertyName);
+    setPropertyValue(propertyValue);
+    setPropertyDescription(propertyDescription);
+    setPropertyDisplayName(propertyDisplayName);
+    setType(type);
+    setRequired(isRequired);
+    setPropertyType(propertyTypes);
+    setPropertyAttributes(propertyAttributes);
+    setPropertyValueAttributes(propertyValueAttributes);
+    setDependsOnProperties(dependsOnProperties);
+  }
+
+  private String stackName;
+  private String stackVersion;
+  private String serviceName;
+  private String propertyName;
+  private String propertyValue;
+  private String propertyDescription;
+  private String propertyDisplayName;
+  private String type;
+  private Map<String, String> propertyAttributes;
+  private ValueAttributesInfo propertyValueAttributes;
+  private Set<PropertyDependencyInfo> dependsOnProperties;
+  private Boolean isRequired;
+  private Set<PropertyType> propertyTypes;
+
+  @ApiModelProperty(name = "stack_name")
+  public String getStackName() {
+    return stackName;
+  }
+
+  public void setStackName(String stackName) {
+    this.stackName = stackName;
+  }
+
+  @ApiModelProperty(name = "stack_version")
+  public String getStackVersion() {
+    return stackVersion;
+  }
+
+  public void setStackVersion(String stackVersion) {
+    this.stackVersion = stackVersion;
+  }
+
+  @ApiModelProperty(name = "service_name")
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  @ApiModelProperty(name = "property_name")
+  public String getPropertyName() {
+    return propertyName;
+  }
+
+  public void setPropertyName(String propertyName) {
+    this.propertyName = propertyName;
+  }
+
+  @ApiModelProperty(name = "property_value")
+  public String getPropertyValue() {
+    return propertyValue;
+  }
+
+  public void setPropertyValue(String propertyValue) {
+    this.propertyValue = propertyValue;
+  }
+
+  @ApiModelProperty(name = "property_description")
+  public String getPropertyDescription() {
+    return propertyDescription;
+  }
+
+  public void setPropertyDescription(String propertyDescription) {
+    this.propertyDescription = propertyDescription;
+  }
+
+  @ApiModelProperty(name = "property_display_name")
+  public String getPropertyDisplayName() {
+    return propertyDisplayName;
+  }
+
+  public void setPropertyDisplayName(String propertyDisplayName) {
+    this.propertyDisplayName = propertyDisplayName;
+  }
+
+  /**
+   * Configuration type
+   *
+   * @return Configuration type (*-site.xml)
+   */
+  public String getType() {
+    return type;
+  }
+
+  @ApiModelProperty(name = "type")
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  /**
+   * Provides attributes of this configuration.
+   *
+   * @return Map of attribute name to attribute value
+   */
+  @ApiModelProperty(hidden = true)
+  public Map<String, String> getPropertyAttributes() {
+    return propertyAttributes;
+  }
+
+  /**
+   * Sets attributes for this configuration.
+   *
+   * @param propertyAttributes Map of attribute name to attribute value
+   */
+  public void setPropertyAttributes(Map<String, String> propertyAttributes) {
+    this.propertyAttributes = propertyAttributes;
+  }
+
+  /**
+   * Provides value attributes of this configuration.
+   *
+   * @return value attributes
+   */
+  @ApiModelProperty(name = "property_value_attributes")
+  public ValueAttributesInfo getPropertyValueAttributes() {
+    return propertyValueAttributes;
+  }
+
+  /**
+   * Sets value attributes for this configuration.
+   *
+   * @param propertyValueAttributes
+   */
+  public void setPropertyValueAttributes(ValueAttributesInfo 
propertyValueAttributes) {
+    this.propertyValueAttributes = propertyValueAttributes;
+  }
+
+  /**
+   * Provides depends on properties of this configuration.
+   *
+   * @return depends on properties set
+   */
+  @ApiModelProperty(name = "dependencies")
+  public Set<PropertyDependencyInfo> getDependsOnProperties() {
+    return dependsOnProperties;
+  }
+
+  /**
+   * Sets depends on properties set for this configuration.
+   *
+   * @param dependsOnProperties
+   */
+  public void setDependsOnProperties(Set<PropertyDependencyInfo> 
dependsOnProperties) {
+    this.dependsOnProperties = dependsOnProperties;
+  }
+
+  /**
+   * Is property a isRequired property
+   *
+   * @return True/False
+   */
+  @ApiModelProperty(hidden = true)
+  public Boolean isRequired() {
+    return isRequired;
+  }
+
+  /**
+   * Set required attribute on this property.
+   *
+   * @param required True/False.
+   */
+  public void setRequired(Boolean required) {
+    this.isRequired = required;
+  }
+
+  /**
+   * Get type of property as set in the stack definition.
+   *
+   * @return Property type.
+   */
+  @ApiModelProperty(name = "property_type")
+  public Set<PropertyType> getPropertyType() {
+    return propertyTypes;
+  }
+
+  public void setPropertyType(Set<PropertyType> propertyTypes) {
+    this.propertyTypes = propertyTypes;
+  }
+
+  /**
+   * Interface to help correct Swagger documentation generation
+   */
+  public interface ReadOnlyConfigurationResponseSwagger extends ApiModel {
+    @ApiModelProperty(name = "ReadOnlyConfigurations")
+    public ReadOnlyConfigurationResponse getStackConfigurationResponse();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/RootClusterSettingRequest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/RootClusterSettingRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/RootClusterSettingRequest.java
new file mode 100644
index 0000000..e86c94d
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/RootClusterSettingRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 RootClusterSettingRequest {
+
+  private String propertyName;
+
+  public RootClusterSettingRequest(String propertyName) {
+    super();
+    setPropertyName(propertyName);
+  }
+
+  public String getPropertyName() {
+    return propertyName;
+  }
+
+  public void setPropertyName(String propertyName) {
+    this.propertyName = propertyName;
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/StackConfigurationResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackConfigurationResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackConfigurationResponse.java
deleted file mode 100644
index fb31c19..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackConfigurationResponse.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.controller;
-
-
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.ambari.server.state.PropertyDependencyInfo;
-import org.apache.ambari.server.state.PropertyInfo.PropertyType;
-import org.apache.ambari.server.state.ValueAttributesInfo;
-
-import io.swagger.annotations.ApiModelProperty;
-
-
-public class StackConfigurationResponse {
-
-  /**
-   * Stack configuration response.
-   * @param propertyName Property Key
-   * @param propertyValue Property Value
-   * @param propertyDescription Property Description
-   * @param type Configuration type
-   * @param propertyAttributes Attributes map
-   */
-  public StackConfigurationResponse(String propertyName, String propertyValue, 
String propertyDescription,
-                                    String type, Map<String, String> 
propertyAttributes) {
-    setPropertyName(propertyName);
-    setPropertyValue(propertyValue);
-    setPropertyDescription(propertyDescription);
-    setType(type);
-    setPropertyAttributes(propertyAttributes);
-  }
-
-  /**
-   * Stack configuration response with all properties.
-   * @param propertyName Property Key
-   * @param propertyValue Property Value
-   * @param propertyDescription Property Description
-   * @param type Configuration type
-   * @param isRequired Is required to be set
-   * @param propertyTypes Property Types
-   * @param propertyAttributes Attributes map
-   * @param propertyValueAttributes Value Attributes
-   * @param dependsOnProperties depends on properties set
-   */
-  public StackConfigurationResponse(String propertyName, String propertyValue,
-                                    String propertyDescription, String 
propertyDisplayName, String type,
-                                    Boolean isRequired,
-                                    Set<PropertyType> propertyTypes,
-                                    Map<String, String> propertyAttributes,
-                                    ValueAttributesInfo 
propertyValueAttributes,
-                                    Set<PropertyDependencyInfo> 
dependsOnProperties) {
-    setPropertyName(propertyName);
-    setPropertyValue(propertyValue);
-    setPropertyDescription(propertyDescription);
-    setPropertyDisplayName(propertyDisplayName);
-    setType(type);
-    setRequired(isRequired);
-    setPropertyType(propertyTypes);
-    setPropertyAttributes(propertyAttributes);
-    setPropertyValueAttributes(propertyValueAttributes);
-    setDependsOnProperties(dependsOnProperties);
-  }
-
-  private String stackName;
-  private String stackVersion;
-  private String serviceName;
-  private String propertyName;
-  private String propertyValue;
-  private String propertyDescription;
-  private String propertyDisplayName;
-  private String type;
-  private Map<String, String> propertyAttributes;
-  private ValueAttributesInfo propertyValueAttributes;
-  private Set<PropertyDependencyInfo> dependsOnProperties;
-  private Boolean isRequired;
-  private Set<PropertyType> propertyTypes;
-
-  @ApiModelProperty(name = "stack_name")
-  public String getStackName() {
-    return stackName;
-  }
-
-  public void setStackName(String stackName) {
-    this.stackName = stackName;
-  }
-
-  @ApiModelProperty(name = "stack_version")
-  public String getStackVersion() {
-    return stackVersion;
-  }
-
-  public void setStackVersion(String stackVersion) {
-    this.stackVersion = stackVersion;
-  }
-
-  @ApiModelProperty(name = "service_name")
-  public String getServiceName() {
-    return serviceName;
-  }
-
-  public void setServiceName(String serviceName) {
-    this.serviceName = serviceName;
-  }
-
-  @ApiModelProperty(name = "property_name")
-  public String getPropertyName() {
-    return propertyName;
-  }
-
-  public void setPropertyName(String propertyName) {
-    this.propertyName = propertyName;
-  }
-
-  @ApiModelProperty(name = "property_value")
-  public String getPropertyValue() {
-    return propertyValue;
-  }
-
-  public void setPropertyValue(String propertyValue) {
-    this.propertyValue = propertyValue;
-  }
-
-  @ApiModelProperty(name = "property_description")
-  public String getPropertyDescription() {
-    return propertyDescription;
-  }
-
-  public void setPropertyDescription(String propertyDescription) {
-    this.propertyDescription = propertyDescription;
-  }
-
-  @ApiModelProperty(name = "property_display_name")
-  public String getPropertyDisplayName() {
-    return propertyDisplayName;
-  }
-
-  public void setPropertyDisplayName(String propertyDisplayName) {
-    this.propertyDisplayName = propertyDisplayName;
-  }
-
-  /**
-   * Configuration type
-   * @return Configuration type (*-site.xml)
-   */
-  public String getType() {
-    return type;
-  }
-
-  @ApiModelProperty(name = "type")
-  public void setType(String type) {
-    this.type = type;
-  }
-
-  /**
-   * Provides attributes of this configuration.
-   *
-   * @return Map of attribute name to attribute value
-   */
-  @ApiModelProperty(hidden = true)
-  public Map<String, String> getPropertyAttributes() {
-    return propertyAttributes;
-  }
-
-  /**
-   * Sets attributes for this configuration.
-   *
-   * @param propertyAttributes Map of attribute name to attribute value
-   */
-  public void setPropertyAttributes(Map<String, String> propertyAttributes) {
-    this.propertyAttributes = propertyAttributes;
-  }
-
-  /**
-   * Provides value attributes of this configuration.
-   *
-   * @return value attributes
-   */
-  @ApiModelProperty(name = "property_value_attributes")
-  public ValueAttributesInfo getPropertyValueAttributes() {
-    return propertyValueAttributes;
-  }
-
-  /**
-   * Sets value attributes for this configuration.
-   *
-   * @param propertyValueAttributes
-   */
-  public void setPropertyValueAttributes(ValueAttributesInfo 
propertyValueAttributes) {
-    this.propertyValueAttributes = propertyValueAttributes;
-  }
-
-  /**
-   * Provides depends on properties of this configuration.
-   *
-   * @return depends on properties set
-   */
-  @ApiModelProperty(name = "dependencies")
-  public Set<PropertyDependencyInfo> getDependsOnProperties() {
-    return dependsOnProperties;
-  }
-
-  /**
-   * Sets depends on properties set for this configuration.
-   *
-   * @param dependsOnProperties
-   */
-  public void setDependsOnProperties(Set<PropertyDependencyInfo> 
dependsOnProperties) {
-    this.dependsOnProperties = dependsOnProperties;
-  }
-
-  /**
-   * Is property a isRequired property
-   * @return True/False
-   */
-  @ApiModelProperty(hidden = true)
-  public Boolean isRequired() {
-    return isRequired;
-  }
-
-  /**
-   * Set required attribute on this property.
-   * @param required True/False.
-   */
-  public void setRequired(Boolean required) {
-    this.isRequired = required;
-  }
-
-  /**
-   * Get type of property as set in the stack definition.
-   * @return Property type.
-   */
-  @ApiModelProperty(name = "property_type")
-  public Set<PropertyType> getPropertyType() {
-    return propertyTypes;
-  }
-
-  public void setPropertyType(Set<PropertyType> propertyTypes) {
-    this.propertyTypes = propertyTypes;
-  }
-
-  /**
-   * Interface to help correct Swagger documentation generation
-   */
-  public interface StackConfigurationResponseSwagger extends ApiModel {
-    @ApiModelProperty(name = "StackConfigurations")
-    public StackConfigurationResponse getStackConfigurationResponse();
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
index ea67207..70678ad 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationRequest.java
@@ -39,4 +39,4 @@ public class StackLevelConfigurationRequest extends 
StackVersionRequest {
     this.propertyName = propertyName;
   }
 
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
index d33b5cb..a962466 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackLevelConfigurationResponse.java
@@ -26,20 +26,20 @@ import 
org.apache.ambari.server.state.PropertyDependencyInfo;
 import org.apache.ambari.server.state.PropertyInfo.PropertyType;
 import org.apache.ambari.server.state.ValueAttributesInfo;
 
-public class StackLevelConfigurationResponse extends 
StackConfigurationResponse {
+public class StackLevelConfigurationResponse extends 
ReadOnlyConfigurationResponse {
   public StackLevelConfigurationResponse(String propertyName,
-      String propertyValue, String propertyDescription, String 
propertyDisplayName, String type,
-      Boolean isRequired, Set<PropertyType> propertyTypes,
-      Map<String, String> propertyAttributes,
-      ValueAttributesInfo propertyValueAttributes,
-      Set<PropertyDependencyInfo> dependsOnProperties) {
+                                         String propertyValue, String 
propertyDescription, String propertyDisplayName, String type,
+                                         Boolean isRequired, Set<PropertyType> 
propertyTypes,
+                                         Map<String, String> 
propertyAttributes,
+                                         ValueAttributesInfo 
propertyValueAttributes,
+                                         Set<PropertyDependencyInfo> 
dependsOnProperties) {
     super(propertyName, propertyValue, propertyDescription, 
propertyDisplayName, type, isRequired,
-        propertyTypes, propertyAttributes, propertyValueAttributes,
-        dependsOnProperties);
+            propertyTypes, propertyAttributes, propertyValueAttributes,
+            dependsOnProperties);
   }
-  
+
   public StackLevelConfigurationResponse(String propertyName, String 
propertyValue, String propertyDescription,
-      String type, Map<String, String> propertyAttributes) {
+                                         String type, Map<String, String> 
propertyAttributes) {
     super(propertyName, propertyValue, propertyDescription, type, 
propertyAttributes);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/StackV2.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackV2.java 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackV2.java
index 8a2208d..a6d8979 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackV2.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackV2.java
@@ -670,14 +670,14 @@ public class StackV2 {
     serviceConfigurations.put(service, mapServiceConfig);
     requiredServiceConfigurations.put(service, mapRequiredServiceConfig);
 
-    Set<StackConfigurationResponse> serviceConfigs = 
controller.getStackConfigurations(
+    Set<ReadOnlyConfigurationResponse> serviceConfigs = 
controller.getStackConfigurations(
         Collections.singleton(new StackConfigurationRequest(name, version, 
service, null)));
-    Set<StackConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
+    Set<ReadOnlyConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
         Collections.singleton(new StackLevelConfigurationRequest(name, 
version, null)));
     serviceConfigs.addAll(stackLevelConfigs);
 
     // shouldn't have any required properties in stack level configuration
-    for (StackConfigurationResponse config : serviceConfigs) {
+    for (ReadOnlyConfigurationResponse config : serviceConfigs) {
       ConfigProperty configProperty = new ConfigProperty(config);
       String type = configProperty.getType();
 
@@ -711,10 +711,10 @@ public class StackV2 {
 
   private void parseStackConfigurations () throws AmbariException {
 
-    Set<StackConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
+    Set<ReadOnlyConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
         Collections.singleton(new StackLevelConfigurationRequest(name, 
version, null)));
 
-    for (StackConfigurationResponse config : stackLevelConfigs) {
+    for (ReadOnlyConfigurationResponse config : stackLevelConfigs) {
       ConfigProperty configProperty = new ConfigProperty(config);
       String type = configProperty.getType();
 
@@ -759,7 +759,7 @@ public class StackV2 {
     private Set<PropertyDependencyInfo> dependsOnProperties =
       Collections.emptySet();
 
-    public ConfigProperty(StackConfigurationResponse config) {
+    public ConfigProperty(ReadOnlyConfigurationResponse config) {
       this.name = config.getPropertyName();
       this.value = config.getPropertyValue();
       this.attributes = config.getPropertyAttributes();

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 84df08a..b8c1674 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
@@ -196,6 +196,8 @@ 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(propertyIds, keyPropertyIds, 
managementController);
       case ClusterStackVersion:

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootClusterSettingsResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootClusterSettingsResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootClusterSettingsResourceProvider.java
new file mode 100644
index 0000000..1488672
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootClusterSettingsResourceProvider.java
@@ -0,0 +1,167 @@
+/*
+ * 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.RootClusterSettingRequest;
+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 RootClusterSettingsResourceProvider extends 
ReadOnlyResourceProvider {
+
+  public static final String RESPONSE_KEY = "ClusterSettingsInfo";
+  public static final String ALL_PROPERTIES = RESPONSE_KEY + 
PropertyHelper.EXTERNAL_PATH_SEP + "*";
+
+  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 'cluster_setting' resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new 
HashMap<>();
+
+  /**
+   * The property ids for an 'cluster_setting' resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+  static {
+    // properties
+    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.RootClusterSetting, PROPERTY_NAME_PROPERTY_ID);
+  }
+
+  protected RootClusterSettingsResourceProvider(@Assisted 
AmbariManagementController managementController) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+          throws SystemException, UnsupportedPropertyException,
+          NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<RootClusterSettingRequest> 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().getResourceLevelClusterSettings(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<>();
+
+    for (ReadOnlyConfigurationResponse response : responses) {
+      Resource resource = new ResourceImpl(Type.RootClusterSetting);
+
+      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 RootClusterSettingRequest getRequest(Map<String, Object> properties) 
{
+    return new RootClusterSettingRequest((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/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
index f8feef2..16907a1 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
@@ -27,8 +27,8 @@ 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.StackConfigurationResponse;
 import org.apache.ambari.server.controller.StackLevelConfigurationRequest;
 import org.apache.ambari.server.controller.StackServiceComponentRequest;
 import org.apache.ambari.server.controller.StackServiceComponentResponse;
@@ -668,14 +668,14 @@ public class Stack {
     serviceConfigurations.put(service, mapServiceConfig);
     requiredServiceConfigurations.put(service, mapRequiredServiceConfig);
 
-    Set<StackConfigurationResponse> serviceConfigs = 
controller.getStackConfigurations(
+    Set<ReadOnlyConfigurationResponse> serviceConfigs = 
controller.getStackConfigurations(
         Collections.singleton(new StackConfigurationRequest(name, version, 
service, null)));
-    Set<StackConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
+    Set<ReadOnlyConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
         Collections.singleton(new StackLevelConfigurationRequest(name, 
version, null)));
     serviceConfigs.addAll(stackLevelConfigs);
 
     // shouldn't have any required properties in stack level configuration
-    for (StackConfigurationResponse config : serviceConfigs) {
+    for (ReadOnlyConfigurationResponse config : serviceConfigs) {
       ConfigProperty configProperty = new ConfigProperty(config);
       String type = configProperty.getType();
 
@@ -709,10 +709,10 @@ public class Stack {
 
   private void parseStackConfigurations () throws AmbariException {
 
-    Set<StackConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
+    Set<ReadOnlyConfigurationResponse> stackLevelConfigs = 
controller.getStackLevelConfigurations(
         Collections.singleton(new StackLevelConfigurationRequest(name, 
version, null)));
 
-    for (StackConfigurationResponse config : stackLevelConfigs) {
+    for (ReadOnlyConfigurationResponse config : stackLevelConfigs) {
       ConfigProperty configProperty = new ConfigProperty(config);
       String type = configProperty.getType();
 
@@ -757,7 +757,7 @@ public class Stack {
     private Set<PropertyDependencyInfo> dependsOnProperties =
       Collections.emptySet();
 
-    public ConfigProperty(StackConfigurationResponse config) {
+    public ConfigProperty(ReadOnlyConfigurationResponse config) {
       this.name = config.getPropertyName();
       this.value = config.getPropertyValue();
       this.attributes = config.getPropertyAttributes();

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackConfigurationResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackConfigurationResourceProvider.java
index 6f5b0f8..b0b1db0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackConfigurationResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackConfigurationResourceProvider.java
@@ -27,8 +27,8 @@ 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.StackConfigurationResponse;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -108,16 +108,16 @@ public class StackConfigurationResourceProvider extends
 
     Set<String> requestedIds = getRequestPropertyIds(request, predicate);
 
-    Set<StackConfigurationResponse> responses = getResources(new 
Command<Set<StackConfigurationResponse>>() {
+    Set<ReadOnlyConfigurationResponse> responses = getResources(new 
Command<Set<ReadOnlyConfigurationResponse>>() {
       @Override
-      public Set<StackConfigurationResponse> invoke() throws AmbariException {
+      public Set<ReadOnlyConfigurationResponse> invoke() throws 
AmbariException {
         return getManagementController().getStackConfigurations(requests);
       }
     });
 
     Set<Resource> resources = new HashSet<>();
     
-    for (StackConfigurationResponse response : responses) {
+    for (ReadOnlyConfigurationResponse response : responses) {
       Resource resource = new ResourceImpl(Resource.Type.StackConfiguration);
 
       setResourceProperty(resource, STACK_NAME_PROPERTY_ID,

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
index 819507b..361f80a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackLevelConfigurationResourceProvider.java
@@ -27,7 +27,7 @@ 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.ReadOnlyConfigurationResponse;
 import org.apache.ambari.server.controller.StackLevelConfigurationRequest;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -105,16 +105,16 @@ public class StackLevelConfigurationResourceProvider 
extends
 
     Set<String> requestedIds = getRequestPropertyIds(request, predicate);
 
-    Set<StackConfigurationResponse> responses = getResources(new 
Command<Set<StackConfigurationResponse>>() {
+    Set<ReadOnlyConfigurationResponse> responses = getResources(new 
Command<Set<ReadOnlyConfigurationResponse>>() {
       @Override
-      public Set<StackConfigurationResponse> invoke() throws AmbariException {
+      public Set<ReadOnlyConfigurationResponse> invoke() throws 
AmbariException {
         return getManagementController().getStackLevelConfigurations(requests);
       }
     });
 
     Set<Resource> resources = new HashSet<>();
     
-    for (StackConfigurationResponse response : responses) {
+    for (ReadOnlyConfigurationResponse response : responses) {
       Resource resource = new 
ResourceImpl(Resource.Type.StackLevelConfiguration);
 
       setResourceProperty(resource, STACK_NAME_PROPERTY_ID,

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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 a364c4c..6a76fff 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
@@ -75,6 +75,7 @@ public interface Resource {
    */
   enum InternalType {
     Cluster,
+    RootClusterSetting,
     Service,
     ServiceGroup,
     Setting,
@@ -204,6 +205,7 @@ public interface Resource {
      * Internal types.  See {@link InternalType}.
      */
     public static final Type Cluster = InternalType.Cluster.getType();
+    public static final Type RootClusterSetting = 
InternalType.RootClusterSetting.getType();
     public static final Type ServiceGroup = 
InternalType.ServiceGroup.getType();
     public static final Type Service = InternalType.Service.getType();
     public static final Type Setting = InternalType.Setting.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/8d8c1a55/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
new file mode 100644
index 0000000..4cb6cd9
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManager.java
@@ -0,0 +1,168 @@
+/**
+ * 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/8d8c1a55/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
new file mode 100644
index 0000000..fcda654
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/resources/ResourceLevelClusterSettingManagerFactory.java
@@ -0,0 +1,34 @@
+/**
+ * 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/8d8c1a55/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index eade914..58b0300 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -89,6 +89,7 @@ public class ConfigHelper {
   public static final String HIVE_SITE = "hive-site";
   public static final String YARN_SITE = "yarn-site";
   public static final String CLUSTER_ENV = "cluster-env";
+  public static final String CLUSTER_SETTINGS = "cluster-settings";
   public static final String CLUSTER_ENV_ALERT_REPEAT_TOLERANCE = 
"alerts_repeat_tolerance";
   public static final String CLUSTER_ENV_RETRY_ENABLED = 
"command_retry_enabled";
   public static final String SERVICE_CHECK_TYPE = "service_check_type";

Reply via email to