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

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

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>