You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2017/11/10 22:20:08 UTC

[1/2] ambari git commit: AMBARI-22366. POST, GET and UPDATE API for cluster settings. (/clusters/{clusterName}/settings).

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714 b558eda2d -> 495920689


http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index f12759e..77bf62b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -24,6 +24,8 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
+
+import org.apache.ambari.server.ClusterSettingNotFoundException;
 import org.apache.ambari.server.ServiceGroupNotFoundException;
 import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
@@ -98,6 +100,36 @@ public interface Cluster {
 
   ServiceGroup addServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException;
 
+
+  ClusterSetting addClusterSetting(String clusterSettingName, String clusterSettingValue) throws AmbariException;
+
+  /**
+   * Add 'cluster setting' to the cluster
+   *
+   * @param clusterSetting
+   * @return
+   * @throws AmbariException
+   */
+  void addClusterSetting(ClusterSetting clusterSetting);
+
+  /**
+   * Update 'cluster setting' in the cluster
+   *
+   * @param clusterSettingName Cluster setting name
+   * @return
+   * @throws AmbariException
+   */
+  ClusterSetting updateClusterSetting(String clusterSettingName, String clusterSettingValue) throws AmbariException;
+
+  /**
+   * Add 'cluster setting' in the cluster
+   *
+   * @param clusterSetting
+   * @return
+   * @throws AmbariException
+   */
+  void updateClusterSetting(ClusterSetting clusterSetting);
+
   //TODO remove when UI starts using service groups
   /**
    * Get a service
@@ -153,6 +185,29 @@ public interface Cluster {
   Map<String, ServiceGroup> getServiceGroups() throws AmbariException;
 
   /**
+   * Get a cluster setting
+   *
+   * @param clusterSettingName
+   * @return
+   */
+  ClusterSetting getClusterSetting(String clusterSettingName) throws ClusterSettingNotFoundException;
+
+  /**
+   * Get a cluster setting
+   *
+   * @param clusterSettingId
+   * @return
+   */
+  ClusterSetting getClusterSetting(Long clusterSettingId) throws ClusterSettingNotFoundException;
+
+  /**
+   * Get all cluster settings
+   *
+   * @return
+   */
+  Map<String, ClusterSetting> getClusterSettings() throws AmbariException;
+
+  /**
    * Get all ServiceComponentHosts on a given host
    *
    * @param hostname
@@ -562,6 +617,21 @@ public interface Cluster {
   void deleteServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException;
 
   /**
+   * Delete all the cluster settings associated with this cluster
+   *
+   * @throws AmbariException
+   */
+  void deleteAllClusterSettings() throws AmbariException;
+
+  /**
+   * Delete the named cluster setting associated with this cluster
+   *
+   * @param clusterSettingName
+   * @throws AmbariException
+   */
+  void deleteClusterSetting(String clusterSettingName) throws AmbariException;
+
+  /**
    * Gets if the cluster can be deleted
    *
    * @return

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSetting.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSetting.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSetting.java
new file mode 100644
index 0000000..0a10907
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSetting.java
@@ -0,0 +1,56 @@
+/**
+ * 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.state;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.ClusterSettingResponse;
+
+public interface ClusterSetting {
+
+    Long getClusterSettingId();
+
+    String getClusterSettingValue();
+
+    void setClusterSettingValue(String clusterSettingValue);
+
+    String getClusterSettingName();
+
+    void setClusterSettingName(String clusterSettingName);
+
+    long getClusterId();
+
+    Cluster getCluster();
+
+    ClusterSettingResponse convertToResponse();
+
+    void debugDump(StringBuilder sb);
+
+    void refresh();
+
+    /**
+     * Find out whether the cluster setting are in a state that
+     * it can be removed from a cluster.
+     *
+     * @return
+     */
+    boolean canBeRemoved();
+
+    void delete() throws AmbariException;
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingFactory.java
new file mode 100644
index 0000000..8b95cf5
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingFactory.java
@@ -0,0 +1,33 @@
+/**
+ * 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.state;
+
+import org.apache.ambari.server.orm.entities.ClusterSettingEntity;
+
+import com.google.inject.assistedinject.Assisted;
+
+public interface ClusterSettingFactory {
+
+    ClusterSetting createNew(Cluster cluster,
+                           @Assisted("clusterSettingName") String clusterSettingName,
+                           @Assisted("clusterSettingValue") String clusterSettingValue);
+
+    ClusterSetting createExisting(Cluster cluster,
+                           ClusterSettingEntity clusterSettingEntity);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingImpl.java
new file mode 100644
index 0000000..8a9fab8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ClusterSettingImpl.java
@@ -0,0 +1,201 @@
+/**
+ * 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.state;
+
+
+import org.apache.ambari.server.AmbariException;
+
+import org.apache.ambari.server.controller.ClusterSettingResponse;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ClusterSettingDAO;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ClusterSettingEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import com.google.inject.persist.Transactional;
+
+
+public class ClusterSettingImpl implements ClusterSetting {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClusterSettingImpl.class);
+
+    private final Cluster cluster;
+
+    private final ClusterDAO clusterDAO;
+    private final ClusterSettingDAO clusterSettingDAO;
+    private final AmbariEventPublisher eventPublisher;
+
+    private Long clusterSettingId;
+    private String clusterSettingName;
+    private String clusterSettingValue;
+
+    @AssistedInject
+    public ClusterSettingImpl(@Assisted Cluster cluster,
+                            @Assisted("clusterSettingName") String clusterSettingName,
+                            @Assisted("clusterSettingValue") String clusterSettingValue,
+                            ClusterDAO clusterDAO,
+                            ClusterSettingDAO clusterSettingDAO,
+                            AmbariEventPublisher eventPublisher) throws AmbariException {
+
+        this.cluster = cluster;
+        this.clusterDAO = clusterDAO;
+        this.clusterSettingDAO = clusterSettingDAO;
+        this.eventPublisher = eventPublisher;
+
+        this.clusterSettingName = clusterSettingName;
+        this.clusterSettingValue = clusterSettingValue;
+
+        ClusterSettingEntity clusterSettingEntity = new ClusterSettingEntity();
+        clusterSettingEntity.setClusterId(cluster.getClusterId());
+        clusterSettingEntity.setClusterSettingId(clusterSettingId);
+        clusterSettingEntity.setClusterSettingName(clusterSettingName);
+        clusterSettingEntity.setClusterSettingValue(clusterSettingValue);
+
+        persist(clusterSettingEntity);
+    }
+
+    @AssistedInject
+    public ClusterSettingImpl(@Assisted Cluster cluster,
+                            @Assisted ClusterSettingEntity clusterSettingEntity,
+                            ClusterDAO clusterDAO,
+                            ClusterSettingDAO clusterSettingDAO,
+                            AmbariEventPublisher eventPublisher) throws AmbariException {
+        this.cluster = cluster;
+        this.clusterDAO = clusterDAO;
+        this.clusterSettingDAO = clusterSettingDAO;
+        this.eventPublisher = eventPublisher;
+
+        this.clusterSettingId = clusterSettingEntity.getClusterSettingId();
+        this.clusterSettingName = clusterSettingEntity.getClusterSettingName();
+        this.clusterSettingValue = clusterSettingEntity.getClusterSettingValue();
+
+        clusterSettingDAO.merge(clusterSettingEntity);
+    }
+
+    @Override
+    public Long getClusterSettingId() {
+        return clusterSettingId;
+    }
+
+    @Override
+    public String getClusterSettingName() {
+        return clusterSettingName;
+    }
+
+    @Override
+    public void setClusterSettingName(String clusterSettingName) {
+        ClusterSettingEntity entity = getClusterSettingEntity();
+        entity.setClusterSettingName(clusterSettingName);
+        clusterSettingDAO.merge(entity);
+        this.clusterSettingName = clusterSettingName;
+    }
+
+    @Override
+    public String getClusterSettingValue() {
+        return clusterSettingValue;
+    }
+
+    @Override
+    public void setClusterSettingValue(String clusterSettingValue) {
+        ClusterSettingEntity entity = getClusterSettingEntity();
+        entity.setClusterSettingValue(clusterSettingValue);
+        clusterSettingDAO.merge(entity);
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+    @Override
+    public long getClusterId() {
+        return cluster.getClusterId();
+    }
+
+    @Override
+    public ClusterSettingResponse convertToResponse() {
+        ClusterSettingResponse r = new ClusterSettingResponse(cluster.getClusterId(),
+                cluster.getClusterName(), getClusterSettingId(), getClusterSettingName(), getClusterSettingValue());
+        return r;
+    }
+
+    @Override
+    public Cluster getCluster() {
+        return cluster;
+    }
+
+    @Override
+    public void debugDump(StringBuilder sb) {
+        sb.append("ClusterSetting={ clusterSettingName=").append(getClusterSettingName())
+                .append(", clusterSettingValue=").append(getClusterSettingValue())
+                .append(", clusterName=").append(cluster.getClusterName())
+                .append(", clusterId=").append(cluster.getClusterId())
+                .append(" }");
+    }
+
+    private void persist(ClusterSettingEntity clusterSettingEntity) {
+        persistEntities(clusterSettingEntity);
+        refresh();
+
+        cluster.addClusterSetting(this);
+    }
+
+    @Transactional
+    protected void persistEntities(ClusterSettingEntity clusterSettingEntity) {
+        long clusterId = cluster.getClusterId();
+
+        ClusterEntity clusterEntity = clusterDAO.findById(clusterId);
+        clusterSettingEntity.setClusterEntity(clusterEntity);
+        clusterSettingDAO.create(clusterSettingEntity);
+        clusterSettingId = clusterSettingEntity.getClusterSettingId();
+        clusterEntity.getClusterSettingEntities().add(clusterSettingEntity);
+        clusterDAO.merge(clusterEntity);
+        clusterSettingDAO.merge(clusterSettingEntity);
+    }
+
+    @Override
+    @Transactional
+    public void refresh() {
+        ClusterSettingEntity clusterSettingEntity = clusterSettingDAO.findByPK(clusterSettingId);
+        clusterSettingDAO.refresh(clusterSettingEntity);
+    }
+
+    @Override
+    public boolean canBeRemoved() {
+        // TODO: Add check logic
+        return true;
+    }
+
+
+    @Override
+    @Transactional
+    public void delete() throws AmbariException {
+        removeEntities();
+    }
+
+    @Transactional
+    protected void removeEntities() throws AmbariException {
+        clusterSettingDAO.removeByPK(clusterSettingId);
+    }
+
+    // Refresh the cached reference on setters
+    private ClusterSettingEntity getClusterSettingEntity() {
+        return clusterSettingDAO.findByPK(clusterSettingId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
index 7737c0d..f12128f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
@@ -46,7 +46,7 @@ import com.google.inject.persist.Transactional;
 
 public class ServiceGroupImpl implements ServiceGroup {
 
-  private static final Logger LOG = LoggerFactory.getLogger(ServiceImpl.class);
+  private static final Logger LOG = LoggerFactory.getLogger(ServiceGroupImpl.class);
 
   private ServiceGroupEntityPK serviceGroupEntityPK;
 
@@ -231,8 +231,6 @@ public class ServiceGroupImpl implements ServiceGroup {
   }
 
   /**
-   * {@inheritDoc}
-   * <p/>
    * This method uses Java locks and then delegates to internal methods which
    * perform the JPA merges inside of a transaction. Because of this, a
    * transaction is not necessary before this calling this method.

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 78201f0..dcead7a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -44,6 +44,7 @@ import javax.persistence.RollbackException;
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterSettingNotFoundException;
 import org.apache.ambari.server.ConfigGroupNotFoundException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
@@ -78,6 +79,7 @@ import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterServiceDAO;
+import org.apache.ambari.server.orm.dao.ClusterSettingDAO;
 import org.apache.ambari.server.orm.dao.ClusterStateDAO;
 import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
@@ -90,6 +92,7 @@ import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
+import org.apache.ambari.server.orm.entities.ClusterSettingEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
@@ -109,6 +112,8 @@ import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ClusterHealthReport;
+import org.apache.ambari.server.state.ClusterSetting;
+import org.apache.ambari.server.state.ClusterSettingFactory;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigFactory;
@@ -180,9 +185,14 @@ public class ClusterImpl implements Cluster {
   private final ConcurrentSkipListMap<String, Service> services = new ConcurrentSkipListMap<>();
   private final ConcurrentSkipListMap<Long, Service> servicesById = new ConcurrentSkipListMap<>();
 
+  // Service groups
   private Map<String, ServiceGroup> serviceGroups = new ConcurrentSkipListMap<>();
   private final Map<Long, ServiceGroup> serviceGroupsById = new ConcurrentSkipListMap<>();
 
+  // Cluster settings
+  private Map<String, ClusterSetting> clusterSettings = new ConcurrentSkipListMap<>();
+  private final Map<Long, ClusterSetting> clusterSettingsById = new ConcurrentSkipListMap<>();
+
   /**
    * [ Config Type -> [ Config Version Tag -> Config ] ]
    */
@@ -241,6 +251,9 @@ public class ClusterImpl implements Cluster {
   private ServiceGroupFactory serviceGroupFactory;
 
   @Inject
+  private ClusterSettingFactory clusterSettingFactory;
+
+  @Inject
   private ConfigFactory configFactory;
 
   @Inject
@@ -288,6 +301,9 @@ public class ClusterImpl implements Cluster {
   @Inject
   private ClusterServiceDAO clusterServiceDAO;
 
+  @Inject
+  private ClusterSettingDAO clusterSettingDAO;
+
   /**
    * Data access object used for looking up stacks from the database.
    */
@@ -344,6 +360,7 @@ public class ClusterImpl implements Cluster {
 
     loadStackVersion();
     loadServiceGroups();
+    loadClusterSettings();
     loadServices();
     loadServiceHostComponents();
 
@@ -479,6 +496,17 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  private void loadClusterSettings() {
+    ClusterEntity clusterEntity = getClusterEntity();
+    if (!clusterEntity.getClusterSettingEntities().isEmpty()) {
+      for (ClusterSettingEntity clusterSettingEntity : clusterEntity.getClusterSettingEntities()) {
+        ClusterSetting cs = clusterSettingFactory.createExisting(this, clusterSettingEntity);
+        clusterSettings.put(clusterSettingEntity.getClusterSettingName(), cs);
+        clusterSettingsById.put(clusterSettingEntity.getClusterSettingId(), cs);
+      }
+    }
+  }
+
   private void loadConfigGroups() {
     ClusterEntity clusterEntity = getClusterEntity();
     if (!clusterEntity.getConfigGroupEntities().isEmpty()) {
@@ -995,8 +1023,8 @@ public class ClusterImpl implements Cluster {
   public void addServiceGroup(ServiceGroup serviceGroup) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("Adding a new service group" + ", clusterName=" + getClusterName()
-        + ", clusterId=" + getClusterId() + ", serviceGroupName="
-        + serviceGroup.getServiceGroupName());
+              + ", clusterId=" + getClusterId() + ", serviceGroupName="
+              + serviceGroup.getServiceGroupName());
     }
     serviceGroups.put(serviceGroup.getServiceGroupName(), serviceGroup);
     serviceGroupsById.put(serviceGroup.getServiceGroupId(), serviceGroup);
@@ -1006,7 +1034,7 @@ public class ClusterImpl implements Cluster {
   public ServiceGroup addServiceGroup(String serviceGroupName) throws AmbariException {
     if (serviceGroups.containsKey(serviceGroupName)) {
       throw new AmbariException("Service group already exists" + ", clusterName=" + getClusterName()
-        + ", clusterId=" + getClusterId() + ", serviceGroupName=" + serviceGroupName);
+              + ", clusterId=" + getClusterId() + ", serviceGroupName=" + serviceGroupName);
     }
 
     ServiceGroup serviceGroup = serviceGroupFactory.createNew(this, serviceGroupName, new HashSet<ServiceGroupKey>());
@@ -1051,6 +1079,55 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public void addClusterSetting(ClusterSetting clusterSetting) {
+    LOG.debug("Adding a new cluster setting, clusterName= {}, clusterId : {}, " +
+            "clusterSettingName : {}", getClusterName(), getClusterId(),
+            clusterSetting.getClusterSettingName());
+
+    clusterSettings.put(clusterSetting.getClusterSettingName(), clusterSetting);
+    clusterSettingsById.put(clusterSetting.getClusterSettingId(), clusterSetting);
+  }
+
+  @Override
+  public ClusterSetting addClusterSetting(String clusterSettingName, String clusterSettingValue) throws AmbariException {
+    if (clusterSettings.containsKey(clusterSettingName)) {
+      throw new AmbariException("'Cluster Setting' already exists" + ", clusterName=" + getClusterName()
+              + ", clusterId=" + getClusterId() + ", clusterSettingName=" + clusterSettingName);
+    }
+
+    ClusterSetting clusterSetting = clusterSettingFactory.createNew(this, clusterSettingName, clusterSettingValue);
+    addClusterSetting(clusterSetting);
+    return clusterSetting;
+  }
+
+
+  @Override
+  public void updateClusterSetting(ClusterSetting clusterSetting) {
+    LOG.debug("Updating cluster setting, clusterName= {}, clusterId : {}, " +
+            "clusterSettingName : {}", getClusterName(), getClusterId(), clusterSetting.getClusterSettingName());
+
+    // Update the changed 'clusterSetting' in the below maps, to reflect object with newest changes.
+    clusterSettings.put(clusterSetting.getClusterSettingName(), clusterSetting);
+    clusterSettingsById.put(clusterSetting.getClusterSettingId(), clusterSetting);
+  }
+
+  @Override
+  public ClusterSetting updateClusterSetting(String clusterSettingName, String clusterSettingValue) throws AmbariException {
+    if (!clusterSettings.containsKey(clusterSettingName)) {
+      throw new AmbariException("'ClusterSetting' doesn't exist" + ", clusterName=" + getClusterName()
+              + ", clusterId=" + getClusterId() + ", clusterSettingName=" + clusterSettingName);
+    }
+
+    ClusterSettingEntity clusterSettingEntity = clusterSettingDAO.findByClusterIdAndSettingName(getClusterId(), clusterSettingName);
+    // Update 'cluster setting' value in 'clusterSettingEntity'.
+    clusterSettingEntity.setClusterSettingValue(clusterSettingValue);
+
+    ClusterSetting clusterSetting = clusterSettingFactory.createExisting(this, clusterSettingEntity);
+    updateClusterSetting(clusterSetting);
+    return clusterSetting;
+  }
+
+  @Override
   public Service getService(String serviceName) throws AmbariException {
     Service service = services.get(serviceName);
     if (null == service) {
@@ -1158,6 +1235,31 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public ClusterSetting getClusterSetting(String clusterSettingName) throws ClusterSettingNotFoundException {
+
+    ClusterSetting clusterSetting = clusterSettings.get(clusterSettingName);
+    if (null == clusterSetting) {
+      throw new ClusterSettingNotFoundException(getClusterName(), clusterSettingName);
+    }
+    return clusterSetting;
+  }
+
+
+  @Override
+  public ClusterSetting getClusterSetting(Long clusterSettingId) throws ClusterSettingNotFoundException {
+    ClusterSetting clusterSetting = clusterSettingsById.get(clusterSettingId);
+    if(null == clusterSetting) {
+      throw new ClusterSettingNotFoundException(getClusterName(), clusterSettingId);
+    }
+    return clusterSetting;
+  }
+
+  @Override
+  public Map<String, ClusterSetting> getClusterSettings() throws AmbariException {
+    return new HashMap<>(clusterSettings);
+  }
+
+  @Override
   public StackId getDesiredStackVersion() {
     return desiredStackVersion;
   }
@@ -1688,6 +1790,33 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  @Override
+  public void deleteAllClusterSettings() throws AmbariException {
+    // TODO : Evaluate if we need a bulk delete feature ?
+  }
+
+  @Override
+  public void deleteClusterSetting(String clusterSettingName) throws AmbariException {
+    clusterGlobalLock.writeLock().lock();
+    try {
+      ClusterSetting clusterSetting = getClusterSetting(clusterSettingName);
+      LOG.info("Deleting 'cluster setting' for cluster" + ", clusterName="
+              + getClusterName() + ", clusterSettingName=" + clusterSetting.getClusterSettingName());
+      // FIXME check dependencies from meta layer
+      if (!clusterSetting.canBeRemoved()) {
+        throw new AmbariException("Could not delete 'cluster setting' from cluster"
+                + ", clusterName=" + getClusterName()
+                + ", clusterSettingName=" + clusterSetting.getClusterSettingName());
+      }
+      Long clusterSettingId = clusterSetting.getClusterSettingId();
+      deleteClusterSetting(clusterSetting);
+      clusterSettings.remove(clusterSettingName);
+      clusterSettingsById.remove(clusterSettingId);
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
   /**
    * Deletes the specified service also removes references to it from {@link this.serviceComponentHosts}
    * and references to ServiceComponentHost objects that belong to the service from {@link this.serviceComponentHostsByHost}
@@ -1726,12 +1855,24 @@ public class ClusterImpl implements Cluster {
    *
    * @param serviceGroup the service group to be deleted
    * @throws AmbariException
-   * @see ServiceComponentHost
    */
   private void deleteServiceGroup(ServiceGroup serviceGroup) throws AmbariException {
     serviceGroup.delete();
   }
 
+  /**
+   * Deletes the specified 'cluster setting'.
+   * <p>
+   * Note: This method must be called only with write lock acquired.
+   * </p>
+   *
+   * @param clusterSetting the 'cluster setting' to be deleted
+   * @throws AmbariException
+   */
+  private void deleteClusterSetting(ClusterSetting clusterSetting) throws AmbariException {
+    clusterSetting.delete();
+  }
+
   @Override
   public boolean canBeRemoved() {
     clusterGlobalLock.readLock().lock();

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 5bc419e..039d8af 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -144,6 +144,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id BIGINT NOT NULL,
+  setting_name VARCHAR(255) NOT NULL,
+  setting_value VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id BIGINT NOT NULL,
   service_group_name VARCHAR(255) NOT NULL,
@@ -1144,6 +1152,8 @@ CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 INSERT INTO ambari_sequences (sequence_name, sequence_value)
   SELECT 'cluster_id_seq', 1 FROM SYSIBM.SYSDUMMY1
   UNION ALL
+  SELECT 'cluster_setting_id_seq', 1 FROM SYSIBM.SYSDUMMY1
+  UNION ALL
   SELECT 'service_group_id_seq', 1 FROM SYSIBM.SYSDUMMY1
   UNION ALL
   SELECT 'service_id_seq', 1 FROM SYSIBM.SYSDUMMY1

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index b3bd221..e14f0f1 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -163,6 +163,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id BIGINT NOT NULL,
+  setting_name VARCHAR(255) NOT NULL,
+  setting_value VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id BIGINT NOT NULL,
   service_group_name VARCHAR(255) NOT NULL,
@@ -1158,6 +1166,7 @@ CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 -- In order for the first ID to be 1, must initialize the ambari_sequences table with a sequence_value of 0.
 INSERT INTO ambari_sequences(sequence_name, sequence_value) VALUES
   ('cluster_id_seq', 1),
+  ('cluster_setting_id_seq', 1),
   ('service_group_id_seq', 1),
   ('service_id_seq', 1),
   ('host_id_seq', 0),

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index f6294c7..a5911eb 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -144,6 +144,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id NUMBER(19) NOT NULL,
+  setting_name VARCHAR2(255) NOT NULL,
+  setting_value VARCHAR2(255) NOT NULL,
+  cluster_id NUMBER(19) NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id NUMBER(19) NOT NULL,
   service_group_name VARCHAR2(255) NOT NULL,
@@ -1138,6 +1146,7 @@ CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 ---------inserting some data-----------
 -- In order for the first ID to be 1, must initialize the ambari_sequences table with a sequence_value of 0.
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('host_role_command_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('cluster_setting_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('service_group_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('service_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('user_id_seq', 1);

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index e2bf5f3..c5203e4 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -145,6 +145,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id BIGINT NOT NULL,
+  setting_name VARCHAR(255) NOT NULL,
+  setting_value VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id BIGINT NOT NULL,
   service_group_name VARCHAR(255) NOT NULL,
@@ -1143,6 +1151,7 @@ CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 BEGIN;
 INSERT INTO ambari_sequences (sequence_name, sequence_value) VALUES
   ('cluster_id_seq', 1),
+  ('cluster_setting_id_seq', 1),
   ('service_group_id_seq', 1),
   ('service_id_seq', 1),
   ('host_id_seq', 0),

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 1379112..a9032f3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -143,6 +143,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id NUMERIC(19) NOT NULL,
+  setting_name VARCHAR(255) NOT NULL,
+  setting_value VARCHAR(255) NOT NULL,
+  cluster_id NUMERIC(19) NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id NUMERIC(19) NOT NULL,
   service_group_name VARCHAR(255) NOT NULL,
@@ -1137,6 +1145,7 @@ CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 
 -- In order for the first ID to be 1, must initialize the ambari_sequences table with a sequence_value of 0.
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('cluster_id_seq', 1);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('cluster_setting_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('service_group_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('service_id_seq', 1);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('host_id_seq', 0);

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 5f03331..d782155 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -157,6 +157,14 @@ CREATE TABLE hosts (
   CONSTRAINT PK_hosts PRIMARY KEY CLUSTERED (host_id),
   CONSTRAINT UQ_hosts_host_name UNIQUE (host_name));
 
+CREATE TABLE clustersettings (
+  id BIGINT NOT NULL,
+  setting_name VARCHAR(255) NOT NULL,
+  setting_value VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_clustersettings PRIMARY KEY (id),
+  CONSTRAINT FK_clustersettings_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE servicegroups (
   id BIGINT NOT NULL,
   service_group_name VARCHAR(255) NOT NULL,
@@ -1163,6 +1171,7 @@ BEGIN TRANSACTION
   INSERT INTO ambari_sequences (sequence_name, [sequence_value])
   VALUES
     ('cluster_id_seq', 1),
+    ('cluster_setting_id_seq', 1),
     ('service_group_id_seq', 1),
     ('service_id_seq', 1),
     ('host_id_seq', 0),

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 009ecd5..218b0d2 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -27,6 +27,7 @@
     <class>org.apache.ambari.server.orm.entities.ClusterConfigEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceGroupEntity</class>
+    <class>org.apache.ambari.server.orm.entities.ClusterSettingEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterServiceEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterStateEntity</class>
     <class>org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity</class>


[2/2] ambari git commit: AMBARI-22366. POST, GET and UPDATE API for cluster settings. (/clusters/{clusterName}/settings).

Posted by sw...@apache.org.
AMBARI-22366. POST, GET and UPDATE API for cluster settings. (/clusters/{clusterName}/settings).


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 4959206893da4060e66b6ece4cfba5136de79157
Parents: b558eda
Author: Swapan Shridhar <ss...@hortonworks.com>
Authored: Fri Nov 10 14:07:40 2017 -0800
Committer: Swapan Shridhar <ss...@hortonworks.com>
Committed: Fri Nov 10 14:07:40 2017 -0800

----------------------------------------------------------------------
 .../server/ClusterSettingNotFoundException.java |  35 ++
 .../resources/ClusterResourceDefinition.java    |   1 +
 .../ClusterSettingResourceDefinition.java       |  45 ++
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../server/api/services/ClusterService.java     |  13 +
 .../api/services/ClusterSettingService.java     | 276 +++++++++
 .../controller/AmbariManagementController.java  |   8 +
 .../AmbariManagementControllerImpl.java         |   8 +
 .../controller/ClusterSettingRequest.java       |  83 +++
 .../controller/ClusterSettingResponse.java      | 147 +++++
 .../server/controller/ControllerModule.java     |   7 +
 .../controller/ResourceProviderFactory.java     |   4 +-
 .../server/controller/ServiceGroupResponse.java |   2 +-
 .../AbstractControllerResourceProvider.java     |   2 +
 .../ClusterSettingResourceProvider.java         | 554 +++++++++++++++++++
 .../internal/DefaultProviderModule.java         |   2 +
 .../internal/ServiceGroupResourceProvider.java  |   4 +-
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../server/events/ClusterSettingEvent.java      |  46 ++
 .../server/orm/dao/ClusterSettingDAO.java       | 100 ++++
 .../server/orm/entities/ClusterEntity.java      |  11 +
 .../orm/entities/ClusterSettingEntity.java      | 131 +++++
 .../resources/RootLevelSettingsManager.java     |   2 +-
 .../org/apache/ambari/server/state/Cluster.java |  70 +++
 .../ambari/server/state/ClusterSetting.java     |  56 ++
 .../server/state/ClusterSettingFactory.java     |  33 ++
 .../ambari/server/state/ClusterSettingImpl.java | 201 +++++++
 .../ambari/server/state/ServiceGroupImpl.java   |   4 +-
 .../server/state/cluster/ClusterImpl.java       | 149 ++++-
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |  10 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   9 +
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   9 +
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   9 +
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |   9 +
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |   9 +
 .../src/main/resources/META-INF/persistence.xml |   1 +
 36 files changed, 2044 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/ClusterSettingNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ClusterSettingNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/ClusterSettingNotFoundException.java
new file mode 100644
index 0000000..1720aea
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ClusterSettingNotFoundException.java
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+@SuppressWarnings("serial")
+public class ClusterSettingNotFoundException extends ObjectNotFoundException {
+
+    public ClusterSettingNotFoundException(String clusterName, String clusterSettingName) {
+        super("ClusterSetting not found"
+                + ", clusterName=" + clusterName
+                + ", clusterSettingName=" + clusterSettingName);
+    }
+
+    public ClusterSettingNotFoundException(String clusterName, Long clusterSettingId) {
+        super("ClusterSetting not found"
+                + ", clusterName=" + clusterName
+                + ", clusterSettingId=" + clusterSettingId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
index e5680dd..d211efd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
@@ -63,6 +63,7 @@ public class ClusterResourceDefinition extends BaseResourceDefinition {
     Set<SubResourceDefinition> setChildren = new HashSet<>();
     setChildren.add(new SubResourceDefinition(Resource.Type.ServiceGroup));
     setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+    setChildren.add(new SubResourceDefinition(Resource.Type.ClusterSetting));
     setChildren.add(new SubResourceDefinition(Resource.Type.Configuration));
     setChildren.add(new SubResourceDefinition(Resource.Type.ServiceConfigVersion));
     setChildren.add(new SubResourceDefinition(Resource.Type.Request));

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterSettingResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterSettingResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterSettingResourceDefinition.java
new file mode 100644
index 0000000..151cfe8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterSettingResourceDefinition.java
@@ -0,0 +1,45 @@
+/*
+ * 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 org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Cluster Setting resource definition.
+ */
+public class ClusterSettingResourceDefinition extends BaseResourceDefinition {
+
+    /**
+     * Constructor.
+     */
+    public ClusterSettingResourceDefinition() {
+        super(Resource.Type.ClusterSetting);
+    }
+
+    @Override
+    public String getPluralName() {
+        return "settings";
+    }
+
+    @Override
+    public String getSingularName() {
+        return "setting";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 7ac41a5..2d2e75e 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
@@ -108,6 +108,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new RootClusterSettingsResourceDefinition();
         break;
 
+      case ClusterSetting:
+        resourceDefinition = new ClusterSettingResourceDefinition();
+        break;
+
       case ServiceGroup:
         resourceDefinition = new ServiceGroupResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 92f50f4..31af4e0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -535,6 +535,19 @@ public class ClusterService extends BaseService {
   }
 
   /**
+   * Gets the cluster setting sub-resource.
+   *
+   * @param request      the request
+   * @param clusterName  the cluster name
+   *
+   * @return the 'cluster setting' service
+   */
+  @Path("{clusterName}/settings")
+  public ClusterSettingService getSettingsHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
+    return new ClusterSettingService(clusterName);
+  }
+
+  /**
    * Gets the requests sub-resource.
    *
    * @param request      the request

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterSettingService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterSettingService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterSettingService.java
new file mode 100644
index 0000000..c8f9bd1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterSettingService.java
@@ -0,0 +1,276 @@
+/*
+ * 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.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+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.annotations.ApiIgnore;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.ClusterSettingResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.http.HttpStatus;
+
+
+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.
+ */
+public class ClusterSettingService extends BaseService {
+    private static final String CLUSTER_SETTING_REQUEST_TYPE = "org.apache.ambari.server.controller.ClusterSettingRequestSwagger";
+
+    /**
+     * Parent cluster name.
+     */
+    private String m_clusterName;
+
+    /**
+     * Constructor.
+     *
+     * @param clusterName cluster id
+     */
+    public ClusterSettingService(String clusterName) {
+        m_clusterName = clusterName;
+    }
+
+
+    /**
+     * Handles URL: /clusters/{clusterId}/settings
+     * Get all 'cluster settings' for a cluster.
+     *
+     * @param headers http headers
+     * @param ui      uri info
+     * @return service collection resource representation
+     */
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @ApiOperation(value = "Get all cluster settings",
+            nickname = "ClusterSettingService#getClusterSettings",
+            notes = "Returns all 'cluster settings'.",
+            response = ClusterSettingResponse.ClusterSettingResponseSwagger.class,
+            responseContainer = RESPONSE_CONTAINER_LIST)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION,
+                    defaultValue = "ClusterSettingInfo/cluster_setting_name, ClusterSettingInfo/cluster_name",
+                    dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+            @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION,
+                    defaultValue = "ClusterSettingInfo/cluster_setting_name.asc, ClusterSettingInfo/cluster_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_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,
+                createClusterSettingResource(m_clusterName, null));
+    }
+
+    /**
+     * Handles URL: /clusters/{clusterId}/settings/{clusterSettingName}
+     * Get a specific 'cluster setting' for a cluster.
+     *
+     * @param headers http headers
+     * @param ui      uri info
+     * @return service collection resource representation
+     */
+    @GET
+    @Path("{clusterSettingName}")
+    @Produces(MediaType.TEXT_PLAIN)
+    @ApiOperation(value = "Get the details of a specific 'cluster setting'",
+            nickname = "ClusterSettingService#getClusterSetting",
+            notes = "Returns the details of a specific 'cluster setting'",
+            response = ClusterSettingResponse.ClusterSettingResponseSwagger.class,
+            responseContainer = RESPONSE_CONTAINER_LIST)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, defaultValue = "ClusterSettingInfo/*",
+                    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 getClusterSetting(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                      @PathParam("clusterSettingName") String clusterSettingName) {
+        return handleRequest(headers, body, ui, Request.Type.GET,
+                createClusterSettingResource(m_clusterName, clusterSettingName));
+    }
+
+    /**
+     * Handles: PUT /clusters/{clusterName}/settings
+     * Update multiple cluster settings.
+     *
+     * @param body        http body
+     * @param headers     http headers
+     * @param ui          uri info
+     * @return information regarding the updated cluster settings.
+     */
+    @PUT
+    @Produces(MediaType.TEXT_PLAIN)
+    @ApiOperation(value = "Updates multiple cluster settings",
+            nickname = "ClusterSettingService#updateClusterSettings"
+    )
+    @ApiImplicitParams({
+            @ApiImplicitParam(dataType = CLUSTER_SETTING_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+    })
+    @ApiResponses({
+            @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+            @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+            @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+            @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 updateClusterSettings(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+        return handleRequest(headers, body, ui, Request.Type.PUT, createClusterSettingResource(m_clusterName, null));
+    }
+
+    /**
+     * Handles: PUT /clusters/{clusterName}/settings/{clusterSettingName}
+     * Updates the specific cluster setting.
+     *
+     * @param body                  http body
+     * @param headers               http headers
+     * @param ui                    uri info
+     * @param clusterSettingName    cluster setting name
+     *
+     * @return information regarding the updated cluster setting.
+     */
+    @PUT
+    @Path("{clusterSettingName}")
+    @Produces(MediaType.TEXT_PLAIN)
+    @ApiOperation(value = "Updates the specific cluster setting",
+            nickname = "ClusterSettingService#updateClusterSetting"
+    )
+    @ApiImplicitParams({
+            @ApiImplicitParam(dataType = CLUSTER_SETTING_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+    })
+    @ApiResponses({
+            @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+            @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+            @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+            @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 updateClusterSettings(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                          @PathParam("clusterSettingName") String clusterSettingName) {
+        return handleRequest(headers, body, ui, Request.Type.PUT, createClusterSettingResource(m_clusterName, clusterSettingName));
+    }
+
+    /**
+     * Handles: DELETE /clusters/{clusterName}/settings/{clusterSettingName}
+     * Delete a specific 'cluster setting'.
+
+     * @param headers               http headers
+     * @param ui                    uri info
+     * @param clusterSettingName    cluster setting name
+     * @return information regarding the deleted 'cluster setting'
+     */
+    @DELETE
+    @Path("{clusterSettingName}")
+    @Produces(MediaType.TEXT_PLAIN)
+    @ApiOperation(value = "Deletes a specific cluster setting",
+            nickname = "ClusterSettingService#deleteClustersetting"
+    )
+    @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 deleteClusterSetting(@Context HttpHeaders headers, @Context UriInfo ui,
+                                       @PathParam("clusterSettingName") String clusterSettingName) {
+
+        return handleRequest(headers, null, ui, Request.Type.DELETE, createClusterSettingResource(m_clusterName, clusterSettingName));
+    }
+
+    /**
+     * Handles URL: /clusters/{clusterId}/settings
+     * The body should contain:
+     * To create multiple settings in a request, provide an array of settings.
+     * eg:
+     *
+     * [
+     *      {
+     *          "ClusterSettingInfo" : {
+     *              "cluster_setting_name": "{setting_name}",
+     *              "cluster_setting_value": "{setting_val}"
+     *          }
+     *      },
+     *      {
+     *          "ClusterSettingInfo" : {
+     *              "cluster_setting_name": "{setting_name}",
+     *              "cluster_setting_value": "{setting_val}"
+     *      }
+     *]
+     *
+     *
+     *
+     * @param headers http headers
+     * @param ui      uri info
+     * @return status code only, 201 if successful
+     */
+    @POST @ApiIgnore // until documented
+    @Produces("text/plain")
+    public Response createConfigurations(String body,@Context HttpHeaders headers, @Context UriInfo ui) {
+        return handleRequest(headers, body, ui, Request.Type.POST, createClusterSettingResource(m_clusterName, null));
+    }
+
+    /**
+     * Create a 'cluster setting' resource instance.
+     *
+     * @param clusterName cluster name
+     *
+     * @return a cluster setting resource instance
+     */
+    ResourceInstance createClusterSettingResource(String clusterName, String clusterSettingName) {
+        Map<Resource.Type,String> mapIds = new HashMap<>();
+        mapIds.put(Resource.Type.Cluster, clusterName);
+        mapIds.put(Resource.Type.ClusterSetting, clusterSettingName);
+
+        return createResource(Resource.Type.ClusterSetting, mapIds);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 86ac3c4..b5bc813 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
@@ -51,6 +51,7 @@ import org.apache.ambari.server.security.ldap.LdapBatchDto;
 import org.apache.ambari.server.security.ldap.LdapSyncDto;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.ClusterSettingFactory;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigHelper;
@@ -582,6 +583,13 @@ public interface AmbariManagementController {
   ServiceGroupFactory getServiceGroupFactory();
 
   /**
+   * Get the 'cluster setting' factory for this management controller.
+   *
+   * @return the 'cluster setting'
+   */
+  ClusterSettingFactory getClusterSettingFactory();
+
+  /**
    * Get the service component factory for this management controller.
    *
    * @return the service component factory

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 dc16f22..80b414578 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
@@ -157,6 +157,7 @@ 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.ClusterSettingFactory;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.CommandScriptDefinition;
 import org.apache.ambari.server.state.ComponentInfo;
@@ -270,6 +271,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   @Inject
   private ServiceGroupFactory serviceGroupFactory;
   @Inject
+  private ClusterSettingFactory clusterSettingFactory;
+  @Inject
   private ServiceFactory serviceFactory;
   @Inject
   private ServiceComponentFactory serviceComponentFactory;
@@ -5278,6 +5281,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
+  public ClusterSettingFactory getClusterSettingFactory() {
+    return clusterSettingFactory;
+  }
+
+  @Override
   public ServiceFactory getServiceFactory() { return serviceFactory; }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingRequest.java
new file mode 100644
index 0000000..37fe5bc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingRequest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.controller;
+
+
+public class ClusterSettingRequest {
+
+    private String clusterName; // REF
+    private String clusterSettingName; // GET/CREATE/DELETE
+    private String clusterSettingValue;
+
+    public ClusterSettingRequest(String clusterName, String clusterSettingName, String clusterSettingValue) {
+        this.clusterName = clusterName;
+        this.clusterSettingName = clusterSettingName;
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+    /**
+     * @return the clusterName
+     */
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    /**
+     * @param clusterName the clusterName to set
+     */
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    /**
+     * @return the clustesettingName
+     */
+    public String getClusterSettingName() {
+        return clusterSettingName;
+    }
+
+    /**
+     * @param clusterSettingName the cluster setting name to set
+     */
+    public void setClusterSettingName(String clusterSettingName) {
+        this.clusterSettingName = clusterSettingName;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("clusterName=" + clusterName
+                + ", clusterSettingName=" + clusterSettingName
+                + ", clusterSettingValue=" + clusterSettingValue);
+        return sb.toString();
+    }
+
+    /**
+     * @return the clustesettingName
+     */
+    public String getClusterSettingValue() {
+        return clusterSettingValue;
+    }
+
+    /**
+     * @param clusterSettingValue the cluster setting value to set
+     */
+    public void setClusterSettingValue(String clusterSettingValue) {
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingResponse.java
new file mode 100644
index 0000000..9d79326
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterSettingResponse.java
@@ -0,0 +1,147 @@
+/**
+ * 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.controller;
+
+import java.util.Objects;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class ClusterSettingResponse {
+
+    private Long clusterId;
+    private String clusterName;
+    private Long clusterSettingId;
+    private String clusterSettingName;
+    private String clusterSettingValue;
+
+    public ClusterSettingResponse(Long clusterId, String clusterName, Long clusterSettingId,
+                                  String clusterSettingName, String clusterSettingValue) {
+        this.clusterId = clusterId;
+        this.clusterSettingId = clusterSettingId;
+        this.clusterName = clusterName;
+        this.clusterSettingName = clusterSettingName;
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+    /**
+     * @return the clusterId
+     */
+    public Long getClusterId() {
+        return clusterId;
+    }
+
+    /**
+     * @param clusterId the clusterId to set
+     */
+    public void setClusterId(Long clusterId) {
+        this.clusterId = clusterId;
+    }
+
+
+
+    /**
+     * @return the clusterName
+     */
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    /**
+     * @param clusterName the clusterName to set
+     */
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+
+
+    /**
+     * @return the cluster Setting Id
+     */
+    public Long getClusterSettingId() {
+        return clusterSettingId;
+    }
+
+    /**
+     * @param  clusterSettingId the cluster Setting Id
+     */
+    public void setClusterSettingId(Long clusterSettingId) {
+        this.clusterSettingId = clusterSettingId;
+    }
+
+
+
+    /**
+     * @return the cluster setting name
+     */
+    public String getClusterSettingName() {
+        return clusterSettingName;
+    }
+
+    /**
+     * @param  clusterSettingName the cluster setting name
+     */
+    public void setClusterSettingName(String clusterSettingName) {
+        this.clusterSettingName = clusterSettingName;
+    }
+
+
+
+    /**
+     * @return the cluster setting name
+     */
+    public String getClusterSettingValue() {
+        return clusterSettingValue;
+    }
+
+    /**
+     * @param  clusterSettingValue the cluster setting value
+     */
+    public void setClusterSettingValue(String clusterSettingValue) {
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ClusterSettingResponse that = (ClusterSettingResponse) o;
+
+        return Objects.equals(clusterId, that.clusterId) &&
+               Objects.equals(clusterSettingId, that.clusterSettingId) &&
+               Objects.equals(clusterName, that.clusterName) &&
+               Objects.equals(clusterSettingName, that.clusterSettingName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(clusterId, clusterSettingId, clusterName, clusterSettingName);
+    }
+
+    /**
+     * Interface to help correct Swagger documentation generation
+     */
+    public interface ClusterSettingResponseSwagger extends ApiModel {
+        @ApiModelProperty(name = "ClusterSettingInfo")
+        ClusterSettingResponse getClusterSettingResponse();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 0303a71..eff1e77 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
@@ -64,6 +64,7 @@ import org.apache.ambari.server.configuration.Configuration.ConnectionPoolType;
 import org.apache.ambari.server.configuration.Configuration.DatabaseType;
 import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider;
 import org.apache.ambari.server.controller.internal.AmbariConfigurationResourceProvider;
+import org.apache.ambari.server.controller.internal.ClusterSettingResourceProvider;
 import org.apache.ambari.server.controller.internal.ClusterStackVersionResourceProvider;
 import org.apache.ambari.server.controller.internal.ComponentResourceProvider;
 import org.apache.ambari.server.controller.internal.CredentialResourceProvider;
@@ -129,6 +130,9 @@ import org.apache.ambari.server.serveraction.users.CsvFilePersisterService;
 import org.apache.ambari.server.stack.StackManagerFactory;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.ClusterSetting;
+import org.apache.ambari.server.state.ClusterSettingFactory;
+import org.apache.ambari.server.state.ClusterSettingImpl;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigFactory;
@@ -473,6 +477,8 @@ public class ControllerModule extends AbstractModule {
         Service.class, ServiceImpl.class).build(ServiceFactory.class));
     install(new FactoryModuleBuilder().implement(
         ServiceGroup.class, ServiceGroupImpl.class).build(ServiceGroupFactory.class));
+    install(new FactoryModuleBuilder().implement(
+        ClusterSetting.class, ClusterSettingImpl.class).build(ClusterSettingFactory.class));
 
     install(new FactoryModuleBuilder()
         .implement(ResourceProvider.class, Names.named("host"), HostResourceProvider.class)
@@ -481,6 +487,7 @@ public class ControllerModule extends AbstractModule {
         .implement(ResourceProvider.class, Names.named("servicegroup"), ServiceGroupResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("servicedependency"), ServiceDependencyResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("servicegroupdependency"), ServiceGroupDependencyResourceProvider.class)
+        .implement(ResourceProvider.class, Names.named("clustersetting"), ClusterSettingResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("component"), ComponentResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("member"), MemberResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("repositoryVersion"), RepositoryVersionResourceProvider.class)

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
index 0fbea9a..a6c69af 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
@@ -41,7 +41,6 @@ public interface ResourceProviderFactory {
   @Named("hostComponent")
   ResourceProvider getHostComponentResourceProvider(Set<String> propertyIds, Map<Type, String> keyPropertyIds,
                                                     AmbariManagementController managementController);
-
   @Named("service")
   ResourceProvider getServiceResourceProvider(AmbariManagementController managementController);
 
@@ -54,6 +53,9 @@ public interface ResourceProviderFactory {
   @Named("servicegroupdependency")
   ResourceProvider getServiceGroupDependencyResourceProvider(AmbariManagementController managementController);
 
+  @Named("clustersetting")
+  ResourceProvider getClusterSettingResourceProvider(AmbariManagementController managementController);
+
   @Named("component")
   ResourceProvider getComponentResourceProvider(AmbariManagementController managementController);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
index 147650c..6b7c32f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
@@ -118,7 +118,7 @@ public class ServiceGroupResponse {
    */
   public interface ServiceGroupResponseSwagger extends ApiModel {
     @ApiModelProperty(name = "ServiceGroupInfo")
-    ServiceResponse getServiceGroupResponse();
+    ServiceGroupResponse getServiceGroupResponse();
   }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 0acf78f..5cc2116 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
@@ -154,6 +154,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
         return new ClusterResourceProvider(managementController);
       case RootClusterSetting:
         return new RootClusterSettingsResourceProvider(managementController);
+      case ClusterSetting:
+        return resourceProviderFactory.getClusterSettingResourceProvider(managementController);
       case Service:
         return resourceProviderFactory.getServiceResourceProvider(managementController);
       case ServiceDependency:

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java
new file mode 100644
index 0000000..936826a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java
@@ -0,0 +1,554 @@
+/**
+ * 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.controller.internal;
+
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterNotFoundException;
+import org.apache.ambari.server.ClusterSettingNotFoundException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.ObjectNotFoundException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.PropertyNotFoundException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ClusterSettingRequest;
+import org.apache.ambari.server.controller.ClusterSettingResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.ResourceType;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.ClusterSetting;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
+
+import com.google.common.collect.Sets;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+
+/**
+ * Resource provider for Cluster Settings resource.
+ **/
+
+public class ClusterSettingResourceProvider extends AbstractControllerResourceProvider {
+
+
+    // ----- Property ID constants ---------------------------------------------
+
+    public static final String RESPONSE_KEY = "ClusterSettingInfo";
+    public static final String ALL_PROPERTIES = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "*";
+    public static final String CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_id";
+    public static final String CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_name";
+    public static final String CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_id";
+    public static final String CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_name";
+    public static final String CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_value";
+
+    private static final Set<String> pkPropertyIds =
+            Sets.newHashSet(new String[]{
+                    CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID,
+                    CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID});
+
+    /**
+     * The property ids for an cluster setting resource.
+     */
+    private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+    /**
+     * The key property ids for an cluster setting resource.
+     */
+    private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
+
+    static {
+        // properties
+        PROPERTY_IDS.add(CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID);
+        PROPERTY_IDS.add(CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID);
+        PROPERTY_IDS.add(CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID);
+        PROPERTY_IDS.add(CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID);
+        PROPERTY_IDS.add(CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID);
+
+        // keys
+        KEY_PROPERTY_IDS.put(Resource.Type.Cluster, CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID);
+        KEY_PROPERTY_IDS.put(Resource.Type.ClusterSetting, CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID);
+    }
+
+    // ----- Constructors ----------------------------------------------------
+
+    /**
+     * Create a  new resource provider for the given management controller.
+     *
+     * @param managementController the management controller
+     */
+    @AssistedInject
+    public ClusterSettingResourceProvider(@Assisted AmbariManagementController managementController) {
+        super(Resource.Type.ClusterSetting, PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
+    }
+
+    // ----- ResourceProvider ------------------------------------------------
+
+    @Override
+    protected RequestStatus createResourcesAuthorized(Request request)
+            throws SystemException,
+            UnsupportedPropertyException,
+            ResourceAlreadyExistsException,
+            NoSuchParentResourceException {
+
+        final Set<ClusterSettingRequest> requests = new HashSet<>();
+        for (Map<String, Object> propertyMap : request.getProperties()) {
+            requests.add(getRequest(propertyMap));
+        }
+        Set<ClusterSettingResponse> createClusterSettings;
+        createClusterSettings = createResources(new Command<Set<ClusterSettingResponse>>() {
+            @Override
+            public Set<ClusterSettingResponse> invoke() throws AmbariException, AuthorizationException {
+                return createClusterSettings(requests);
+            }
+        });
+        Set<Resource> associatedResources = new HashSet<>();
+        if (createClusterSettings != null) {
+            Iterator<ClusterSettingResponse> itr = createClusterSettings.iterator();
+            while (itr.hasNext()) {
+                ClusterSettingResponse response = itr.next();
+                notifyCreate(Resource.Type.ClusterSetting, request);
+                Resource resource = new ResourceImpl(Resource.Type.ClusterSetting);
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID, response.getClusterId());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID, response.getClusterName());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID, response.getClusterSettingId());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID, response.getClusterSettingName());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID, response.getClusterSettingValue());
+
+                associatedResources.add(resource);
+            }
+            return getRequestStatus(null, associatedResources);
+        }
+
+        return getRequestStatus(null);
+    }
+
+    @Override
+    protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws
+            SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+        final Set<ClusterSettingRequest> requests = new HashSet<>();
+
+        for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+            requests.add(getRequest(propertyMap));
+        }
+
+        Set<ClusterSettingResponse> responses = getResources(new Command<Set<ClusterSettingResponse>>() {
+            @Override
+            public Set<ClusterSettingResponse> invoke() throws AmbariException {
+                return getClusterSettings(requests);
+            }
+        });
+
+        Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+        Set<Resource> resources = new HashSet<>();
+
+        for (ClusterSettingResponse response : responses) {
+            Resource resource = new ResourceImpl(Resource.Type.ClusterSetting);
+            setResourceProperty(resource, CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID,
+                    response.getClusterId(), requestedIds);
+            setResourceProperty(resource, CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID,
+                    response.getClusterName(), requestedIds);
+            setResourceProperty(resource, CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID,
+                    response.getClusterSettingId(), requestedIds);
+            setResourceProperty(resource, CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID,
+                    response.getClusterSettingName(), requestedIds);
+            setResourceProperty(resource, CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID,
+                    response.getClusterSettingValue(), requestedIds);
+            resources.add(resource);
+        }
+        return resources;
+    }
+
+    @Override
+    protected RequestStatus updateResourcesAuthorized(final Request request, Predicate predicate)
+            throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+        final Set<ClusterSettingRequest> requests = new HashSet<>();
+        for (Map<String, Object> propertyMap : request.getProperties()) {
+            requests.add(getRequest(propertyMap));
+        }
+        Set<ClusterSettingResponse> createClusterSettings;
+        createClusterSettings = modifyResources(new Command<Set<ClusterSettingResponse>>() {
+            @Override
+            public Set<ClusterSettingResponse> invoke() throws AmbariException, AuthorizationException {
+                return updateClusterSettings(requests);
+            }
+        });
+        Set<Resource> associatedResources = new HashSet<>();
+        if (createClusterSettings != null) {
+            Iterator<ClusterSettingResponse> itr = createClusterSettings.iterator();
+            while (itr.hasNext()) {
+                ClusterSettingResponse response = itr.next();
+                notifyUpdate(Resource.Type.ClusterSetting, request, predicate);
+                Resource resource = new ResourceImpl(Resource.Type.ClusterSetting);
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID, response.getClusterId());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID, response.getClusterName());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID, response.getClusterSettingId());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID, response.getClusterSettingName());
+                resource.setProperty(CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID, response.getClusterSettingValue());
+
+                associatedResources.add(resource);
+            }
+            return getRequestStatus(null, associatedResources);
+        }
+
+        return getRequestStatus(null);
+    }
+
+    @Override
+    protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+            throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+        final Set<ClusterSettingRequest> requests = new HashSet<>();
+
+        for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+            requests.add(getRequest(propertyMap));
+        }
+        DeleteStatusMetaData deleteStatusMetaData;
+        deleteStatusMetaData = modifyResources(new Command<DeleteStatusMetaData>() {
+            @Override
+            public DeleteStatusMetaData invoke() throws AmbariException, AuthorizationException {
+                deleteClusterSettings(requests);
+                return new DeleteStatusMetaData();
+            }
+        });
+
+        notifyDelete(Resource.Type.ClusterSetting, predicate);
+        for(ClusterSettingRequest settingReq : requests) {
+            deleteStatusMetaData.addDeletedKey("cluster_name: "+settingReq.getClusterName() + ", " + "cluster_setting_name: "+settingReq.getClusterSettingName());
+        }
+        return getRequestStatus(null, null, deleteStatusMetaData);
+    }
+
+    // ----- AbstractResourceProvider ----------------------------------------
+
+    @Override
+    protected Set<String> getPKPropertyIds() {
+        return pkPropertyIds;
+    }
+
+    // ----- utility methods -------------------------------------------------
+
+    /**
+     * Get a cluster setting request object from a map of property values.
+     *
+     * @param properties the predicate
+     * @return the service request object
+     */
+    private ClusterSettingRequest getRequest(Map<String, Object> properties) {
+        String clusterName = (String) properties.get(CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID);
+        String clusterSettingName = (String) properties.get(CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID);
+        String clusterSettingValue = (String) properties.get(CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID);
+        return  new ClusterSettingRequest(clusterName, clusterSettingName, clusterSettingValue);
+    }
+
+    // Create 'cluster setting' based on the given request.
+    private synchronized Set<ClusterSettingResponse> createClusterSettings(Set<ClusterSettingRequest> requests)
+            throws AmbariException, AuthorizationException {
+
+        if (requests.isEmpty()) {
+            LOG.warn("Received an empty requests set");
+            return null;
+        }
+        AmbariManagementController controller = getManagementController();
+        Clusters clusters = controller.getClusters();
+
+        // do all validation checks
+        validateCreateRequests(requests, clusters);
+
+        Set<ClusterSettingResponse> createdClusterSettings = new HashSet<>();
+        for (ClusterSettingRequest request : requests) {
+            Cluster cluster = clusters.getCluster(request.getClusterName());
+
+            // Already checked that 'cluster setting' does not exist
+            ClusterSetting cs = cluster.addClusterSetting(request.getClusterSettingName(), request.getClusterSettingValue());
+            createdClusterSettings.add(cs.convertToResponse());
+        }
+        return createdClusterSettings;
+    }
+
+    // update 'cluster setting' based on the given request.
+    private synchronized Set<ClusterSettingResponse> updateClusterSettings(Set<ClusterSettingRequest> requests)
+            throws AmbariException, AuthorizationException {
+
+        if (requests.isEmpty()) {
+            LOG.warn("Received an empty requests set");
+            return null;
+        }
+        AmbariManagementController controller = getManagementController();
+        Clusters clusters = controller.getClusters();
+
+        // do all validation checks
+        validateUpdateRequests(requests, clusters);
+
+        Set<ClusterSettingResponse> updatedClusterSettings = new HashSet<>();
+        for (ClusterSettingRequest request : requests) {
+            Cluster cluster = clusters.getCluster(request.getClusterName());
+
+            // Already checked that 'cluster setting' exists
+            ClusterSetting cs = cluster.updateClusterSetting(request.getClusterSettingName(), request.getClusterSettingValue());
+            updatedClusterSettings.add(cs.convertToResponse());
+        }
+        return updatedClusterSettings;
+    }
+
+    // Get 'cluster settings' from the given set of requests.
+    private Set<ClusterSettingResponse> getClusterSettings(Set<ClusterSettingRequest> requests)
+            throws AmbariException {
+        Set<ClusterSettingResponse> response = new HashSet<>();
+        for (ClusterSettingRequest request : requests) {
+            try {
+                response.addAll(getClusterSettings(request));
+            } catch (ClusterSettingNotFoundException e) {
+                if (requests.size() == 1) {
+                    // only throw exception if 1 request.
+                    // there will be > 1 request in case of OR predicate
+                    throw e;
+                }
+            }
+        }
+        return response;
+    }
+
+    // Get 'cluster settings' from the given request.
+    private Set<ClusterSettingResponse> getClusterSettings(ClusterSettingRequest request)
+            throws AmbariException {
+        if (request.getClusterName() == null) {
+            throw new AmbariException("Invalid arguments, cluster id"
+                    + " cannot be null");
+        }
+        AmbariManagementController controller = getManagementController();
+        Clusters clusters = controller.getClusters();
+        String clusterName = request.getClusterName();
+
+        final Cluster cluster;
+        try {
+            cluster = clusters.getCluster(clusterName);
+        } catch (ObjectNotFoundException e) {
+            throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+        }
+
+        Set<ClusterSettingResponse> response = new HashSet<>();
+        if (request.getClusterSettingName() != null) {
+            ClusterSetting clusterSetting = cluster.getClusterSetting(request.getClusterSettingName());
+            ClusterSettingResponse clusterSettingResponse = clusterSetting.convertToResponse();
+
+            response.add(clusterSettingResponse);
+            return response;
+        }
+
+        for (ClusterSetting clusterSetting : cluster.getClusterSettings().values()) {
+            ClusterSettingResponse clusterSettingResponse = clusterSetting.convertToResponse();
+            response.add(clusterSettingResponse);
+        }
+        return response;
+    }
+
+
+    // Delete 'cluster setting' based on the given set of requests
+    private void deleteClusterSettings(Set<ClusterSettingRequest> request)
+            throws AmbariException, AuthorizationException {
+
+        Clusters clusters = getManagementController().getClusters();
+
+        Set<ClusterSetting> removable = new HashSet<>();
+
+        for (ClusterSettingRequest clusterSettingRequest : request) {
+            if (null == clusterSettingRequest.getClusterName()
+                    || StringUtils.isEmpty(clusterSettingRequest.getClusterSettingName())) {
+                // FIXME throw correct error
+                throw new AmbariException("invalid arguments");
+            } else {
+
+                // TODO : IS 'CLUSTER_MODIFY_CONFIGS' the correct authorization field to be used ?
+                if (!AuthorizationHelper.isAuthorized(
+                        ResourceType.CLUSTER, getClusterResourceId(clusterSettingRequest.getClusterName()),
+                        RoleAuthorization.CLUSTER_MODIFY_CONFIGS)) {
+                    throw new AuthorizationException("The user is not authorized to delete service groups");
+                }
+
+                ClusterSetting clusterSetting = clusters.getCluster(
+                        clusterSettingRequest.getClusterName()).getClusterSetting(
+                        clusterSettingRequest.getClusterSettingName());
+
+                removable.add(clusterSetting);
+            }
+        }
+
+        for (ClusterSetting clusterSetting : removable) {
+            clusterSetting.getCluster().deleteClusterSetting(clusterSetting.getClusterSettingName());
+        }
+    }
+
+
+    private void validateCreateRequests(Set<ClusterSettingRequest> requests, Clusters clusters)
+            throws AuthorizationException, AmbariException {
+
+        Map<String, Set<String>> clusterSettingNames = new HashMap<>();
+        Set<String> duplicates = new HashSet<>();
+        for (ClusterSettingRequest request : requests) {
+            final String clusterName = request.getClusterName();
+            final String clusterSettingName = request.getClusterSettingName();
+
+            Validate.notNull(clusterName, "Cluster name should be provided when creating a 'cluster setting'");
+            Validate.notEmpty(clusterSettingName, "'Cluster Setting name' should be provided when creating a 'cluster setting'");
+
+            LOG.debug("Received a createClusterSetting request, clusterName= {}, clusterSettingName : {}, " +
+                    "request : {}", clusterName, clusterSettingName, request);
+
+            if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,
+                    getClusterResourceId(clusterName), RoleAuthorization.CLUSTER_MODIFY_CONFIGS)) {
+                throw new AuthorizationException("The user is not authorized to add/create cluster settings");
+            }
+
+            clusterSettingNames.computeIfAbsent(clusterName, k -> new HashSet<>());
+
+            if (clusterSettingNames.get(clusterName).contains(clusterSettingName)) {
+                // throw error later for dup
+                duplicates.add(clusterSettingName);
+                continue;
+            }
+            clusterSettingNames.get(clusterName).add(clusterSettingName);
+
+            Cluster cluster;
+            try {
+                cluster = clusters.getCluster(clusterName);
+            } catch (ClusterNotFoundException e) {
+                throw new ParentObjectNotFoundException("Attempted to add a 'cluster setting' to a cluster which doesn't exist", e);
+            }
+            try {
+                ClusterSetting cs = cluster.getClusterSetting(clusterSettingName);
+                if (cs != null) {
+                    // throw error later for dup
+                    duplicates.add(clusterSettingName);
+                    continue;
+                }
+            } catch (ClusterSettingNotFoundException e) {
+                // Expected
+            }
+        }
+        // ensure only a single cluster update
+        if (clusterSettingNames.size() != 1) {
+            throw new IllegalArgumentException("Invalid arguments, updates allowed" +
+                    "on only one cluster at a time");
+        }
+
+        // Validate dups
+        if (!duplicates.isEmpty()) {
+            String clusterName = requests.iterator().next().getClusterName();
+            String msg = "Attempted to add/create a 'cluster setting' which already exists: " +
+                    ", clusterName=" + clusterName + " clusterSettingName=" + StringUtils.join(duplicates, ",");
+
+            throw new DuplicateResourceException(msg);
+        }
+    }
+
+    private void validateUpdateRequests(Set<ClusterSettingRequest> requests, Clusters clusters)
+            throws AuthorizationException, AmbariException {
+
+        Map<String, Set<String>> clusterSettingNames = new HashMap<>();
+        Set<String> duplicates = new HashSet<>();
+        Set<String> nonExisting = new HashSet<>();
+        for (ClusterSettingRequest request : requests) {
+            final String clusterName = request.getClusterName();
+            final String clusterSettingName = request.getClusterSettingName();
+
+            Validate.notNull(clusterName, "Cluster name should be provided when updating a 'cluster setting'");
+            Validate.notEmpty(clusterSettingName, "'Cluster Setting name' should be provided when creating a 'cluster setting'");
+
+            LOG.debug("Received a updateClusterSetting request, clusterName= {}, clusterSettingName : {}, " +
+                    "request : {}", clusterName, clusterSettingName, request);
+
+            if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,
+                    getClusterResourceId(clusterName), RoleAuthorization.CLUSTER_MODIFY_CONFIGS)) {
+                throw new AuthorizationException("The user is not authorized to update cluster settings");
+            }
+
+            clusterSettingNames.computeIfAbsent(clusterName, k -> new HashSet<>());
+
+            if (clusterSettingNames.get(clusterName).contains(clusterSettingName)) {
+                // throw error later for dup
+                duplicates.add(clusterSettingName);
+                continue;
+            }
+            clusterSettingNames.get(clusterName).add(clusterSettingName);
+
+            Cluster cluster;
+            try {
+                cluster = clusters.getCluster(clusterName);
+            } catch (ClusterNotFoundException e) {
+                throw new ParentObjectNotFoundException("Attempted to update a 'cluster setting' to a cluster which doesn't exist", e);
+            }
+            try {
+                ClusterSetting cs = cluster.getClusterSetting(clusterSettingName);
+                if (cs == null) {
+                    // throw error later for it not being present.
+                    nonExisting.add(clusterSettingName);
+                    continue;
+                }
+            } catch (ClusterSettingNotFoundException e) {
+                // Expected
+            }
+        }
+        // ensure only a single cluster update
+        if (clusterSettingNames.size() != 1) {
+            throw new IllegalArgumentException("Invalid arguments, updates allowed" +
+                    "on only one cluster at a time");
+        }
+
+        // Validate dups
+        if (!duplicates.isEmpty()) {
+            String clusterName = requests.iterator().next().getClusterName();
+            String msg = "Attempted to update a 'cluster setting' which has more than one occurrence: " +
+                    ", clusterName=" + clusterName + " clusterSettingName=" + StringUtils.join(nonExisting, ",");
+
+            throw new DuplicateResourceException(msg);
+        }
+
+        // Validate non existing one(s)
+        if (!nonExisting.isEmpty()) {
+            String clusterName = requests.iterator().next().getClusterName();
+            String msg = "Attempted to update a 'cluster setting' which doesn't exist: " +
+                    ", clusterName=" + clusterName + " clusterSettingName=" + StringUtils.join(nonExisting, ",");
+
+            throw new PropertyNotFoundException(msg);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index 2f8f65f..674b352 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -78,6 +78,8 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new ViewPermissionResourceProvider();
       case ClusterPrivilege:
         return new ClusterPrivilegeResourceProvider();
+      case ClusterSetting:
+        return new ClusterSettingResourceProvider(managementController);
       case LdapSyncEvent:
         return new LdapSyncEventResourceProvider(managementController);
       case UserPrivilege:

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
index 2e935af..baccc10 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
@@ -314,7 +314,7 @@ public class ServiceGroupResourceProvider extends AbstractControllerResourceProv
     return response;
   }
 
-  // Get services from the given request.
+  // Get services groups from the given request.
   private Set<ServiceGroupResponse> getServiceGroups(ServiceGroupRequest request)
     throws AmbariException {
     if (request.getClusterName() == null) {
@@ -349,7 +349,7 @@ public class ServiceGroupResourceProvider extends AbstractControllerResourceProv
   }
 
 
-  // Delete services based on the given set of requests
+  // Delete services groups based on the given set of requests
   protected void deleteServiceGroups(Set<ServiceGroupRequest> request)
     throws AmbariException, AuthorizationException {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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 31b7517..64ea97b 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
@@ -76,6 +76,7 @@ public interface Resource {
   enum InternalType {
     Cluster,
     RootClusterSetting,
+    ClusterSetting,
     Service,
     ServiceDependency,
     ServiceGroup,
@@ -210,6 +211,7 @@ public interface Resource {
      */
     public static final Type Cluster = InternalType.Cluster.getType();
     public static final Type RootClusterSetting = InternalType.RootClusterSetting.getType();
+    public static final Type ClusterSetting = InternalType.ClusterSetting.getType();
     public static final Type ServiceGroup = InternalType.ServiceGroup.getType();
     public static final Type ServiceGroupDependency = InternalType.ServiceGroupDependency.getType();
     public static final Type Service = InternalType.Service.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterSettingEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterSettingEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterSettingEvent.java
new file mode 100644
index 0000000..3d32831
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterSettingEvent.java
@@ -0,0 +1,46 @@
+/**
+ * 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.events;
+
+
+public abstract class ClusterSettingEvent extends ClusterEvent {
+
+    /**
+     * The name of the 'cluster setting'.
+     */
+    protected final String m_clusterSettingName;
+
+    /**
+     * Constructor.
+     *
+     * @param eventType
+     * @param clusterId
+     */
+    public ClusterSettingEvent(AmbariEventType eventType, long clusterId, String clusterSettingName) {
+        super(eventType, clusterId);
+        m_clusterSettingName = clusterSettingName;
+    }
+
+    /**
+     * @return the cluster setting name (never {@code null}).
+     */
+    public String getServiceGroupName() {
+        return m_clusterSettingName;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterSettingDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterSettingDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterSettingDAO.java
new file mode 100644
index 0000000..7fa7adc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterSettingDAO.java
@@ -0,0 +1,100 @@
+/**
+ * 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.orm.dao;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.ClusterSettingEntity;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+
+@Singleton
+public class ClusterSettingDAO {
+    @Inject
+    Provider<EntityManager> entityManagerProvider;
+    @Inject
+    DaoUtils daoUtils;
+
+    @RequiresSession
+    public ClusterSettingEntity findByPK(Long clusterSettingId) {
+        TypedQuery<ClusterSettingEntity> query = entityManagerProvider.get()
+                .createNamedQuery("clusterSettingById", ClusterSettingEntity.class);
+        query.setParameter("clusterSettingId", clusterSettingId);
+
+        try {
+            return query.getSingleResult();
+        } catch (NoResultException ignored) {
+            return null;
+        }
+    }
+
+    @RequiresSession
+    public ClusterSettingEntity findByClusterIdAndSettingName(Long clusterId, String clusterSettingName) {
+        TypedQuery<ClusterSettingEntity> query = entityManagerProvider.get()
+                .createNamedQuery("clusterSettingByClusterIdAndSettingName", ClusterSettingEntity.class);
+        query.setParameter("clusterId", clusterId);
+        query.setParameter("clusterSettingName", clusterSettingName);
+
+        try {
+            return query.getSingleResult();
+        } catch (NoResultException ignored) {
+            return null;
+        }
+    }
+
+    @RequiresSession
+    public List<ClusterSettingEntity> findAll() {
+        return daoUtils.selectAll(entityManagerProvider.get(), ClusterSettingEntity.class);
+    }
+
+    @Transactional
+    public void refresh(ClusterSettingEntity clusterSettingEntity) {
+        entityManagerProvider.get().refresh(clusterSettingEntity);
+    }
+
+    @Transactional
+    public void create(ClusterSettingEntity clusterSettingEntity) {
+        entityManagerProvider.get().persist(clusterSettingEntity);
+    }
+
+    @Transactional
+    public ClusterSettingEntity merge(ClusterSettingEntity clusterSettingEntity) {
+        return entityManagerProvider.get().merge(clusterSettingEntity);
+    }
+
+    @Transactional
+    public void remove(ClusterSettingEntity clusterSettingEntity) {
+        entityManagerProvider.get().remove(merge(clusterSettingEntity));
+    }
+
+    @Transactional
+    public void removeByPK(Long clusterId) {
+        ClusterSettingEntity entity = findByPK(clusterId);
+        entityManagerProvider.get().remove(entity);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
index abbf709..793f1a1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
@@ -108,6 +108,9 @@ public class ClusterEntity {
   @OneToMany(mappedBy = "clusterEntity")
   private Collection<ServiceGroupEntity> serviceGroupEntities;
 
+  @OneToMany(mappedBy = "clusterEntity")
+  private Collection<ClusterSettingEntity> clusterSettingEntities;
+
   @OneToOne(mappedBy = "clusterEntity", cascade = CascadeType.REMOVE)
   private ClusterStateEntity clusterStateEntity;
 
@@ -281,6 +284,14 @@ public class ClusterEntity {
     this.serviceGroupEntities = serviceGroupEntities;
   }
 
+  public Collection<ClusterSettingEntity> getClusterSettingEntities() {
+    return clusterSettingEntities;
+  }
+
+  public void setClusterSettingEntities(Collection<ClusterSettingEntity> clusterSettingEntities) {
+    this.clusterSettingEntities = clusterSettingEntities;
+  }
+
   public ClusterStateEntity getClusterStateEntity() {
     return clusterStateEntity;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterSettingEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterSettingEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterSettingEntity.java
new file mode 100644
index 0000000..10a829c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterSettingEntity.java
@@ -0,0 +1,131 @@
+/**
+ * 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.orm.entities;
+
+import java.util.Objects;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+
+
+@Table(name = "clustersettings")
+@NamedQueries({
+        @NamedQuery(name = "clusterSettingByClusterIdAndSettingName", query =
+                "SELECT clusterSetting " +
+                        "FROM ClusterSettingEntity clusterSetting " +
+                        "JOIN clusterSetting.clusterEntity cluster " +
+                        "WHERE clusterSetting.clusterSettingName=:clusterSettingName AND cluster.clusterId=:clusterId"),
+        @NamedQuery(name = "clusterSettingById", query =
+                "SELECT clusterSetting " +
+                        "FROM ClusterSettingEntity clusterSetting " +
+                        "WHERE clusterSetting.clusterSettingId=:clusterSettingId"),
+})
+@Entity
+@TableGenerator(name = "cluster_setting_id_generator",
+        table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
+        , pkColumnValue = "cluster_setting_id_seq"
+        , initialValue = 1
+)
+public class ClusterSettingEntity {
+
+    @Id
+    @Column(name = "id", nullable = false, insertable = true, updatable = true)
+    @GeneratedValue(strategy = GenerationType.TABLE, generator = "cluster_setting_id_generator")
+    private Long clusterSettingId;
+
+    @Column(name = "cluster_id", nullable = false, insertable = false, updatable = false, length = 10)
+    private Long clusterId;
+
+    @Column(name = "setting_name", nullable = false, insertable = true, updatable = false)
+    private String clusterSettingName;
+
+    @Column(name = "setting_value", nullable = false, insertable = true, updatable = true)
+    private String clusterSettingValue;
+
+    @ManyToOne
+    @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false)
+    private ClusterEntity clusterEntity;
+
+    public Long getClusterId() {
+        return clusterId;
+    }
+
+    public void setClusterId(Long clusterId) {
+        this.clusterId = clusterId;
+    }
+
+    public Long getClusterSettingId() {
+        return clusterSettingId;
+    }
+
+    public void setClusterSettingId(Long clusterSettingId) {
+        this.clusterSettingId = clusterSettingId;
+    }
+
+
+    public String getClusterSettingName() {
+        return clusterSettingName;
+    }
+
+    public void setClusterSettingName(String clusterSettingName) {
+        this.clusterSettingName = clusterSettingName;
+    }
+
+    public String getClusterSettingValue() {
+        return clusterSettingValue;
+    }
+
+    public void setClusterSettingValue(String clusterSettingValue) {
+        this.clusterSettingValue = clusterSettingValue;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ClusterSettingEntity that = (ClusterSettingEntity) o;
+        return Objects.equals(clusterId, that.clusterId) &&
+               Objects.equals(clusterSettingName, that.clusterSettingName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(clusterId, clusterSettingName);
+    }
+
+    public ClusterEntity getClusterEntity() {
+        return clusterEntity;
+    }
+
+    public void setClusterEntity(ClusterEntity clusterEntity) {
+        this.clusterEntity = clusterEntity;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/49592068/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
index 3b74e69..8bd24f2 100644
--- 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
@@ -65,7 +65,7 @@ public class RootLevelSettingsManager {
     clusterSettingsFileName = settingsFileName;
     clusterSettingsConfigType = settingsTypeName;
     clusterSettingsFile = new File(clusterSettingsPath + File.separator + clusterSettingsFileName);
-    LOG.info("\n\n\n\n SWAP - clusterSettingsPath = "+clusterSettingsPath+" - clusterSettingsFileName = "+clusterSettingsFileName
+    LOG.debug("clusterSettingsPath = "+clusterSettingsPath+" - clusterSettingsFileName = "+clusterSettingsFileName
             +" - clusterSettingsConfigType = "+clusterSettingsFile + "clusterSettingsFile = "+clusterSettingsFile);
     populateClusterSettingsXml();
   }