You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mp...@apache.org on 2014/07/30 23:37:29 UTC

[3/3] git commit: AMBARI-6660. Implement service config versions. (mpapirkovskyy)

AMBARI-6660. Implement service config versions. (mpapirkovskyy)


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

Branch: refs/heads/trunk
Commit: ce4020028973fadaa79f1bacea649de0b61dbe0c
Parents: a84a653
Author: Myroslav Papirkovskyy <mp...@hortonworks.com>
Authored: Wed Jul 30 19:19:56 2014 +0300
Committer: Myroslav Papirkovskyy <mp...@hortonworks.com>
Committed: Thu Jul 31 00:14:52 2014 +0300

----------------------------------------------------------------------
 .../resources/ClusterResourceDefinition.java    |   1 +
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../ServiceConfigVersionResourceDefinition.java |  80 ++++
 .../api/services/ConfigurationService.java      |   6 +
 .../services/ServiceConfigVersionService.java   |  57 +++
 .../controller/AmbariManagementController.java  |  18 +-
 .../AmbariManagementControllerImpl.java         | 154 ++++++--
 .../server/controller/ClusterRequest.java       |  11 +-
 .../server/controller/ClusterResponse.java      |  10 +
 .../server/controller/ConfigurationRequest.java |   9 +
 .../controller/ConfigurationResponse.java       |  46 ++-
 .../controller/ServiceConfigVersionRequest.java |  89 +++++
 .../ServiceConfigVersionResponse.java           | 104 +++++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/AbstractProviderModule.java        |   2 +-
 .../internal/AbstractResourceProvider.java      |   1 +
 .../internal/ClusterResourceProvider.java       |  72 +++-
 .../internal/ConfigGroupResourceProvider.java   |   2 +-
 .../internal/ConfigurationResourceProvider.java |   3 +
 .../internal/HostResourceProvider.java          |   5 +-
 .../ServiceConfigVersionResourceProvider.java   | 168 ++++++++
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../ambari/server/orm/dao/ClusterDAO.java       |  23 +-
 .../ambari/server/orm/dao/ServiceConfigDAO.java | 116 ++++++
 .../orm/entities/ClusterConfigEntity.java       |  62 ++-
 .../orm/entities/ClusterConfigEntityPK.java     |  83 ----
 .../entities/ClusterConfigMappingEntity.java    |  19 +-
 .../server/orm/entities/ClusterEntity.java      |  10 +
 .../ServiceConfigApplicationEntity.java         | 102 +++++
 .../orm/entities/ServiceConfigEntity.java       | 146 +++++++
 .../org/apache/ambari/server/state/Cluster.java |  38 +-
 .../org/apache/ambari/server/state/Config.java  |  22 +-
 .../ambari/server/state/ConfigHelper.java       |  11 +-
 .../apache/ambari/server/state/ConfigImpl.java  |  55 ++-
 .../server/state/ConfigVersionHelper.java       |  52 +++
 .../ambari/server/state/DesiredConfig.java      |  35 +-
 .../server/state/cluster/ClusterImpl.java       | 388 ++++++++++++++++---
 .../server/state/cluster/ClustersImpl.java      |   2 +
 .../state/configgroup/ConfigGroupImpl.java      |  22 +-
 .../ambari/server/state/host/HostImpl.java      |  14 +-
 .../server/upgrade/AbstractUpgradeCatalog.java  |   6 +-
 .../server/upgrade/UpgradeCatalog150.java       |  15 +-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  14 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  14 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  22 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |  27 +-
 .../src/main/resources/META-INF/persistence.xml |   2 +
 .../src/main/resources/key_properties.json      |   4 +
 .../src/main/resources/properties.json          |  12 +-
 .../ExecutionCommandWrapperTest.java            |   8 +-
 .../server/agent/TestHeartbeatMonitor.java      |   4 +-
 .../ClusterResourceDefinitionTest.java          |   3 +-
 .../AmbariManagementControllerTest.java         |  46 +--
 .../internal/ClusterResourceProviderTest.java   |   5 +
 .../ConfigGroupResourceProviderTest.java        |   6 +-
 .../ConfigurationResourceProviderTest.java      |  12 +-
 .../internal/JMXHostProviderTest.java           |   4 +-
 .../ambari/server/state/ConfigGroupTest.java    |  10 +-
 .../ambari/server/state/ConfigHelperTest.java   |  11 +-
 .../ambari/server/state/DesiredConfigTest.java  |   4 +-
 .../server/state/cluster/ClusterTest.java       |  21 +-
 .../server/state/cluster/ClustersTest.java      |   4 +-
 .../ambari/server/state/host/HostTest.java      |   6 +-
 .../svccomphost/ServiceComponentHostTest.java   |   8 +-
 .../server/upgrade/UpgradeCatalog150Test.java   |   9 +-
 .../server/upgrade/UpgradeCatalogTest.java      |   8 +-
 66 files changed, 1942 insertions(+), 389 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 644e8d2..86fc247 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
@@ -62,6 +62,7 @@ public class ClusterResourceDefinition extends BaseResourceDefinition {
     setChildren.add(new SubResourceDefinition(Resource.Type.Service));
     setChildren.add(new SubResourceDefinition(Resource.Type.Host));
     setChildren.add(new SubResourceDefinition(Resource.Type.Configuration));
+    setChildren.add(new SubResourceDefinition(Resource.Type.ServiceConfigVersion));
     setChildren.add(new SubResourceDefinition(Resource.Type.Request));
     setChildren.add(new SubResourceDefinition(Resource.Type.Workflow));
     setChildren.add(new SubResourceDefinition(Resource.Type.ConfigGroup));

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 5399404..3d198d6 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
@@ -109,6 +109,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new ConfigurationResourceDefinition();
         break;
 
+      case ServiceConfigVersion:
+        resourceDefinition = new ServiceConfigVersionResourceDefinition();
+        break;
+
       case Task:
         resourceDefinition = new TaskResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceConfigVersionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceConfigVersionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceConfigVersionResourceDefinition.java
new file mode 100644
index 0000000..a907166
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceConfigVersionResourceDefinition.java
@@ -0,0 +1,80 @@
+/*
+ * 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.api.services.Request;
+import org.apache.ambari.server.api.util.TreeNode;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ServiceConfigVersionResourceDefinition extends BaseResourceDefinition {
+  /**
+   * Constructor.
+   *
+   */
+  public ServiceConfigVersionResourceDefinition() {
+    super(Resource.Type.ServiceConfigVersion);
+  }
+
+  @Override
+  public List<PostProcessor> getPostProcessors() {
+    List<PostProcessor> listProcessors = super.getPostProcessors();
+    listProcessors.add(new HrefProcessor());
+
+    return listProcessors;
+  }
+
+  @Override
+  public String getPluralName() {
+    return "serviceconfigversions";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "serviceconfigversion";
+  }
+
+  private class HrefProcessor extends BaseHrefPostProcessor {
+
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      if (resultNode.getObject().getType() == Resource.Type.ServiceConfigVersion) {
+
+        if (! href.endsWith("/")) {
+          href += '/';
+        }
+
+        String clustersToken = "/clusters";
+        int idx = href.indexOf(clustersToken) + clustersToken.length() + 1;
+        idx = href.indexOf("/", idx) + 1;
+
+        String serviceName = (String) resultNode.getObject().getPropertyValue("service_name");
+        Long version = (Long) resultNode.getObject().getPropertyValue("serviceconfigversion");
+        href = href.substring(0, idx) + "cenfigurations/serviceconfigversions?service_name=" + serviceName + "&serviceconfigversion=" + version;
+
+        resultNode.setProperty("href", href);
+      } else {
+        super.process(request, resultNode, href);
+      }
+
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
index fd2f744..18fa335 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
@@ -50,6 +51,11 @@ public class ConfigurationService extends BaseService {
     m_clusterName = clusterName;
   }
 
+  @Path("serviceconfigversions")
+  public ServiceConfigVersionService getServiceConfigVersionService() {
+    return new ServiceConfigVersionService(m_clusterName);
+  }
+
   /**
    * Handles URL: /clusters/{clusterId}/configurations
    * Get all services for a cluster.

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
new file mode 100644
index 0000000..03a64e2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ServiceConfigVersionService extends BaseService {
+  /**
+   * Parent cluster name.
+   */
+  private String m_clusterName;
+
+  public ServiceConfigVersionService(String m_clusterName) {
+    this.m_clusterName = m_clusterName;
+  }
+
+  @GET
+  @Produces("text/plain")
+  public Response getServiceConfigVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET, createServiceConfigResource(m_clusterName));
+  }
+
+
+  ResourceInstance createServiceConfigResource(String clusterName) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.ServiceConfigVersion, null);
+
+    return createResource(Resource.Type.ServiceConfigVersion, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 b2c5ed0..ab03b30 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
@@ -75,7 +75,7 @@ public interface AmbariManagementController {
    *
    * @throws AmbariException when the configuration cannot be created.
    */
-  public void createConfiguration(ConfigurationRequest request)
+  public ConfigurationResponse createConfiguration(ConfigurationRequest request)
       throws AmbariException;
 
   /**
@@ -158,6 +158,15 @@ public interface AmbariManagementController {
       throws AmbariException;
 
   /**
+   * Get service config version history
+   * @param requests service config version requests
+   * @return service config versions
+   * @throws AmbariException
+   */
+  Set<ServiceConfigVersionResponse> getServiceConfigVersions(Set<ServiceConfigVersionRequest> requests)
+      throws AmbariException;
+
+  /**
    * Gets the users identified by the given request objects.
    *
    * @param requests the request objects
@@ -636,6 +645,13 @@ public interface AmbariManagementController {
   public ExecutionScheduleManager getExecutionScheduleManager();
 
   /**
+   * Get cached clusterUpdateResults, used only for service config versions currently
+   * @param clusterRequest
+   * @return
+   */
+  ClusterResponse getClusterUpdateResults(ClusterRequest clusterRequest);
+
+  /**
    * Get JobTracker hostname
    */
   public String getJobTrackerHost(Cluster cluster);

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 b25e56c..ef031e6 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
@@ -18,6 +18,8 @@
 
 package org.apache.ambari.server.controller;
 
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
 import com.google.gson.Gson;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -28,18 +30,11 @@ import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
@@ -136,6 +131,7 @@ import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
 import org.apache.http.client.utils.URIBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -214,6 +210,9 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   final private String serverDB;
   final private String mysqljdbcUrl;
 
+  private Cache<ClusterRequest, ClusterResponse> clusterUpdateCache =
+      CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
+
   @Inject
   private AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
   @Inject
@@ -599,14 +598,13 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
 
   @Override
-  public synchronized void createConfiguration(
+  public synchronized ConfigurationResponse createConfiguration(
       ConfigurationRequest request) throws AmbariException {
     if (null == request.getClusterName() || request.getClusterName().isEmpty()
         || null == request.getType() || request.getType().isEmpty()
-        || null == request.getVersionTag() || request.getVersionTag().isEmpty()
         || null == request.getProperties()) {
       throw new IllegalArgumentException("Invalid Arguments,"
-          + " clustername, config type, config version and configs should not"
+          + " clustername, config type and configs should not"
           + " be null or empty");
     }
 
@@ -632,11 +630,17 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
     Config config = configFactory.createNew (cluster, request.getType(),
         request.getProperties(), propertiesAttributes);
-    config.setVersionTag(request.getVersionTag());
+
+    if (!StringUtils.isEmpty(request.getVersionTag())) {
+      config.setTag(request.getVersionTag());
+    }
 
     config.persist();
 
     cluster.addConfig(config);
+
+    return new ConfigurationResponse(cluster.getClusterName(), config.getType(), config.getTag(), config.getVersion(),
+        config.getProperties(), config.getPropertiesAttributes());
   }
 
   @Override
@@ -767,20 +771,22 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           + ", stackInfo=" + request.getStackVersion());
     }
 
+    Cluster singleCluster = null;
     if (request.getClusterName() != null) {
-      Cluster c = clusters.getCluster(request.getClusterName());
-      ClusterResponse cr = c.convertToResponse();
-      cr.setDesiredConfigs(c.getDesiredConfigs());
-      response.add(cr);
-      return response;
+      singleCluster = clusters.getCluster(request.getClusterName());
     } else if (request.getClusterId() != null) {
-      Cluster c = clusters.getClusterById(request.getClusterId());
-      ClusterResponse cr = c.convertToResponse();
-      cr.setDesiredConfigs(c.getDesiredConfigs());
+      singleCluster = clusters.getClusterById(request.getClusterId());
+    }
+
+    if (singleCluster != null) {
+      ClusterResponse cr = singleCluster.convertToResponse();
+      cr.setDesiredConfigs(singleCluster.getDesiredConfigs());
+      cr.setDesiredServiceConfigVersions(singleCluster.getActiveServiceConfigVersions());
       response.add(cr);
       return response;
     }
 
+
     Map<String, Cluster> allClusters = clusters.getClusters();
     for (Cluster c : allClusters.values()) {
       if (request.getStackVersion() != null) {
@@ -1017,7 +1023,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           request.getVersionTag());
       if (null != config) {
         ConfigurationResponse response = new ConfigurationResponse(
-            cluster.getClusterName(), config.getType(), config.getVersionTag(),
+            cluster.getClusterName(), config.getType(), config.getTag(), config.getVersion(),
             config.getProperties(), config.getPropertiesAttributes());
         responses.add(response);
       }
@@ -1031,7 +1037,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           for (Entry<String, Config> entry : configs.entrySet()) {
             ConfigurationResponse response = new ConfigurationResponse(
                 cluster.getClusterName(), request.getType(),
-                entry.getValue().getVersionTag(), new HashMap<String, String>(),
+                entry.getValue().getTag(), entry.getValue().getVersion(), new HashMap<String, String>(),
                 new HashMap<String, Map<String,String>>());
             responses.add(response);
           }
@@ -1042,7 +1048,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
         for (Config config : all) {
           ConfigurationResponse response = new ConfigurationResponse(
-             cluster.getClusterName(), config.getType(), config.getVersionTag(),
+             cluster.getClusterName(), config.getType(), config.getTag(), config.getVersion(),
              new HashMap<String, String>(), new HashMap<String, Map<String,String>>());
 
           responses.add(response);
@@ -1084,6 +1090,9 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         + ", request=" + request);
 
     final Cluster cluster = clusters.getCluster(request.getClusterName());
+    //save data to return configurations created
+    ConfigurationResponse configurationResponse = null;
+    ServiceConfigVersionResponse serviceConfigVersionResponse = null;
 
     // set or create configuration mapping (and optionally create the map of properties)
     if (null != request.getDesiredConfig()) {
@@ -1104,21 +1113,21 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
               request.getClusterName()));
 
           cr.setClusterName(cluster.getClusterName());
-          createConfiguration(cr);
+          configurationResponse = createConfiguration(cr);
         }
       }
 
       Config baseConfig = cluster.getConfig(cr.getType(), cr.getVersionTag());
       if (null != baseConfig) {
         String authName = getAuthName();
-
-        if (cluster.addDesiredConfig(authName, baseConfig)) {
+        serviceConfigVersionResponse = cluster.addDesiredConfig(authName, baseConfig);
+        if (serviceConfigVersionResponse != null) {
           Logger logger = LoggerFactory.getLogger("configchange");
           logger.info("cluster '" + request.getClusterName() + "' "
               + "changed by: '" + authName + "'; "
               + "type='" + baseConfig.getType() + "' "
-              + "tag='" + baseConfig.getVersionTag() + "'"
-              + (null == oldConfig ? "" : " from='"+ oldConfig.getVersionTag() + "'"));
+              + "tag='" + baseConfig.getTag() + "'"
+              + (null == oldConfig ? "" : " from='"+ oldConfig.getTag() + "'"));
         }
       }
     }
@@ -1177,9 +1186,53 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       cluster.setProvisioningState(provisioningState);
     }
 
+    if (null != request.getServiceConfigVersionRequest()) {
+      ServiceConfigVersionRequest serviceConfigVersionRequest = request.getServiceConfigVersionRequest();
+      if (StringUtils.isEmpty(serviceConfigVersionRequest.getServiceName()) ||
+          null == serviceConfigVersionRequest.getVersion()) {
+        String msg = "Service name and version should be specified in service config version";
+        LOG.error(msg);
+        throw new IllegalArgumentException(msg);
+      }
+
+      cluster.setServiceConfigVersion(serviceConfigVersionRequest.getServiceName(),
+          serviceConfigVersionRequest.getVersion(), getAuthName());
+    }
+
+    if (serviceConfigVersionResponse != null) {
+      if (configurationResponse != null) {
+        serviceConfigVersionResponse.setConfigurations(Collections.singletonList(configurationResponse));
+      }
+
+      ClusterResponse clusterResponse =
+          new ClusterResponse(cluster.getClusterId(), cluster.getClusterName(), null, null, null, null, null);
+
+      clusterResponse.setDesiredServiceConfigVersions(
+          Collections.singletonMap(serviceConfigVersionResponse.getServiceName(), serviceConfigVersionResponse));
+
+      //workaround to be able to retrieve update results in resource provider
+      //as this method only expected to return request response
+      saveClusterUpdate(request, clusterResponse);
+    }
+
     return null;
   }
 
+  /**
+   * Save cluster update results to retrieve later
+   * @param clusterRequest
+   * @param clusterResponse
+   */
+  public void saveClusterUpdate(ClusterRequest clusterRequest, ClusterResponse clusterResponse) {
+    clusterUpdateCache.put(clusterRequest, clusterResponse);
+  }
+
+
+  @Override
+  public ClusterResponse getClusterUpdateResults(ClusterRequest clusterRequest) {
+    return clusterUpdateCache.getIfPresent(clusterRequest);
+  }
+
   public String getJobTrackerHost(Cluster cluster) {
     try {
       Service svc = cluster.getService("MAPREDUCE");
@@ -2574,6 +2627,45 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
+  public Set<ServiceConfigVersionResponse> getServiceConfigVersions(Set<ServiceConfigVersionRequest> requests)
+      throws AmbariException {
+    Set<ServiceConfigVersionResponse> responses = new LinkedHashSet<ServiceConfigVersionResponse>();
+
+    for (ServiceConfigVersionRequest request : requests) {
+      responses.addAll(getServiceConfigVersions(request));
+    }
+
+    return responses;
+  }
+
+  private Set<ServiceConfigVersionResponse> getServiceConfigVersions(ServiceConfigVersionRequest request)
+      throws AmbariException {
+    if (request.getClusterName() == null) {
+      throw new IllegalArgumentException("Invalid arguments, cluster name"
+          + " should not be null");
+    }
+
+    Cluster cluster = clusters.getCluster(request.getClusterName());
+
+    Set<ServiceConfigVersionResponse> result = new LinkedHashSet<ServiceConfigVersionResponse>();
+
+    for (ServiceConfigVersionResponse response : cluster.getServiceConfigVersions()) {
+      if (request.getServiceName() != null && !StringUtils.equals(request.getServiceName(), response.getServiceName())) {
+        continue;
+      }
+      if (request.getVersion() != null && NumberUtils.compare(request.getVersion(), response.getVersion()) != 0) {
+        continue;
+      }
+      if (request.getUserName() != null && !StringUtils.equals(request.getUserName(), response.getUserName())) {
+        continue;
+      }
+      result.add(response);
+    }
+
+    return result;
+  }
+
+  @Override
   public Set<UserResponse> getUsers(Set<UserRequest> requests)
       throws AmbariException {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
index d5d55a1..14cc6be 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
@@ -37,6 +37,8 @@ public class ClusterRequest {
   
   private ConfigurationRequest config = null;
 
+  private ServiceConfigVersionRequest serviceConfigVersionRequest = null;
+
   public ClusterRequest(Long clusterId, String clusterName, 
       String stackVersion, Set<String> hostNames) {
     this(clusterId, clusterName, null, stackVersion, hostNames);
@@ -163,6 +165,13 @@ public class ClusterRequest {
     sb.append("] }");
     return sb.toString();
   }
-  
 
+
+  public ServiceConfigVersionRequest getServiceConfigVersionRequest() {
+    return serviceConfigVersionRequest;
+  }
+
+  public void setServiceConfigVersionRequest(ServiceConfigVersionRequest serviceConfigVersionRequest) {
+    this.serviceConfigVersionRequest = serviceConfigVersionRequest;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java
index e8a60c8..dc83474 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java
@@ -36,6 +36,8 @@ public class ClusterResponse {
   private final String desiredStackVersion;
 
   private Map<String, DesiredConfig> desiredConfigs;
+
+  private Map<String, ServiceConfigVersionResponse> desiredServiceConfigVersions;
   
   private String provisioningState;
 
@@ -177,4 +179,12 @@ public class ClusterResponse {
   public ClusterHealthReport getClusterHealthReport() {
     return clusterHealthReport;
   }
+
+  public Map<String, ServiceConfigVersionResponse> getDesiredServiceConfigVersions() {
+    return desiredServiceConfigVersions;
+  }
+
+  public void setDesiredServiceConfigVersions(Map<String, ServiceConfigVersionResponse> desiredServiceConfigVersions) {
+    this.desiredServiceConfigVersions = desiredServiceConfigVersions;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
index ba15afd..0130de4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
@@ -30,6 +30,7 @@ public class ConfigurationRequest {
   private String clusterName;
   private String type;
   private String tag;
+  private Long version;
   private Map<String, String> configs;
   private boolean selected = true;
   private Map<String, Map<String, String>> configsAttributes;
@@ -137,4 +138,12 @@ public class ConfigurationRequest {
       Map<String, Map<String, String>> configsAttributes) {
     this.configsAttributes = configsAttributes;
   }
+
+  public Long getVersion() {
+    return version;
+  }
+
+  public void setVersion(Long version) {
+    this.version = version;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
index 86b1a3a..dd5c667 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.controller;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -32,12 +33,17 @@ public class ConfigurationResponse {
 
   private String versionTag;
 
+  private Long version;
+
+  private List<Long> serviceConfigVersions;
+
   private Map<String, String> configs;
 
   private Map<String, Map<String, String>> configAttributes;
 
   public ConfigurationResponse(String clusterName,
                                String type, String versionTag,
+                               Long version,
                                Map<String, String> configs,
                                Map<String, Map<String, String>> configAttributes) {
     super();
@@ -45,6 +51,7 @@ public class ConfigurationResponse {
     this.configs = configs;
     this.type = type;
     this.versionTag = versionTag;
+    this.version = version;
     this.configs = configs;
     this.configAttributes = configAttributes;
   }
@@ -100,26 +107,24 @@ public class ConfigurationResponse {
     return clusterName;
   }
 
+  public Long getVersion() {
+    return version;
+  }
+
+  public void setVersion(Long version) {
+    this.version = version;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
 
-    ConfigurationResponse that =
-        (ConfigurationResponse) o;
-
-    if (clusterName != null ?
-        !clusterName.equals(that.clusterName) : that.clusterName != null) {
-      return false;
-    }
-    if (type != null ?
-        !type.equals(that.type) : that.type != null) {
-      return false;
-    }
-    if (versionTag != null ?
-        !versionTag.equals(that.versionTag) : that.versionTag != null){
-      return false;
-    }
+    ConfigurationResponse that = (ConfigurationResponse) o;
+
+    if (clusterName != null ? !clusterName.equals(that.clusterName) : that.clusterName != null) return false;
+    if (type != null ? !type.equals(that.type) : that.type != null) return false;
+    if (version != null ? !version.equals(that.version) : that.version != null) return false;
 
     return true;
   }
@@ -127,9 +132,16 @@ public class ConfigurationResponse {
   @Override
   public int hashCode() {
     int result = clusterName != null ? clusterName.hashCode() : 0;
-    result = 71 * result + (type != null ? type.hashCode() : 0);
-    result = 71 * result + (versionTag != null ? versionTag.hashCode():0);
+    result = 31 * result + (type != null ? type.hashCode() : 0);
+    result = 31 * result + (version != null ? version.hashCode() : 0);
     return result;
   }
 
+  public List<Long> getServiceConfigVersions() {
+    return serviceConfigVersions;
+  }
+
+  public void setServiceConfigVersions(List<Long> serviceConfigVersions) {
+    this.serviceConfigVersions = serviceConfigVersions;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionRequest.java
new file mode 100644
index 0000000..4784970
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionRequest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+public class ServiceConfigVersionRequest {
+  private String clusterName;
+  private String serviceName;
+  private Long version;
+  private Long createTime;
+  private Long applyTime;
+  private String userName;
+
+  public ServiceConfigVersionRequest() {
+  }
+
+  public ServiceConfigVersionRequest(String clusterName, String serviceName, Long version, Long createTime, Long applyTime, String userName) {
+    this.clusterName = clusterName;
+    this.serviceName = serviceName;
+    this.version = version;
+    this.createTime = createTime;
+    this.applyTime = applyTime;
+    this.userName = userName;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  public Long getVersion() {
+    return version;
+  }
+
+  public void setVersion(Long version) {
+    this.version = version;
+  }
+
+  public Long getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(Long createTime) {
+    this.createTime = createTime;
+  }
+
+  public Long getApplyTime() {
+    return applyTime;
+  }
+
+  public void setApplyTime(Long applyTime) {
+    this.applyTime = applyTime;
+  }
+
+  public String getUserName() {
+    return userName;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionResponse.java
new file mode 100644
index 0000000..765e765
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceConfigVersionResponse.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+
+import org.apache.ambari.server.state.Config;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.List;
+
+public class ServiceConfigVersionResponse {
+  private String clusterName;
+  private String serviceName;
+  private Long version;
+  private Long createTime;
+  private Long applyTime;
+  private String userName;
+  private List<ConfigurationResponse> configurations;
+
+  @JsonProperty("service_name")
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  @JsonProperty("serviceconfigversion")
+  public Long getVersion() {
+    return version;
+  }
+
+  public void setVersion(Long version) {
+    this.version = version;
+  }
+
+  @JsonProperty("createtime")
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+  public Long getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(Long createTime) {
+    this.createTime = createTime;
+  }
+
+  @JsonProperty("appliedtime")
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+  public Long getApplyTime() {
+    return applyTime;
+  }
+
+  public void setApplyTime(Long applyTime) {
+    this.applyTime = applyTime;
+  }
+
+  @JsonProperty("user")
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+  public String getUserName() {
+    return userName;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  @JsonProperty("cluster_name")
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+  public List<ConfigurationResponse> getConfigurations() {
+    return configurations;
+  }
+
+  public void setConfigurations(List<ConfigurationResponse> configurations) {
+    this.configurations = configurations;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 028bf41..7224d7a 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
@@ -104,6 +104,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return resourceProviderFactory.getHostComponentResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Configuration:
         return new ConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case ServiceConfigVersion:
+        return new ServiceConfigVersionResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Action:
         return new ActionResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Request:

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
index c3fd56a..f7d2ed1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
@@ -623,7 +623,7 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
         if (configs != null) {
           DesiredConfig config = (DesiredConfig) configs.get(configType);
           if (config != null) {
-            versionTag = config.getVersion();
+            versionTag = config.getTag();
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java
index 8caa01b..01c526d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java
@@ -32,6 +32,7 @@ import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.ServiceConfigVersionRequest;
 import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
index a39e5ad..b72beb6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
@@ -29,12 +29,7 @@ import java.util.Set;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
-import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.ClusterRequest;
-import org.apache.ambari.server.controller.ClusterResponse;
-import org.apache.ambari.server.controller.ConfigGroupRequest;
-import org.apache.ambari.server.controller.ConfigurationRequest;
-import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.*;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -66,6 +61,7 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
   protected static final String CLUSTER_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "version");  
   protected static final String CLUSTER_PROVISIONING_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "provisioning_state");
   protected static final String CLUSTER_DESIRED_CONFIGS_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "desired_configs");
+  protected static final String CLUSTER_DESIRED_SERVICE_CONFIG_VERSIONS_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "desired_serviceconfigversions");
   protected static final String CLUSTER_TOTAL_HOSTS_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "total_hosts");
   protected static final String CLUSTER_HEALTH_REPORT_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "health_report");
   protected static final String BLUEPRINT_PROPERTY_ID = PropertyHelper.getPropertyId(null, "blueprint");
@@ -175,6 +171,7 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
       setResourceProperty(resource, CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), requestedIds);
       setResourceProperty(resource, CLUSTER_PROVISIONING_STATE_PROPERTY_ID, response.getProvisioningState(), requestedIds);
       setResourceProperty(resource, CLUSTER_DESIRED_CONFIGS_PROPERTY_ID, response.getDesiredConfigs(), requestedIds);
+      setResourceProperty(resource, CLUSTER_DESIRED_SERVICE_CONFIG_VERSIONS_PROPERTY_ID, response.getDesiredServiceConfigVersions(), requestedIds);
       setResourceProperty(resource, CLUSTER_TOTAL_HOSTS_PROPERTY_ID, response.getTotalHosts(), requestedIds);
       setResourceProperty(resource, CLUSTER_HEALTH_REPORT_PROPERTY_ID, response.getClusterHealthReport(), requestedIds);
       
@@ -211,7 +208,35 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
       }
     });
     notifyUpdate(Resource.Type.Cluster, request, predicate);
-    return getRequestStatus(response);
+
+    Set<Resource> associatedResources = null;
+    for (ClusterRequest clusterRequest : requests) {
+      ClusterResponse updateResults = getManagementController().getClusterUpdateResults(clusterRequest);
+      if (updateResults != null) {
+        Map<String, ServiceConfigVersionResponse> serviceConfigVersions = updateResults.getDesiredServiceConfigVersions();
+        if (serviceConfigVersions != null) {
+          associatedResources = new HashSet<Resource>();
+          for (Map.Entry<String, ServiceConfigVersionResponse> stringServiceConfigVersionResponseEntry : serviceConfigVersions.entrySet()) {
+            Resource resource = new ResourceImpl(Resource.Type.ServiceConfigVersion);
+            ServiceConfigVersionResponse serviceConfigVersionResponse = stringServiceConfigVersionResponseEntry.getValue();
+            resource.setProperty(ServiceConfigVersionResourceProvider.SERVICE_CONFIG_VERSION_SERVICE_NAME_PROPERTY_ID,
+                serviceConfigVersionResponse.getServiceName());
+            resource.setProperty(ServiceConfigVersionResourceProvider.SERVICE_CONFIG_VERSION_PROPERTY_ID,
+                serviceConfigVersionResponse.getVersion());
+            if (serviceConfigVersionResponse.getConfigurations() != null) {
+              resource.setProperty(
+                  ServiceConfigVersionResourceProvider.SERVICE_CONFIG_VERSION_CONFIGURATIONS_PROPERTY_ID,
+                  serviceConfigVersionResponse.getConfigurations());
+            }
+            associatedResources.add(resource);
+          }
+
+        }
+      }
+    }
+
+
+    return getRequestStatus(response, associatedResources);
   }
 
   @Override
@@ -272,13 +297,44 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
 
     ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
 
+    ServiceConfigVersionRequest serviceConfigVersionRequest = getServiceConfigVersionRequest("Clusters", properties);
+
     if (null != configRequest)
       cr.setDesiredConfig(configRequest);
 
+    if (serviceConfigVersionRequest != null) {
+      cr.setServiceConfigVersionRequest(serviceConfigVersionRequest);
+    }
+
     return cr;
   }
 
   /**
+   * Helper method for creating rollback request
+   */
+  protected ServiceConfigVersionRequest getServiceConfigVersionRequest(String parentCategory, Map<String, Object> properties) {
+    ServiceConfigVersionRequest serviceConfigVersionRequest = null;
+
+    for (Map.Entry<String, Object> entry : properties.entrySet()) {
+      String absCategory = PropertyHelper.getPropertyCategory(entry.getKey());
+      String propName = PropertyHelper.getPropertyName(entry.getKey());
+
+      if (absCategory.startsWith(parentCategory + "/desired_serviceconfigversions")) {
+        serviceConfigVersionRequest =
+            (serviceConfigVersionRequest ==null ) ? new ServiceConfigVersionRequest() : serviceConfigVersionRequest;
+
+        if (propName.equals("service_name"))
+          serviceConfigVersionRequest.setServiceName(entry.getValue().toString());
+        else if (propName.equals("serviceconfigversion"))
+          serviceConfigVersionRequest.setVersion(Long.valueOf(entry.getValue().toString()));
+
+      }
+    }
+
+    return serviceConfigVersionRequest;
+  }
+
+  /**
    * Determine if the request is a create using a blueprint.
    *
    * @param properties  request properties
@@ -975,7 +1031,7 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
         String type = entry.getKey();
         String service = stack.getServiceForConfigType(type);
         Config config = new ConfigImpl(type);
-        config.setVersionTag(entity.getName());
+        config.setTag(entity.getName());
         config.setProperties(entry.getValue());
         Map<String, Config> serviceConfigs = groupConfigs.get(service);
         if (serviceConfigs == null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
index 7948f56..ab9646d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
@@ -621,7 +621,7 @@ public class ConfigGroupResourceProvider extends
           }
 
           Config config = new ConfigImpl(type);
-          config.setVersionTag(tag);
+          config.setTag(tag);
           config.setProperties(configProperties);
           config.setPropertiesAttributes(configAttributes);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java
index a478e21..06d556d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java
@@ -58,6 +58,8 @@ public class ConfigurationResourceProvider extends
     PropertyHelper.getPropertyId(null, "type");
   public static final String CONFIGURATION_CONFIG_TAG_PROPERTY_ID   =
     PropertyHelper.getPropertyId(null, "tag");
+  public static final String CONFIGURATION_CONFIG_VERSION_PROPERTY_ID   =
+    PropertyHelper.getPropertyId(null, "version");
 
 
   /**
@@ -159,6 +161,7 @@ public class ConfigurationResourceProvider extends
       resource.setProperty(CONFIGURATION_CLUSTER_NAME_PROPERTY_ID, response.getClusterName());
       resource.setProperty(CONFIGURATION_CONFIG_TYPE_PROPERTY_ID, response.getType());
       resource.setProperty(CONFIGURATION_CONFIG_TAG_PROPERTY_ID, response.getVersionTag());
+      resource.setProperty(CONFIGURATION_CONFIG_VERSION_PROPERTY_ID, response.getVersion());
 
       if (null != response.getConfigs() && response.getConfigs().size() > 0) {
         Map<String, String> configs = response.getConfigs();

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
index 6eceea9..559f64d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
@@ -616,8 +616,9 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
                   + "host '" + h.getHostName() + "' "
                   + "changed by: '" + authName + "'; "
                   + "type='" + baseConfig.getType() + "' "
-                  + "tag='" + baseConfig.getVersionTag() + "'"
-                  + (null == oldConfig ? "" : ", from='" + oldConfig.getVersion() + "'"));
+                  + "version='" + baseConfig.getVersion() + "'"
+                  + "tag='" + baseConfig.getTag() + "'"
+                  + (null == oldConfig ? "" : ", from='" + oldConfig.getTag() + "'"));
             }
           }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceConfigVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceConfigVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceConfigVersionResourceProvider.java
new file mode 100644
index 0000000..a265e73
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceConfigVersionResourceProvider.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ConfigurationResponse;
+import org.apache.ambari.server.controller.ServiceConfigVersionRequest;
+import org.apache.ambari.server.controller.ServiceConfigVersionResponse;
+import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.Config;
+
+import java.util.*;
+
+public class ServiceConfigVersionResourceProvider extends
+    AbstractControllerResourceProvider {
+  public static final String SERVICE_CONFIG_VERSION_CLUSTER_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(null, "cluster_name");
+  public static final String SERVICE_CONFIG_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId(null, "serviceconfigversion");
+  public static final String SERVICE_CONFIG_VERSION_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(null, "service_name");
+  public static final String SERVICE_CONFIG_VERSION_CREATE_TIME_PROPERTY_ID = PropertyHelper.getPropertyId(null, "createtime");
+  public static final String SERVICE_CONFIG_VERSION_APPLY_TIME_PROPERTY_ID = PropertyHelper.getPropertyId(null, "appliedtime");
+  public static final String SERVICE_CONFIG_VERSION_USER_PROPERTY_ID = PropertyHelper.getPropertyId(null, "user");
+  public static final String SERVICE_CONFIG_VERSION_CONFIGURATIONS_PROPERTY_ID = PropertyHelper.getPropertyId(null, "configurations");
+
+  /**
+   * The primary key property ids for the service config version resource type.
+   */
+  private static Set<String> pkPropertyIds =
+      new HashSet<String>(Arrays.asList(new String[]{
+          SERVICE_CONFIG_VERSION_CLUSTER_NAME_PROPERTY_ID,
+          SERVICE_CONFIG_VERSION_SERVICE_NAME_PROPERTY_ID}));
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Constructor
+   *
+   * @param propertyIds           the property ids supported by this provider
+   * @param keyPropertyIds        the key properties for this provider
+   * @param managementController  the associated management controller
+   */
+  ServiceConfigVersionResourceProvider(Set<String> propertyIds,
+                                Map<Resource.Type, String> keyPropertyIds,
+                                AmbariManagementController managementController) {
+
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Cannot explicitly create service config version");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    final Set<ServiceConfigVersionRequest> requests = new HashSet<ServiceConfigVersionRequest>();
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      requests.add(createRequest(properties));
+    }
+
+    Set<ServiceConfigVersionResponse> responses = getResources(new Command<Set<ServiceConfigVersionResponse>>() {
+      @Override
+      public Set<ServiceConfigVersionResponse> invoke() throws AmbariException {
+        return getManagementController().getServiceConfigVersions(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+    for (ServiceConfigVersionResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.ServiceConfigVersion);
+      resource.setProperty(SERVICE_CONFIG_VERSION_CLUSTER_NAME_PROPERTY_ID, response.getClusterName());
+      resource.setProperty(SERVICE_CONFIG_VERSION_SERVICE_NAME_PROPERTY_ID, response.getServiceName());
+      resource.setProperty(SERVICE_CONFIG_VERSION_USER_PROPERTY_ID, response.getUserName());
+      resource.setProperty(SERVICE_CONFIG_VERSION_PROPERTY_ID, response.getVersion());
+      resource.setProperty(SERVICE_CONFIG_VERSION_APPLY_TIME_PROPERTY_ID, response.getApplyTime());
+      resource.setProperty(SERVICE_CONFIG_VERSION_CREATE_TIME_PROPERTY_ID, response.getCreateTime());
+      resource.setProperty(SERVICE_CONFIG_VERSION_CONFIGURATIONS_PROPERTY_ID,
+          convertToSubResources(response.getClusterName(), response.getConfigurations()));
+
+      resources.add(resource);
+    }
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Cannot update service config version");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Cannot delete service config version");
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+
+    for (String propertyId : propertyIds) {
+
+      if (!propertyId.equals("cluster_name") && !propertyId.equals("serviceconfigversion") &&
+          !propertyId.equals("service_name") && !propertyId.equals("createtime") &&
+          !propertyId.equals("appliedtime") && !propertyId.equals("user")) {
+
+        unsupportedProperties.add(propertyId);
+
+      }
+    }
+    return unsupportedProperties;
+  }
+
+
+  private ServiceConfigVersionRequest createRequest(Map<String, Object> properties) {
+    String clusterName = (String) properties.get(SERVICE_CONFIG_VERSION_CLUSTER_NAME_PROPERTY_ID);
+    String serviceName = (String) properties.get(SERVICE_CONFIG_VERSION_SERVICE_NAME_PROPERTY_ID);
+    String user = (String) properties.get(SERVICE_CONFIG_VERSION_USER_PROPERTY_ID);
+    Object versionObject = properties.get(SERVICE_CONFIG_VERSION_PROPERTY_ID);
+    Long version = versionObject == null ? null : Long.valueOf(versionObject.toString());
+
+    return new ServiceConfigVersionRequest(clusterName, serviceName, version, null, null, user);
+  }
+
+  private List<Map<String, Object>> convertToSubResources(final String clusterName, List<ConfigurationResponse> configs) {
+    List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
+    for (final ConfigurationResponse config : configs) {
+      Map<String, Object> configMap = new LinkedHashMap<String, Object>();
+      configMap.put("Config", new HashMap<String, String>(){{put("cluster_name", clusterName);}});
+      configMap.put("type", config.getType());
+      configMap.put("tag", config.getVersionTag());
+      configMap.put("version", config.getVersion());
+      configMap.put("properties", config.getConfigs());
+      configMap.put("properties_attributes", config.getConfigAttributes());
+      result.add(configMap);
+    }
+
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 c6cc95b..51a3086 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
@@ -80,6 +80,7 @@ public interface Resource {
     Component,
     HostComponent,
     Configuration,
+    ServiceConfigVersion,
     ConfigGroup,
     Action,
     Request,
@@ -157,6 +158,7 @@ public interface Resource {
     public static final Type Component = InternalType.Component.getType();
     public static final Type HostComponent = InternalType.HostComponent.getType();
     public static final Type Configuration = InternalType.Configuration.getType();
+    public static final Type ServiceConfigVersion = InternalType.ServiceConfigVersion.getType();
     public static final Type ConfigGroup = InternalType.ConfigGroup.getType();
     public static final Type Action = InternalType.Action.getType();
     public static final Type Request = InternalType.Request.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterDAO.java
index 6ae785a..1be9e88 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterDAO.java
@@ -23,11 +23,14 @@ import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
 
 import com.google.inject.Singleton;
+import org.apache.ambari.server.controller.ivory.Cluster;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
-import org.apache.ambari.server.orm.entities.ClusterConfigEntityPK;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 
 import com.google.inject.Inject;
@@ -39,6 +42,8 @@ public class ClusterDAO {
 
   @Inject
   Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
 
   /**
    * Looks for Cluster by ID
@@ -72,11 +77,25 @@ public class ClusterDAO {
   }
 
   @RequiresSession
-  public ClusterConfigEntity findConfig(ClusterConfigEntityPK configEntityPK) {
+  public ClusterConfigEntity findConfig(Long configEntityPK) {
     return entityManagerProvider.get().find(ClusterConfigEntity.class,
       configEntityPK);
   }
 
+  @RequiresSession
+  public ClusterConfigEntity findConfig(Long clusterId, String type, String tag) {
+    CriteriaBuilder cb = entityManagerProvider.get().getCriteriaBuilder();
+    CriteriaQuery<ClusterConfigEntity> cq = cb.createQuery(ClusterConfigEntity.class);
+    Root<ClusterConfigEntity> config = cq.from(ClusterConfigEntity.class);
+    cq.where(cb.and(
+        cb.equal(config.get("clusterId"), clusterId)),
+        cb.equal(config.get("type"), type),
+        cb.equal(config.get("tag"), tag)
+    );
+    TypedQuery<ClusterConfigEntity> query = entityManagerProvider.get().createQuery(cq);
+    return daoUtils.selectOne(query);
+  }
+
   /**
    * Create Cluster entity in Database
    * @param clusterEntity entity to create

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceConfigDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceConfigDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceConfigDAO.java
new file mode 100644
index 0000000..8b2487d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceConfigDAO.java
@@ -0,0 +1,116 @@
+/*
+ * 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.orm.dao;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.ServiceConfigApplicationEntity;
+import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Singleton
+@RequiresSession
+public class ServiceConfigDAO {
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
+
+
+  public ServiceConfigEntity find(Long serviceConfigId) {
+    return entityManagerProvider.get().find(ServiceConfigEntity.class, serviceConfigId);
+  }
+
+  public ServiceConfigEntity findByServiceAndVersion(String serviceName, Long version) {
+    TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().
+        createQuery("SELECT scv FROM ServiceConfigEntity scv " +
+            "WHERE scv.serviceName=?1 AND scv.version=?2", ServiceConfigEntity.class);
+    return daoUtils.selectOne(query, serviceName, version);
+  }
+
+  public Map<String, Long> findMaxVersions(Long clusterId) {
+    Map<String, Long> maxVersions = new HashMap<String, Long>();
+
+    TypedQuery<String> query = entityManagerProvider.get().createQuery("SELECT DISTINCT scv.serviceName FROM ServiceConfigEntity scv WHERE scv.clusterId = ?1", String.class);
+    List<String> serviceNames = daoUtils.selectList(query, clusterId);
+
+    for (String serviceName : serviceNames) {
+      maxVersions.put(serviceName, findMaxVersion(clusterId, serviceName).getVersion());
+    }
+
+    return maxVersions;
+  }
+
+  public List<Long> getServiceConfigVersionsByConfig(Long clusterId, String configType, Long configVersion) {
+    TypedQuery<Long> query = entityManagerProvider.get().createQuery("SELECT scv.version " +
+        "FROM ServiceConfigEntity scv JOIN scv.clusterConfigEntities cc " +
+        "WHERE cc.clusterId=?1 AND cc.type = ?2 AND cc.version = ?3", Long.class);
+    return daoUtils.selectList(query, clusterId, configType, configVersion);
+  }
+
+  public ServiceConfigApplicationEntity getLastApplication(Long clusterId, String serviceName) {
+    TypedQuery<ServiceConfigApplicationEntity> query = entityManagerProvider.get().
+        createQuery("SELECT sca FROM ServiceConfigEntity scv JOIN scv.serviceConfigApplicationEntities sca " +
+                "WHERE scv.clusterId = ?1 AND scv.serviceName = ?2 ORDER BY sca.applyTimestamp DESC",
+            ServiceConfigApplicationEntity.class);
+    return daoUtils.selectOne(query, clusterId, serviceName);
+  }
+
+  public ServiceConfigEntity findMaxVersion(Long clusterId, String serviceName) {
+    TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createQuery("SELECT scv FROM ServiceConfigEntity scv " +
+      "WHERE scv.clusterId=?1 AND scv.serviceName=?2 AND scv.version = (" +
+      "SELECT max(scv2.version) FROM ServiceConfigEntity scv2 " +
+      "WHERE scv2.clusterId=?1 AND scv2.serviceName=?2)", ServiceConfigEntity.class);
+
+    return daoUtils.selectSingle(query, clusterId, serviceName);
+  }
+
+  public List<ServiceConfigApplicationEntity> getServiceConfigApplications(Long clusterId) {
+    TypedQuery<ServiceConfigApplicationEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT apply FROM ServiceConfigApplicationEntity apply JOIN apply.serviceConfigEntity scv " +
+            "WHERE scv.clusterId=?1 ORDER BY apply.applyTimestamp DESC", ServiceConfigApplicationEntity.class);
+
+    return daoUtils.selectList(query, clusterId);
+  }
+
+  @Transactional
+  public void create(ServiceConfigEntity serviceConfigEntity) {
+    entityManagerProvider.get().persist(serviceConfigEntity);
+  }
+
+  @Transactional
+  public ServiceConfigEntity merge(ServiceConfigEntity serviceConfigEntity) {
+    return entityManagerProvider.get().merge(serviceConfigEntity);
+  }
+
+  @Transactional
+  public void remove(ServiceConfigEntity serviceConfigEntity) {
+    entityManagerProvider.get().remove(merge(serviceConfigEntity));
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
index 10148ff..f513ee2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
@@ -21,20 +21,32 @@ package org.apache.ambari.server.orm.entities;
 import javax.persistence.*;
 import java.util.Collection;
 
-@IdClass(ClusterConfigEntityPK.class)
-@Table(name = "clusterconfig")
 @Entity
+@Table(name = "clusterconfig",
+  uniqueConstraints = {@UniqueConstraint(name = "UQ_config_type_tag", columnNames = {"cluster_id", "type_name", "version_tag"}),
+    @UniqueConstraint(name = "UQ_config_type_version", columnNames = {"cluster_id", "type_name", "version"})})
+@TableGenerator(name = "config_id_generator",
+  table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "value"
+  , pkColumnValue = "config_id_seq"
+  , initialValue = 1
+  , allocationSize = 1
+)
 public class ClusterConfigEntity {
 
   @Id
+  @Column(name = "config_id")
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "config_id_generator")
+  private Long configId;
+
   @Column(name = "cluster_id", nullable = false, insertable = false, updatable = false, length = 10)
   private Long clusterId;
 
-  @Id
   @Column(name = "type_name")
   private String type;
 
-  @Id
+  @Column(name = "version")
+  private Long version;
+
   @Column(name = "version_tag")
   private String tag;
 
@@ -58,6 +70,17 @@ public class ClusterConfigEntity {
   @OneToMany(mappedBy = "clusterConfigEntity")
   private Collection<ConfigGroupConfigMappingEntity> configGroupConfigMappingEntities;
 
+  @ManyToMany(mappedBy = "clusterConfigEntities")
+  private Collection<ServiceConfigEntity> serviceConfigEntities;
+
+  public Long getConfigId() {
+    return configId;
+  }
+
+  public void setConfigId(Long configId) {
+    this.configId = configId;
+  }
+
   public Long getClusterId() {
     return clusterId;
   }
@@ -65,19 +88,27 @@ public class ClusterConfigEntity {
   public void setClusterId(Long clusterId) {
     this.clusterId = clusterId;
   }
-  
+
   public String getType() {
     return type;
   }
-  
+
   public void setType(String typeName) {
     type = typeName;
   }
-  
+
+  public Long getVersion() {
+    return version;
+  }
+
+  public void setVersion(Long version) {
+    this.version = version;
+  }
+
   public String getTag() {
     return tag;
   }
-  
+
   public void setTag(String versionTag) {
     tag = versionTag;
   }
@@ -89,11 +120,11 @@ public class ClusterConfigEntity {
   public void setData(String data) {
     this.configJson = data;
   }
-  
+
   public long getTimestamp() {
     return timestamp;
   }
-  
+
   public void setTimestamp(long stamp) {
     timestamp = stamp;
   }
@@ -117,7 +148,7 @@ public class ClusterConfigEntity {
     if (configJson != null ? !configJson.equals(that.configJson) : that.configJson != null)
       return false;
     if (configAttributesJson != null ? !configAttributesJson
-        .equals(that.configAttributesJson) : that.configAttributesJson != null)
+      .equals(that.configAttributesJson) : that.configAttributesJson != null)
       return false;
 
     return true;
@@ -146,4 +177,13 @@ public class ClusterConfigEntity {
   public void setConfigGroupConfigMappingEntities(Collection<ConfigGroupConfigMappingEntity> configGroupConfigMappingEntities) {
     this.configGroupConfigMappingEntities = configGroupConfigMappingEntities;
   }
+
+
+  public Collection<ServiceConfigEntity> getServiceConfigEntities() {
+    return serviceConfigEntities;
+  }
+
+  public void setServiceConfigEntities(Collection<ServiceConfigEntity> serviceConfigEntities) {
+    this.serviceConfigEntities = serviceConfigEntities;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntityPK.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntityPK.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntityPK.java
deleted file mode 100644
index aee7dd8..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntityPK.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.orm.entities;
-
-import javax.persistence.Column;
-import javax.persistence.Id;
-import java.io.Serializable;
-
-@SuppressWarnings("serial")
-public class ClusterConfigEntityPK implements Serializable {
-  private Long clusterId;
-
-  @Id
-  @Column(name = "cluster_id", nullable = false, insertable = true, updatable = true, length = 10)
-  public Long getClusterId() {
-    return clusterId;
-  }
-
-  public void setClusterId(Long clusterId) {
-    this.clusterId = clusterId;
-  }
-
-  private String type;
-  @Id
-  @Column(name = "type_name", nullable = false, insertable = true, updatable = false)
-  public String getType() {
-    return type;
-  }
-
-  public void setType(String typeName) {
-    type = typeName;
-  }
-
-  private String tag;
-  @Id
-  @Column(name="version_tag", nullable = false, insertable = true, updatable = false)
-  public String getTag() {
-    return tag;
-  }
-
-  public void setTag(String configTag) {
-    tag = configTag;
-  }
-
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    ClusterConfigEntityPK that = (ClusterConfigEntityPK) o;
-
-    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
-    if (type != null ? !type.equals(that.type) : that.type != null) return false;
-    if (tag != null ? !tag.equals(that.tag) : that.tag != null) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = clusterId !=null ? clusterId.intValue() : 0;
-    result = 31 * result + (type != null ? type.hashCode() : 0);
-    result = 31 * result + (tag != null ? tag.hashCode() : 0);
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
index d127f2a..fa48399 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
@@ -19,18 +19,21 @@ package org.apache.ambari.server.orm.entities;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.IdClass;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
+import javax.persistence.TableGenerator;
 
 /**
  * Entity that maps to a cluster config mapping.
  */
-@IdClass(ClusterConfigMappingEntityPK.class)
 @Table(name = "clusterconfigmapping")
 @Entity
+@IdClass(ClusterConfigMappingEntityPK.class)
 public class ClusterConfigMappingEntity {
 
   @Id
@@ -46,7 +49,7 @@ public class ClusterConfigMappingEntity {
   private Long createTimestamp;
 
   @Column(name = "version_tag", insertable = true, updatable = false, nullable = false)
-  private String versionTag;
+  private String tag;
 
   @Column(name = "selected", insertable = true, updatable = true, nullable = false)
   private int selectedInd = 0;
@@ -81,12 +84,12 @@ public class ClusterConfigMappingEntity {
     createTimestamp = timestamp;
   }
   
-  public String getVersion() {
-    return versionTag;
+  public String getTag() {
+    return tag;
   }
   
-  public void setVersion(String version) {
-    versionTag = version;
+  public void setTag(String version) {
+    tag = version;
   }
  
   public int isSelected() {
@@ -118,6 +121,6 @@ public class ClusterConfigMappingEntity {
   public void setClusterEntity(ClusterEntity entity) {
     clusterEntity = entity;
   }
-  
-  
+
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ce402002/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 6fb9b5a..16134c5 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
@@ -93,6 +93,9 @@ public class ClusterEntity {
   @OneToMany(mappedBy = "clusterEntity", cascade = CascadeType.ALL)
   private Collection<RequestScheduleEntity> requestScheduleEntities;
 
+  @OneToMany(mappedBy = "clusterEntity", cascade = CascadeType.REMOVE)
+  private Collection<ServiceConfigEntity> serviceConfigEntities;
+
   public Long getClusterId() {
     return clusterId;
   }
@@ -231,4 +234,11 @@ public class ClusterEntity {
     this.requestScheduleEntities = requestScheduleEntities;
   }
 
+  public Collection<ServiceConfigEntity> getServiceConfigEntities() {
+    return serviceConfigEntities;
+  }
+
+  public void setServiceConfigEntities(Collection<ServiceConfigEntity> serviceConfigEntities) {
+    this.serviceConfigEntities = serviceConfigEntities;
+  }
 }