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

[2/2] git commit: AMBARI-3672. Add Support to AmbariManagementController to derive configs from Config groups. (swagle)

AMBARI-3672. Add Support to AmbariManagementController to derive configs from Config groups. (swagle)


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

Branch: refs/heads/trunk
Commit: 6292620075cbb27760a06c3b6e733f905da36dd4
Parents: 8e08173
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Thu Nov 7 13:16:45 2013 -0800
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Thu Nov 7 13:16:45 2013 -0800

----------------------------------------------------------------------
 .../actionmanager/ExecutionCommandWrapper.java  |  91 +---
 .../ambari/server/agent/HeartBeatHandler.java   |   2 +-
 .../ambari/server/agent/HeartbeatMonitor.java   |  72 ++--
 .../AmbariManagementControllerImpl.java         | 127 ++----
 .../server/controller/ClusterResponse.java      |   2 +-
 .../ambari/server/controller/HostResponse.java  |  13 +
 .../ServiceComponentHostResponse.java           |  13 +-
 .../internal/ConfigGroupResourceProvider.java   |   5 +-
 .../internal/HostResourceProvider.java          |   4 +-
 .../orm/dao/ConfigGroupHostMappingDAO.java      |  11 +
 .../org/apache/ambari/server/state/Cluster.java |   2 +-
 .../ambari/server/state/ConfigHelper.java       | 225 ++++++----
 .../org/apache/ambari/server/state/Host.java    |   3 +
 .../apache/ambari/server/state/HostConfig.java  |  74 ++++
 .../server/state/ServiceComponentHost.java      |   2 +-
 .../server/state/cluster/ClusterImpl.java       |  42 +-
 .../server/state/cluster/ClustersImpl.java      |   9 +-
 .../ambari/server/state/host/HostImpl.java      |  59 ++-
 .../svccomphost/ServiceComponentHostImpl.java   | 107 +++--
 .../ExecutionCommandWrapperTest.java            |   6 +-
 .../server/agent/TestHeartbeatMonitor.java      |  12 +-
 .../AmbariManagementControllerTest.java         | 432 ++++++++++++++++++-
 .../ambari/server/state/ConfigHelperTest.java   | 209 +++++++++
 .../svccomphost/ServiceComponentHostTest.java   |  34 +-
 24 files changed, 1202 insertions(+), 354 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
index 76c9b05..b253138 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -48,38 +49,6 @@ public class ExecutionCommandWrapper {
     this.executionCommand = executionCommand;
   }
 
-  public static void applyCustomConfig(Map<String, Map<String, String>> configurations, String type,
-                                       String name, String value, Boolean deleted) {
-    if (!configurations.containsKey(type)) {
-      configurations.put(type, new HashMap<String, String>());
-    }
-    String nameToUse = deleted ? DELETED + name : name;
-    Map<String, String> properties = configurations.get(type);
-    if (properties.containsKey(nameToUse)) {
-      properties.remove(nameToUse);
-    }
-    properties.put(nameToUse, value);
-  }
-
-  public static Map<String, String> getMergedConfig(Map<String, String> persistedClusterConfig,
-                                                    Map<String, String> override) {
-    Map<String, String> finalConfig = new HashMap<String, String>(persistedClusterConfig);
-    if (override != null && override.size() > 0) {
-      for (String overrideKey : override.keySet()) {
-        Boolean deleted = 0 == overrideKey.indexOf(DELETED);
-        String nameToUse = deleted ? overrideKey.substring(DELETED.length()) : overrideKey;
-        if (finalConfig.containsKey(nameToUse)) {
-          finalConfig.remove(nameToUse);
-        }
-        if (!deleted) {
-          finalConfig.put(nameToUse, override.get(overrideKey));
-        }
-      }
-    }
-
-    return finalConfig;
-  }
-
   public ExecutionCommand getExecutionCommand() {
     if (executionCommand != null) {
       return executionCommand;
@@ -102,44 +71,28 @@ public class ExecutionCommandWrapper {
 
         try {
           Cluster cluster = clusters.getClusterById(clusterId);
-          for (Map.Entry<String, Map<String, String>> entry : executionCommand.getConfigurationTags().entrySet()) {
+          ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+
+          Map<String, Map<String, String>> configProperties = configHelper
+            .getEffectiveConfigProperties(cluster,
+              executionCommand.getConfigurationTags());
+
+          // Apply the configurations saved with the Execution Cmd on top of
+          // derived configs - This will take care of all the hacks
+          for (Map.Entry<String, Map<String, String>> entry : configProperties.entrySet()) {
             String type = entry.getKey();
-            Map<String, String> tags = entry.getValue();
-
-            String tag = tags.get("tag");
-            
-            if (tag != null) {
-              Config config = cluster.getConfig(type, tag);
-              
-              //Merge cluster level configs with service overriden, with host overriden
-              Map<String, String> allLevelMergedConfig = new HashMap<String, String>();
-              
-              allLevelMergedConfig.putAll(config.getProperties());
-              
-              String serviceTag =  tags.get("service_override_tag");
-              if (serviceTag != null) {
-                Config configService = cluster.getConfig(type, serviceTag);
-                if (configService != null)
-                  allLevelMergedConfig = getMergedConfig(allLevelMergedConfig, configService.getProperties());
-              }
-                
-              String hostTag = tags.get("host_override_tag");
-              if (hostTag != null) {
-                Config configHost = cluster.getConfig(type, hostTag);
-                if (configHost != null)
-                  allLevelMergedConfig = getMergedConfig(allLevelMergedConfig, configHost.getProperties());
-              }
-              
-              if (executionCommand.getConfigurations().containsKey(type)) {
-                Map<String, String> mergedConfig =
-                    getMergedConfig(allLevelMergedConfig, executionCommand.getConfigurations().get(type));
-                executionCommand.getConfigurations().get(type).clear();
-                executionCommand.getConfigurations().get(type).putAll(mergedConfig);
-
-              } else {
-                executionCommand.getConfigurations().put(type, new HashMap<String, String>());
-                executionCommand.getConfigurations().get(type).putAll(allLevelMergedConfig);
-              }
+            Map<String, String> allLevelMergedConfig = entry.getValue();
+
+            if (executionCommand.getConfigurations().containsKey(type)) {
+              Map<String, String> mergedConfig =
+                configHelper.getMergedConfig(allLevelMergedConfig,
+                  executionCommand.getConfigurations().get(type));
+              executionCommand.getConfigurations().get(type).clear();
+              executionCommand.getConfigurations().get(type).putAll(mergedConfig);
+
+            } else {
+              executionCommand.getConfigurations().put(type, new HashMap<String, String>());
+              executionCommand.getConfigurations().get(type).putAll(allLevelMergedConfig);
             }
           }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index d1af55c..46976b5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -93,7 +93,7 @@ public class HeartBeatHandler {
     this.clusterFsm = fsm;
     this.actionQueue = aq;
     this.actionManager = am;
-    this.heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000);
+    this.heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000, ambariMetaInfo);
     injector.injectMembers(this);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
index bb348c6..43961b2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
@@ -25,10 +25,11 @@ import java.util.TreeMap;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.Service;
@@ -45,19 +46,21 @@ import org.apache.commons.logging.LogFactory;
  */
 public class HeartbeatMonitor implements Runnable {
   private static Log LOG = LogFactory.getLog(HeartbeatMonitor.class);
-  private Clusters fsm;
+  private Clusters clusters;
   private ActionQueue actionQueue;
   private ActionManager actionManager;
   private final int threadWakeupInterval; //1 minute
   private volatile boolean shouldRun = true;
   private Thread monitorThread = null;
+  private final ConfigHelper configHelper;
 
-  public HeartbeatMonitor(Clusters fsm, ActionQueue aq, ActionManager am,
-      int threadWakeupInterval) {
-    this.fsm = fsm;
+  public HeartbeatMonitor(Clusters clusters, ActionQueue aq, ActionManager am,
+                          int threadWakeupInterval, AmbariMetaInfo ambariMetaInfo) {
+    this.clusters = clusters;
     this.actionQueue = aq;
     this.actionManager = am;
     this.threadWakeupInterval = threadWakeupInterval;
+    this.configHelper = new ConfigHelper(this.clusters, ambariMetaInfo);
   }
 
   public void shutdown() {
@@ -97,10 +100,10 @@ public class HeartbeatMonitor implements Runnable {
   }
 
   //Go through all the nodes, check for last heartbeat or any waiting state
-  //If heartbeat is lost, update node fsm state, purge the action queue
+  //If heartbeat is lost, update node clusters state, purge the action queue
   //notify action manager for node failure.
   private void doWork() throws InvalidStateTransitionException, AmbariException {
-    List<Host> allHosts = fsm.getHosts();
+    List<Host> allHosts = clusters.getHosts();
     long now = System.currentTimeMillis();
     for (Host hostObj : allHosts) {
       String host = hostObj.getHostName();
@@ -109,7 +112,7 @@ public class HeartbeatMonitor implements Runnable {
 
       long lastHeartbeat = 0;
       try {
-        lastHeartbeat = fsm.getHost(host).getLastHeartbeatTime();
+        lastHeartbeat = clusters.getHost(host).getLastHeartbeatTime();
       } catch (AmbariException e) {
         LOG.warn("Exception in getting host object; Is it fatal?", e);
       }
@@ -119,16 +122,16 @@ public class HeartbeatMonitor implements Runnable {
         hostObj.handleEvent(new HostHeartbeatLostEvent(host));
 
         // mark all components that are not clients with unknown status
-        for (Cluster cluster : fsm.getClustersForHost(hostObj.getHostName())) {
+        for (Cluster cluster : clusters.getClustersForHost(hostObj.getHostName())) {
           for (ServiceComponentHost sch : cluster.getServiceComponentHosts(hostObj.getHostName())) {
             Service s = cluster.getService(sch.getServiceName());
             ServiceComponent sc = s.getServiceComponent(sch.getServiceComponentName());
             if (!sc.isClientComponent() &&
-                !sch.getState().equals(State.INIT) &&
-                !sch.getState().equals(State.INSTALLING) &&
-                !sch.getState().equals(State.INSTALL_FAILED) &&
-                !sch.getState().equals(State.UNINSTALLED) &&
-                !sch.getState().equals(State.MAINTENANCE)) {
+              !sch.getState().equals(State.INIT) &&
+              !sch.getState().equals(State.INSTALLING) &&
+              !sch.getState().equals(State.INSTALL_FAILED) &&
+              !sch.getState().equals(State.UNINSTALLED) &&
+              !sch.getState().equals(State.MAINTENANCE)) {
               LOG.warn("Setting component state to UNKNOWN for component " + sc.getName() + " on " + host);
               sch.setState(State.UNKNOWN);
             }
@@ -152,7 +155,7 @@ public class HeartbeatMonitor implements Runnable {
       // Get status of service components
       List<StatusCommand> cmds = generateStatusCommands(hostname);
       LOG.trace("Generated " + cmds.size() + " status commands for host: " +
-          hostname);
+        hostname);
       if (cmds.isEmpty()) {
         // Nothing to do
       } else {
@@ -165,12 +168,12 @@ public class HeartbeatMonitor implements Runnable {
 
   /**
    * @param hostname
-   * @return  list of commands to get status of service components on a concrete host
+   * @return list of commands to get status of service components on a concrete host
    */
   public List<StatusCommand> generateStatusCommands(String hostname) throws AmbariException {
     List<StatusCommand> cmds = new ArrayList<StatusCommand>();
-    
-    for (Cluster cl : fsm.getClustersForHost(hostname)) {
+
+    for (Cluster cl : clusters.getClustersForHost(hostname)) {
       for (ServiceComponentHost sch : cl.getServiceComponentHosts(hostname)) {
         String serviceName = sch.getServiceName();
         Service service = cl.getService(sch.getServiceName());
@@ -184,27 +187,32 @@ public class HeartbeatMonitor implements Runnable {
         Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String, String>>();
 
         // get the cluster config for type 'global'
-        // apply service overrides, if the tag is not the same
-        // apply host overrides, if any
+        // apply config group overrides
 
         Config clusterConfig = cl.getDesiredConfigByType("global");
-        if (null != clusterConfig) {
+        if (clusterConfig != null) {
           // cluster config for 'global'
           Map<String, String> props = new HashMap<String, String>(clusterConfig.getProperties());
 
-          // apply service overrides, only if the tag is not the same (for when service configs are overrides)
-          Config svcConfig = service.getDesiredConfigs().get("global");
-          if (null != svcConfig && !svcConfig.getVersionTag().equals(clusterConfig.getVersionTag())) {
-            props.putAll(svcConfig.getProperties());
+          // Apply global properties for this host from all config groups
+          Map<String, Map<String, String>> allConfigTags = configHelper
+            .getEffectiveDesiredTags(cl, hostname);
+
+          Map<String, Map<String, String>> configTags = new HashMap<String,
+            Map<String, String>>();
+
+          for (Map.Entry<String, Map<String, String>> entry : allConfigTags.entrySet()) {
+            if (entry.getKey().equals("global")) {
+              configTags.put("global", entry.getValue());
+            }
           }
 
-          // apply host overrides, if any
-          Host host = fsm.getHost(hostname);
-          DesiredConfig dc = host.getDesiredConfigs(cl.getClusterId()).get("global");
-          if (null != dc) {
-            Config hostConfig = cl.getConfig("global", dc.getVersion());
-            if (null != hostConfig) {
-              props.putAll(hostConfig.getProperties());
+          Map<String, Map<String, String>> properties = configHelper
+            .getEffectiveConfigProperties(cl, configTags);
+
+          if (!properties.isEmpty()) {
+            for (Map<String, String> propertyMap : properties.values()) {
+              props.putAll(propertyMap);
             }
           }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 7146b0c..5132c5a 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,21 +18,11 @@
 
 package org.apache.ambari.server.controller;
 
-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.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -45,15 +35,10 @@ import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.StackAccessException;
-import org.apache.ambari.server.actionmanager.ActionDefinition;
 import org.apache.ambari.server.actionmanager.ActionManager;
-import org.apache.ambari.server.actionmanager.ActionType;
-import org.apache.ambari.server.actionmanager.CustomActionDBAccessorImpl;
-import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
-import org.apache.ambari.server.actionmanager.TargetHostType;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
@@ -70,7 +55,6 @@ import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigFactory;
 import org.apache.ambari.server.state.ConfigHelper;
-import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.OperatingSystemInfo;
@@ -102,12 +86,20 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.http.client.utils.URIBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
+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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
 
 @Singleton
 public class AmbariManagementControllerImpl implements
@@ -123,8 +115,6 @@ public class AmbariManagementControllerImpl implements
 
   private static final String BASE_LOG_DIR = "/tmp/ambari";
 
-  private static final String CLUSTER_LEVEL_TAG = "tag";
-
   private final Clusters clusters;
 
   private final ActionManager actionManager;
@@ -158,6 +148,8 @@ public class AmbariManagementControllerImpl implements
   private AbstractRootServiceResponseFactory rootServiceResponseFactory;
   @Inject
   private ConfigGroupFactory configGroupFactory;
+  @Inject
+  private ConfigHelper configHelper;
 
   final private String masterHostname;
   final private Integer masterPort;
@@ -577,7 +569,7 @@ public class AmbariManagementControllerImpl implements
 
     // Hack - Remove passwords from configs
     if (event.getServiceComponentName().equals(Role.HIVE_CLIENT.toString())) {
-      ExecutionCommandWrapper.applyCustomConfig(configurations, Configuration.HIVE_CONFIG_TAG,
+      configHelper.applyCustomConfig(configurations, Configuration.HIVE_CONFIG_TAG,
           Configuration.HIVE_METASTORE_PASSWORD_PROPERTY, "", true);
     }
 
@@ -1100,48 +1092,23 @@ public class AmbariManagementControllerImpl implements
     }
   }
 
-  private Map<String, Map<String, String>> findConfigurationPropertiesWithOverrides(
-      Map<String, Map<String, String>> configurations,
-      Cluster cluster, String serviceName,
-      Map<String, DesiredConfig> desiredConfigMap) throws AmbariException {
-
-    
-    ConfigHelper ch = injector.getInstance(ConfigHelper.class);
-        
-    Map<String, Map<String,String>> configTags = ch.getEffectiveDesiredTags(cluster, serviceName, desiredConfigMap);
-
+  /**
+   * Find configuration tags with applied overrides
+   *
+   * @param cluster
+   * @param hostName
+   * @return
+   * @throws AmbariException
+   */
+  private Map<String, Map<String,String>> findConfigurationTagsWithOverrides(
+    Cluster cluster, String hostName) throws AmbariException {
 
-    // HACK HACK HACK if the service has configs that are NOT included
-    // in cluster-level, then use them anyway.  THIS IS GENERALLY A BAD
-    // IDEA, but is included for backward compatibility.  Do not check host
-    // overrides, because that wasn't in the version where this code would
-    // be the case.
-    Service service = cluster.getService(serviceName);
-    for (Config c : service.getDesiredConfigs().values()) {
-      String type = c.getType();
-      if (!configurations.containsKey(type)) {
-        configurations.put(type, new HashMap<String, String>(c.getProperties()));
+    Map<String, Map<String,String>> configTags =
+      configHelper.getEffectiveDesiredTags(cluster, hostName);
 
-        HashMap<String, String> tags = new HashMap<String, String>();
-        tags.put(CLUSTER_LEVEL_TAG, c.getVersionTag());
-        configTags.put(type, tags);
-      }
-    }
-    
     return configTags;
   }
 
-  private Map<String, Map<String,String>> findConfigurationPropertiesWithOverrides(
-      Map<String, Map<String, String>> configurations,
-      Cluster cluster, String serviceName, String hostName) throws AmbariException {
-
-    Host host = clusters.getHost(hostName);
-    Map<String, DesiredConfig> desiredConfigMap = host.getDesiredConfigs(cluster.getClusterId());
-
-    return findConfigurationPropertiesWithOverrides(configurations, cluster,
-        serviceName, desiredConfigMap);
-  }
-
 
   private List<Stage> doStageCreation(Cluster cluster,
       Map<State, List<Service>> changedServices,
@@ -1196,8 +1163,6 @@ public class AmbariManagementControllerImpl implements
         }
       }
 
-      Map<String, Map<String, DesiredConfig>> configsByHosts = cluster.getHostsDesiredConfigs(hostnames);
-
       //HACK
       String jobtrackerHost = getJobTrackerHost(cluster);
       Map<String, List<String>> clusterHostInfo = StageUtils.getClusterHostInfo(
@@ -1333,13 +1298,15 @@ public class AmbariManagementControllerImpl implements
 
             // [ type -> [ key, value ] ]
             Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String, String>>();
-            Map<String, Map<String, String>> configTags = findConfigurationPropertiesWithOverrides(
-                configurations, cluster, scHost.getServiceName(), configsByHosts.get(scHost.getHostName()));
+            Host host = clusters.getHost(scHost.getHostName());
+
+            Map<String, Map<String, String>> configTags =
+              findConfigurationTagsWithOverrides(cluster, host.getHostName());
 
-            // HACK HACK HACK
+            // HACK - Set configs on the ExecCmd
             if (!scHost.getHostName().equals(jobtrackerHost)) {
               if (configTags.get(Configuration.GLOBAL_CONFIG_TAG) != null) {
-                ExecutionCommandWrapper.applyCustomConfig(
+                configHelper.applyCustomConfig(
                     configurations, Configuration.GLOBAL_CONFIG_TAG,
                     Configuration.RCA_ENABLED_PROPERTY, "false", false);
               }
@@ -1377,8 +1344,8 @@ public class AmbariManagementControllerImpl implements
 
         // [ type -> [ key, value ] ]
         Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String,String>>();
-        Map<String, Map<String, String>> configTags = findConfigurationPropertiesWithOverrides(
-            configurations, cluster, serviceName, clientHost);
+        Map<String, Map<String, String>> configTags =
+          findConfigurationTagsWithOverrides(cluster, clientHost);
 
         stage.getExecutionCommandWrapper(clientHost,
             smokeTestRole).getExecutionCommand()
@@ -2341,8 +2308,8 @@ public class AmbariManagementControllerImpl implements
     
     // [ type -> [ key, value ] ]
     Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String,String>>();
-    Map<String, Map<String, String>> configTags = findConfigurationPropertiesWithOverrides(configurations,
-      cluster, actionRequest.getServiceName(), hostName);
+    Map<String, Map<String, String>> configTags =
+      findConfigurationTagsWithOverrides(cluster, hostName);
 
     ExecutionCommand execCmd = stage.getExecutionCommandWrapper(hostName,
       actionRequest.getCommandName()).getExecutionCommand();
@@ -2399,12 +2366,12 @@ public class AmbariManagementControllerImpl implements
         new TreeMap<String, Map<String, String>>();
 
     
-    Map<String, Map<String, String>> configTags = findConfigurationPropertiesWithOverrides(
-        configurations, cluster, serviceName, namenodeHost);
+    Map<String, Map<String, String>> configTags =
+      findConfigurationTagsWithOverrides(cluster, namenodeHost);
     
     // Add the tag for hdfs-exclude-file
     Map<String, String> excludeTags = new HashMap<String, String>();
-    excludeTags.put(CLUSTER_LEVEL_TAG, config.getVersionTag());
+    excludeTags.put(ConfigHelper.CLUSTER_DEFAULT_TAG, config.getVersionTag());
     configTags.put(hdfsExcludeFileType, excludeTags);
 
     stage.addHostRoleExecutionCommand(

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 15cc60e..557cf6e 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
@@ -121,7 +121,7 @@ public class ClusterResponse {
   }
 
   /**
-   * @param desiredConfigs
+   * @param configs
    */
   public void setDesiredConfigs(Map<String, DesiredConfig> configs) {
     desiredConfigs = configs;

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
index b6306b8..cfa21fb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
@@ -27,6 +27,7 @@ import org.apache.ambari.server.agent.AgentEnv;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.HostConfig;
 import org.apache.ambari.server.state.HostHealthStatus;
 
 public class HostResponse {
@@ -133,6 +134,11 @@ public class HostResponse {
 
   private Map<String, DesiredConfig> desiredConfigs;
 
+  /**
+   * Configs derived from Config groups
+   */
+  private Map<String, HostConfig> desiredHostConfigs;
+
   public HostResponse(String hostname, String clusterName,
                       String ipv4, String ipv6, int cpuCount, int phCpuCount, String osArch, String osType,
                       String osInfo, long availableMemBytes, long totalMemBytes,
@@ -492,4 +498,11 @@ public class HostResponse {
     return desiredConfigs;
   }
 
+  public Map<String, HostConfig> getDesiredHostConfigs() {
+    return desiredHostConfigs;
+  }
+
+  public void setDesiredHostConfigs(Map<String, HostConfig> desiredHostConfigs) {
+    this.desiredHostConfigs = desiredHostConfigs;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
index e773871..0448864 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
@@ -18,9 +18,10 @@
 
 package org.apache.ambari.server.controller;
 
-import java.util.Map;
-
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.HostConfig;
+
+import java.util.Map;
 
 public class ServiceComponentHostResponse {
 
@@ -38,7 +39,7 @@ public class ServiceComponentHostResponse {
   private Map<String, String> desiredConfigs;
   
   // type -> desired config
-  private Map<String, DesiredConfig> actualConfigs;
+  private Map<String, HostConfig> actualConfigs;
 
   private String liveState;
 
@@ -238,16 +239,16 @@ public class ServiceComponentHostResponse {
   }
 
   /**
-   * @param actualConfigs the actual configs
+   * @param configs the actual configs
    */
-  public void setActualConfigs(Map<String, DesiredConfig> configs) {
+  public void setActualConfigs(Map<String, HostConfig> configs) {
     actualConfigs = configs;
   }
   
   /**
    * @return the actual configs
    */
-  public Map<String, DesiredConfig> getActualConfigs() {
+  public Map<String, HostConfig> getActualConfigs() {
     return actualConfigs;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 a63f382..277ef33 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
@@ -431,10 +431,9 @@ public class ConfigGroupResourceProvider extends
         request.getConfigs(), hosts);
 
       // Persist before add, since id is auto-generated
-
       configLogger.info("Persisting new Config group, "
-        + ", clusterName = " + configGroup.getClusterName()
-        + ", id = " + configGroup.getId()
+        + ", clusterName = " + cluster.getClusterName()
+        + ", name = " + configGroup.getName()
         + ", tag = " + configGroup.getTag()
         + ", user = " + getManagementController().getAuthName());
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 45dc22c..30394d9 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
@@ -227,7 +227,7 @@ class HostResourceProvider extends AbstractControllerResourceProvider {
       setResourceProperty(resource, HOST_STATE_PROPERTY_ID,
           response.getHostState(), requestedIds);
       setResourceProperty(resource, HOST_DESIRED_CONFIGS_PROPERTY_ID,
-          response.getDesiredConfigs(), requestedIds);
+          response.getDesiredHostConfigs(), requestedIds);
       resources.add(resource);
     }
     return resources;
@@ -485,7 +485,7 @@ class HostResourceProvider extends AbstractControllerResourceProvider {
         if (clusters.getClustersForHost(h.getHostName()).contains(cluster)) {
           HostResponse r = h.convertToResponse();
           r.setClusterName(clusterName);
-          r.setDesiredConfigs(h.getDesiredConfigs(cluster.getClusterId()));
+          r.setDesiredHostConfigs(h.getDesiredHostConfigs(cluster));
 
           response.add(r);
         } else if (hostName != null) {

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ConfigGroupHostMappingDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ConfigGroupHostMappingDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ConfigGroupHostMappingDAO.java
index 9ca3fee..90aa5a5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ConfigGroupHostMappingDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ConfigGroupHostMappingDAO.java
@@ -109,6 +109,17 @@ public class ConfigGroupHostMappingDAO {
         "confighosts.configGroupId = ?1", Long.class);
 
     daoUtils.executeUpdate(query, groupId);
+    // Flush to current transaction required in order to avoid Eclipse link
+    // from re-ordering delete
     entityManagerProvider.get().flush();
   }
+
+  @Transactional
+  public void removeAllByHost(String hostname) {
+    TypedQuery<String> query = entityManagerProvider.get().createQuery
+      ("DELETE FROM ConfigGroupHostMappingEntity confighosts WHERE " +
+        "confighosts.hostname = ?1", String.class);
+
+    daoUtils.executeUpdate(query, hostname);
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 186ac97..9a88ae3 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
@@ -254,5 +254,5 @@ public interface Cluster {
    * @param hostname
    * @return Map of config group id to config group
    */
-  public Map<Long, ConfigGroup> getConfigGroupsByHostname(String hostname);
+  public Map<Long, ConfigGroup> getConfigGroupsByHostname(String hostname) throws AmbariException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index 855711b..91ab4f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
 
+import com.google.inject.Singleton;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 
@@ -37,10 +38,13 @@ import com.google.inject.Inject;
 /**
  * Helper class that works with config traversals.
  */
+@Singleton
 public class ConfigHelper {
 
   private Clusters clusters = null;
   private AmbariMetaInfo ambariMetaInfo = null;
+  private static String DELETED = "DELETED_";
+  public static final String CLUSTER_DEFAULT_TAG = "tag";
   
   @Inject
   public ConfigHelper(Clusters c, AmbariMetaInfo metaInfo) {
@@ -51,30 +55,28 @@ public class ConfigHelper {
   /**
    * Gets the desired tags for a cluster and host
    * @param cluster the cluster
-   * @param serviceName the optional service name
    * @param hostName the host name
    * @return a map of tag type to tag names with overrides
    * @throws AmbariException
    */
   public Map<String, Map<String, String>> getEffectiveDesiredTags(
-      Cluster cluster, String serviceName, String hostName) throws AmbariException {
+      Cluster cluster, String hostName) throws AmbariException {
     
     Host host = clusters.getHost(hostName);
-    Map<String, DesiredConfig> hostDesired = host.getDesiredConfigs(cluster.getClusterId());
     
-    return getEffectiveDesiredTags(cluster, serviceName, hostDesired);
+    return getEffectiveDesiredTags(cluster, host.getDesiredHostConfigs(cluster));
   }
 
   /**
-   * Gets the desired tags for a cluster and host
+   * Gets the desired tags for a cluster and overrides for a host
    * @param cluster the cluster
-   * @param serviceName the optional service name
-   * @param hostDesired the optional host desired configs
+   * @param hostConfigOverrides the host overrides applied using config groups
    * @return a map of tag type to tag names with overrides
    * @throws AmbariException
    */
-  public Map<String, Map<String, String>> getEffectiveDesiredTags(
-      Cluster cluster, String serviceName, Map<String, DesiredConfig> hostDesired) throws AmbariException {
+  private Map<String, Map<String, String>> getEffectiveDesiredTags(
+      Cluster cluster, Map<String, HostConfig> hostConfigOverrides)
+        throws AmbariException {
     
     Map<String, DesiredConfig> clusterDesired = cluster.getDesiredConfigs();
     
@@ -82,48 +84,130 @@ public class ConfigHelper {
     
     // Do not use host component config mappings.  Instead, the rules are:
     // 1) Use the cluster desired config
-    // 2) override (1) with service-specific overrides
-    // 3) override (2) with host-specific overrides
+    // 2) override (1) with config-group overrides
     
     for (Entry<String, DesiredConfig> clusterEntry : clusterDesired.entrySet()) {
-        String type = clusterEntry.getKey();
-        String tag = clusterEntry.getValue().getVersion();
-        
-        // 1) start with cluster config
-        Config config = cluster.getConfig(type, tag);
-        if (null == config) {
-          continue;
-        }
+      String type = clusterEntry.getKey();
+      String tag = clusterEntry.getValue().getVersion();
 
-        Map<String, String> tags = new LinkedHashMap<String, String>();
-        
-        tags.put("tag", config.getVersionTag());
-        
-        // 2) apply the service overrides, if any are defined with different tags
-        if (null != serviceName) {
-          Service service = cluster.getService(serviceName);
-          Config svcConfig = service.getDesiredConfigs().get(type);
-          if (null != svcConfig && !svcConfig.getVersionTag().equals(tag)) {
-            tags.put("service_override_tag", svcConfig.getVersionTag());
+      // 1) start with cluster config
+      Config config = cluster.getConfig(type, tag);
+      if (null == config) {
+        continue;
+      }
+
+      Map<String, String> tags = new LinkedHashMap<String, String>();
+
+      tags.put(CLUSTER_DEFAULT_TAG, config.getVersionTag());
+
+      // AMBARI-3672. Only consider Config groups for override tags
+      // tags -> (configGroupId, versionTag)
+      if (hostConfigOverrides != null) {
+        HostConfig hostConfig = hostConfigOverrides.get(config.getType());
+        if (hostConfig != null) {
+          for (Entry<Long, String> tagEntry : hostConfig
+              .getConfigGroupOverrides().entrySet()) {
+            tags.put(tagEntry.getKey().toString(), tagEntry.getValue());
           }
         }
+      }
 
-        if (null != hostDesired) {
-          // 3) apply the host overrides, if any
-          DesiredConfig dc = hostDesired.get(type);
-  
-          if (null != dc) {
-            Config hostConfig = cluster.getConfig(type, dc.getVersion());
-            if (null != hostConfig) {
-              tags.put("host_override_tag", hostConfig.getVersionTag());
+      resolved.put(type, tags);
+    }
+
+    return resolved;
+  }
+
+  /**
+   * Get all config properties for a cluster given a set of configType to
+   * versionTags map. This helper method merges all the override tags with a
+   * the properties from parent cluster config properties
+   *
+   * @param cluster
+   * @param desiredTags
+   * @return {type : {key, value}}
+   */
+  public Map<String, Map<String, String>> getEffectiveConfigProperties(
+    Cluster cluster, Map<String, Map<String, String>> desiredTags) {
+
+    Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
+
+    if (desiredTags != null) {
+      for (Entry<String, Map<String, String>> entry : desiredTags.entrySet()) {
+        String type = entry.getKey();
+        Map<String, String> propertyMap = properties.get(type);
+        if (propertyMap == null) {
+          propertyMap = new HashMap<String, String>();
+        }
+
+        Map<String, String> tags = new HashMap<String, String>(entry.getValue());
+        String clusterTag = tags.get(CLUSTER_DEFAULT_TAG);
+
+        // Overrides is only supported if the config type exists at cluster
+        // level
+        if (clusterTag != null) {
+          Config config = cluster.getConfig(type, clusterTag);
+          if (config != null) {
+            propertyMap.putAll(config.getProperties());
+          }
+          tags.remove(CLUSTER_DEFAULT_TAG);
+          // Now merge overrides
+          for (Entry<String, String> overrideEntry : tags.entrySet()) {
+            Config overrideConfig = cluster.getConfig(type,
+              overrideEntry.getValue());
+
+            if (overrideConfig != null) {
+              propertyMap = getMergedConfig(propertyMap, overrideConfig.getProperties());
             }
           }
         }
-        
-        resolved.put(type, tags);
+        properties.put(type, propertyMap);
       }
-    
-    return resolved;
+    }
+
+    return properties;
+  }
+
+  /**
+   * Merge override with original, if original property doesn't exist,
+   * add it to the properties
+   *
+   * @param persistedClusterConfig
+   * @param override
+   * @return
+   */
+  public Map<String, String> getMergedConfig(Map<String,
+      String> persistedClusterConfig, Map<String, String> override) {
+
+    Map<String, String> finalConfig = new HashMap<String, String>(persistedClusterConfig);
+
+    if (override != null && override.size() > 0) {
+      for (String overrideKey : override.keySet()) {
+        Boolean deleted = 0 == overrideKey.indexOf(DELETED);
+        String nameToUse = deleted ? overrideKey.substring(DELETED.length()) : overrideKey;
+        if (finalConfig.containsKey(nameToUse)) {
+          finalConfig.remove(nameToUse);
+        }
+        if (!deleted) {
+          finalConfig.put(nameToUse, override.get(overrideKey));
+        }
+      }
+    }
+
+    return finalConfig;
+  }
+
+  public void applyCustomConfig(Map<String, Map<String, String>> configurations,
+      String type, String name, String value, Boolean deleted) {
+    if (!configurations.containsKey(type)) {
+      configurations.put(type, new HashMap<String, String>());
+    }
+    String nameToUse = deleted ? DELETED + name : name;
+    Map<String, String> properties = configurations.get(type);
+    if (properties.containsKey(nameToUse)) {
+      properties.remove(nameToUse);
+    }
+    properties.put(nameToUse, value);
   }
   
   /**
@@ -146,12 +230,12 @@ public class ConfigHelper {
    *     </ul>
    *   </li>
    * </ul>
-   * @param serviceComponentHostImpl
+   * @param @ServiceComponentHost
    * @return <code>true</code> if the actual configs are stale
    */
   public boolean isStaleConfigs(ServiceComponentHost sch) throws AmbariException {
 
-    Map<String, DesiredConfig> actual = sch.getActualConfigs();
+    Map<String, HostConfig> actual = sch.getActualConfigs();
     if (null == actual || actual.isEmpty())
       return false;
     
@@ -159,11 +243,11 @@ public class ConfigHelper {
     StackId stackId = cluster.getDesiredStackVersion();
     
     Map<String, Map<String, String>> desired = getEffectiveDesiredTags(cluster,
-        sch.getServiceName(), sch.getHostName());
+        sch.getHostName());
     
     ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(),
         stackId.getStackVersion(), sch.getServiceName());
-    
+
     // Configs are considered stale when:
     // - desired type DOES NOT exist in actual
     // --- desired type DOES NOT exist in stack: not_stale
@@ -192,15 +276,16 @@ public class ConfigHelper {
           // then all services
           Collection<String> keys = mergeKeyNames(cluster, type, tags.values());
           
-          if (serviceInfo.hasPropertyFor(type, keys) || !hasPropertyFor(stackId, type, keys))
+          if (serviceInfo.hasPropertyFor(type, keys) || !hasPropertyFor(stackId, type, keys)) {
             stale = true;
+          }
         }
       } else {
         // desired and actual both define the type
-        DesiredConfig dc = actual.get(type);
-        Map<String, String> actualTags = buildTags(dc);
+        HostConfig hc = actual.get(type);
+        Map<String, String> actualTags = buildTags(hc);
         
-        if (!isTagChange(tags, actualTags)) {
+        if (!isTagChanged(tags, actualTags)) {
           stale = false;
         } else {
           // tags are change, need to find out what has changed, and if it applies
@@ -220,6 +305,7 @@ public class ConfigHelper {
    * @return <code>true</code> if any service on the stack defines a property
    * for the type.
    */
+  // TODO: Create a static hash map for quick lookup
   private boolean hasPropertyFor(StackId stack, String type,
       Collection<String> keys) throws AmbariException {
 
@@ -273,39 +359,32 @@ public class ConfigHelper {
   /**
    * @return the map of tags for a desired config
    */
-  private Map<String, String> buildTags(DesiredConfig dc) {
+  private Map<String, String> buildTags(HostConfig hc) {
     Map<String, String> map = new LinkedHashMap<String, String>();
-    map.put("tag", dc.getVersion());
-    if (null != dc.getServiceName())
-      map.put("service_override_tag", dc.getServiceName());
-    if (0 != dc.getHostOverrides().size())
-      map.put("host_override_tag", dc.getHostOverrides().get(0).getVersionTag());
-    
+    map.put(CLUSTER_DEFAULT_TAG, hc.getDefaultVersionTag());
+    if (hc.getConfigGroupOverrides() != null) {
+      for (Entry<Long, String> entry : hc.getConfigGroupOverrides().entrySet()) {
+        map.put(entry.toString(), entry.getValue());
+      }
+    }
     return map;
   }
   
   /**
    * @return true if the tags are different in any way, even if not-specified
    */
-  private boolean isTagChange(Map<String, String> desiredTags, Map<String, String> actualTags) {
-    if (!actualTags.get("tag").equals (desiredTags.get("tag")))
+  private boolean isTagChanged(Map<String, String> desiredTags, Map<String, String> actualTags) {
+    if (!actualTags.get(CLUSTER_DEFAULT_TAG).equals(desiredTags.get(CLUSTER_DEFAULT_TAG)))
       return true;
-    
-    String tag0 = actualTags.get("service_override_tag"); 
-    String tag1 = desiredTags.get("service_override_tag");
-    tag0 = (null == tag0) ? "" : tag0;
-    tag1 = (null == tag1) ? "" : tag1;
-    if (!tag0.equals(tag1))
-      return true;
-    
-    // desired config can only have one value here since it's from the HC.
-    tag0 = actualTags.get("host_override_tag");
-    tag1 = desiredTags.get("host_override_tag");
-    tag0 = (null == tag0) ? "" : tag0;
-    tag1 = (null == tag1) ? "" : tag1;
-    if (!tag0.equals(tag1))
+
+    Set<String> desiredSet = new HashSet<String>(desiredTags.keySet());
+    Set<String> actualSet = new HashSet<String>(actualTags.keySet());
+
+    desiredSet.removeAll(actualSet);
+
+    if (!desiredSet.isEmpty())
       return true;
-    
+
     return false;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
index c9b2e65..5eef430 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.state;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.AgentEnv;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.HostInfo;
@@ -309,4 +310,6 @@ public interface Host {
    * return a map of type-to-{@link DesiredConfig} instances.
    */
   public Map<String, DesiredConfig> getDesiredConfigs(long clusterId);
+
+  public Map<String, HostConfig> getDesiredHostConfigs(Cluster cluster) throws AmbariException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/HostConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/HostConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/state/HostConfig.java
new file mode 100644
index 0000000..0f451ce
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/HostConfig.java
@@ -0,0 +1,74 @@
+/*
+ * 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.state;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Data structure that hangs off of the Host and points to what tags are
+ * applicable to a config derived at the host-level
+ */
+
+public class HostConfig {
+  private final Map<Long, String> configGroupOverrides = new HashMap<Long, String>();
+  private String defaultVersionTag;
+
+  public HostConfig() {
+  }
+
+  @JsonProperty("default")
+  public String getDefaultVersionTag() {
+    return defaultVersionTag;
+  }
+
+  public void setDefaultVersionTag(String defaultVersionTag) {
+    this.defaultVersionTag = defaultVersionTag;
+  }
+
+  @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+  @JsonProperty("overrides")
+  public Map<Long, String> getConfigGroupOverrides() {
+    return configGroupOverrides;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("{");
+    if (defaultVersionTag != null) {
+      sb.append("default = " + defaultVersionTag);
+    }
+    if (!configGroupOverrides.isEmpty()) {
+      sb.append(", overrides = [ ");
+      int i = 0;
+      for (Map.Entry<Long, String> entry : configGroupOverrides.entrySet()) {
+        if (i++ != 0)
+          sb.append(", ");
+        sb.append(entry.getKey().toString() + " : " + entry.getValue());
+      }
+      sb.append("]");
+    }
+    sb.append("}");
+
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
index 627d24d..c4af55a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
@@ -117,7 +117,7 @@ public interface ServiceComponentHost {
    * Gets the actual config tags, if known.
    * @return the actual config map
    */
-  public Map<String, DesiredConfig> getActualConfigs();
+  public Map<String, HostConfig> getActualConfigs();
 
   public HostState getHostState();
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/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 fb897c9..03c3c95 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
@@ -288,15 +288,16 @@ public class ClusterImpl implements Cluster {
           + ", tag = " + configGroup.getTag());
 
         if (clusterConfigGroups.containsKey(configGroup.getId())) {
-          throw new AmbariException("Config group already exists"
+          // The loadConfigGroups will load all groups to memory
+          LOG.debug("Config group already exists"
             + ", clusterName = " + getClusterName()
             + ", groupName = " + configGroup.getName()
             + ", groupId = " + configGroup.getId()
             + ", tag = " + configGroup.getTag());
+        } else {
+          clusterConfigGroups.put(configGroup.getId(), configGroup);
         }
 
-        clusterConfigGroups.put(configGroup.getId(), configGroup);
-
       } finally {
         writeLock.unlock();
       }
@@ -322,23 +323,34 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
-  public Map<Long, ConfigGroup> getConfigGroupsByHostname(String hostname) {
+  public Map<Long, ConfigGroup> getConfigGroupsByHostname(String hostname)
+    throws AmbariException {
+    Map<Long, ConfigGroup> configGroupMap = getConfigGroups();
     Map<Long, ConfigGroup> configGroups = new HashMap<Long, ConfigGroup>();
 
-    List<ConfigGroupHostMappingEntity> hostMappingEntities =
-      configGroupHostMappingDAO.findByHost(hostname);
-
-    if (hostMappingEntities != null && !hostMappingEntities.isEmpty()) {
-      for (ConfigGroupHostMappingEntity entity : hostMappingEntities) {
-        ConfigGroup configGroup = clusterConfigGroups.get(entity
-          .getConfigGroupId());
-        if (configGroup != null && !configGroups.containsKey(configGroup.getId())) {
-          configGroups.put(configGroup.getId(), configGroup);
+    clusterGlobalLock.readLock().lock();
+    try {
+      readLock.lock();
+      try {
+        List<ConfigGroupHostMappingEntity> hostMappingEntities =
+          configGroupHostMappingDAO.findByHost(hostname);
+
+        if (hostMappingEntities != null && !hostMappingEntities.isEmpty()) {
+          for (ConfigGroupHostMappingEntity entity : hostMappingEntities) {
+            ConfigGroup configGroup = configGroupMap.get(entity.getConfigGroupId());
+            if (configGroup != null && !configGroups.containsKey(configGroup.getId())) {
+              configGroups.put(configGroup.getId(), configGroup);
+            }
+          }
         }
+        return configGroups;
+
+      } finally {
+        readLock.unlock();
       }
+    } finally {
+      clusterGlobalLock.readLock().unlock();
     }
-
-    return configGroups;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index 4d92a6a..16dc0fb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -29,6 +29,7 @@ import org.apache.ambari.server.HostNotFoundException;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
 import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
@@ -89,7 +90,7 @@ public class ClustersImpl implements Clusters {
   @Inject
   Gson gson;
   @Inject
-  private HostConfigMappingDAO hostConfigMappingDAO;
+  private ConfigGroupHostMappingDAO configGroupHostMappingDAO;
 
   @Inject
   public ClustersImpl() {
@@ -622,7 +623,7 @@ public class ClustersImpl implements Clusters {
     hostEntity.getClusterEntities().remove(clusterEntity);
     clusterEntity.getHostEntities().remove(hostEntity);
 
-    hostConfigMappingDAO.removeHost(clusterId, hostName);
+    configGroupHostMappingDAO.removeAllByHost(hostName);
     
     hostDAO.merge(hostEntity);
     clusterDAO.merge(clusterEntity);
@@ -640,10 +641,10 @@ public class ClustersImpl implements Clusters {
     try {
       HostEntity entity = hostDAO.findByName(hostname);
       hostDAO.refresh(entity);
-      
       hostDAO.remove(entity);
-      
       hosts.remove(hostname);
+      // Remove Config group mapping
+      configGroupHostMappingDAO.removeAllByHost(hostname);
     } catch (Exception e) {
       throw new AmbariException("Could not remove host", e);
     } finally {

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
index a335a4e..6a2cdb5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
@@ -15,8 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
 package org.apache.ambari.server.state.host;
 
 import java.lang.reflect.Type;
@@ -33,23 +31,28 @@ import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.HostInfo;
 import org.apache.ambari.server.controller.HostResponse;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
 import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostStateDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
 import org.apache.ambari.server.orm.entities.HostConfigMappingEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostStateEntity;
 import org.apache.ambari.server.state.AgentVersion;
+import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostConfig;
 import org.apache.ambari.server.state.HostEvent;
 import org.apache.ambari.server.state.HostEventType;
 import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.SingleArcTransition;
 import org.apache.ambari.server.state.fsm.StateMachine;
@@ -86,6 +89,7 @@ public class HostImpl implements Host {
   private ClusterDAO clusterDAO;
   private Clusters clusters;
   private HostConfigMappingDAO hostConfigMappingDAO;
+  private ConfigGroupHostMappingDAO configGroupHostMappingDAO;
 
   private long lastHeartbeatTime = 0L;
   private AgentEnv lastAgentEnv = null;
@@ -214,6 +218,8 @@ public class HostImpl implements Host {
     this.clusterDAO = injector.getInstance(ClusterDAO.class);
     this.clusters = injector.getInstance(Clusters.class);
     this.hostConfigMappingDAO = injector.getInstance(HostConfigMappingDAO.class);
+    this.configGroupHostMappingDAO = injector.getInstance
+      (ConfigGroupHostMappingDAO.class);
 
     hostStateEntity = hostEntity.getHostStateEntity();
     if (hostStateEntity == null) {
@@ -260,9 +266,9 @@ public class HostImpl implements Host {
         agentVersion = e.agentVersion.getVersion();
       }
       LOG.info("Received host registration, host="
-          + e.hostInfo.toString()
-          + ", registrationTime=" + e.registrationTime
-          + ", agentVersion=" + agentVersion);
+        + e.hostInfo.toString()
+        + ", registrationTime=" + e.registrationTime
+        + ", agentVersion=" + agentVersion);
       host.persist();
     }
   }
@@ -278,7 +284,7 @@ public class HostImpl implements Host {
           + ", host=" + e.getHostName()
           + ", heartbeatTime=" + e.getTimestamp());
       host.setHealthStatus(new HostHealthStatus(HealthStatus.HEALTHY,
-          host.getHealthStatus().getHealthReport()));
+        host.getHealthStatus().getHealthReport()));
     }
   }
 
@@ -1142,7 +1148,7 @@ public class HostImpl implements Host {
   @Override
   public Map<String, DesiredConfig> getDesiredConfigs(long clusterId) {
     Map<String, DesiredConfig> map = new HashMap<String, DesiredConfig>();
-    
+
     for (HostConfigMappingEntity e : hostConfigMappingDAO.findSelected(
         clusterId, hostEntity.getHostName())) {
       
@@ -1155,10 +1161,45 @@ public class HostImpl implements Host {
     }
     return map;
   }
-  
+
+  /**
+   * Get a map of configType with all applicable config tags.
+   *
+   * @param cluster
+   * @return Map of configType -> HostConfig
+   */
+  @Override
+  public Map<String, HostConfig> getDesiredHostConfigs(Cluster cluster) throws AmbariException {
+    Map<String, HostConfig> hostConfigMap = new HashMap<String, HostConfig>();
+
+    Map<Long, ConfigGroup> configGroups = cluster.getConfigGroupsByHostname
+      (this.getHostName());
+
+    if (configGroups != null && !configGroups.isEmpty()) {
+      for (ConfigGroup configGroup : configGroups.values()) {
+        for (Map.Entry<String, Config> configEntry : configGroup
+            .getConfigurations().entrySet()) {
+
+          String configType = configEntry.getKey();
+          // HostConfig config holds configType -> versionTag, per config group
+          HostConfig hostConfig = hostConfigMap.get(configType);
+          if (hostConfig == null) {
+            hostConfig = new HostConfig();
+            hostConfigMap.put(configType, hostConfig);
+            hostConfig.setDefaultVersionTag(cluster.getDesiredConfigByType
+              (configType).getVersionTag());
+          }
+          Config config = configEntry.getValue();
+          hostConfig.getConfigGroupOverrides().put(configGroup.getId(),
+            config.getVersionTag());
+        }
+      }
+    }
+    return hostConfigMap;
+  }
+
   private HostConfigMappingEntity getDesiredConfigEntity(long clusterId, String type) {
     return hostConfigMappingDAO.findSelectedByType(clusterId,
         hostEntity.getHostName(), type);
   }
-      
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index 71ae98f..a4897ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -18,12 +18,12 @@
 
 package org.apache.ambari.server.state.svccomphost;
 
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.orm.dao.HostComponentConfigMappingDAO;
@@ -41,8 +41,20 @@ import org.apache.ambari.server.orm.entities.HostComponentStateEntityPK;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntityPK;
-import org.apache.ambari.server.state.*;
-import org.apache.ambari.server.state.DesiredConfig.HostOverride;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostConfig;
+import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceComponentHostEvent;
+import org.apache.ambari.server.state.ServiceComponentHostEventType;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.SingleArcTransition;
 import org.apache.ambari.server.state.fsm.StateMachine;
@@ -50,13 +62,17 @@ import org.apache.ambari.server.state.fsm.StateMachineFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.assistedinject.Assisted;
-import com.google.inject.assistedinject.AssistedInject;
-import com.google.inject.persist.Transactional;
-import java.util.logging.Level;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public class ServiceComponentHostImpl implements ServiceComponentHost {
 
@@ -90,7 +106,6 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   HostComponentDesiredConfigMappingDAO hostComponentDesiredConfigMappingDAO;
   @Inject
   HostComponentConfigMappingDAO hostComponentConfigMappingDAO;
-  
   @Inject
   ConfigHelper helper;
 
@@ -103,7 +118,8 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   private long lastOpStartTime;
   private long lastOpEndTime;
   private long lastOpLastUpdateTime;
-  private Map<String, DesiredConfig> actualConfigs = new HashMap<String, DesiredConfig>();
+  private Map<String, HostConfig> actualConfigs = new HashMap<String,
+    HostConfig>();
 
   private static final StateMachineFactory
   <ServiceComponentHostImpl, State,
@@ -1550,31 +1566,52 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   
   @Override
   public void updateActualConfigs(Map<String, Map<String, String>> configTags) {
+    Cluster cluster = null;
+    Map<Long, ConfigGroup> configGroupMap = new HashMap<Long, ConfigGroup>();
+    try {
+      cluster = clusters.getClusterById(getClusterId());
+      if (cluster != null) {
+        configGroupMap = cluster.getConfigGroups();
+      }
+    } catch (AmbariException ae) {
+      LOG.warn("Unable to get cluster info for cluster id = " + getClusterId());
+    }
+
     clusterGlobalLock.readLock().lock();
     try {
       writeLock.lock();
       try {
-
-        actualConfigs = new HashMap<String, DesiredConfig>();
-
-        String hostName = getHostName();
+        actualConfigs = new HashMap<String, HostConfig>();
 
         for (Entry<String, Map<String, String>> entry : configTags.entrySet()) {
           String type = entry.getKey();
-          Map<String, String> values = entry.getValue();
-
-          String tag = values.get("tag");
-          String hostTag = values.get("host_override_tag");
-
-          DesiredConfig dc = new DesiredConfig();
-          dc.setServiceName(values.get("service_override_tag"));
-          dc.setVersion(tag);
-          actualConfigs.put(type, dc);
-          if (null != hostTag && null != hostName) {
-            List<HostOverride> list = new ArrayList<HostOverride>();
-            list.add(new HostOverride(hostName, hostTag));
-            dc.setHostOverrides(list);
+          Map<String, String> values = new HashMap<String, String>(entry.getValue());
+
+          String tag = values.get(ConfigHelper.CLUSTER_DEFAULT_TAG);
+          values.remove(ConfigHelper.CLUSTER_DEFAULT_TAG);
+
+          HostConfig hc = new HostConfig();
+          hc.setDefaultVersionTag(tag);
+          actualConfigs.put(type, hc);
+
+          if (!values.isEmpty()) {
+            for (Entry<String, String> overrideEntry : values.entrySet()) {
+              try {
+                Long groupId = Long.parseLong(overrideEntry.getKey());
+                ConfigGroup configGroup = configGroupMap.get(groupId);
+                if (configGroup != null) {
+                  hc.getConfigGroupOverrides().put(groupId,
+                    overrideEntry.getValue());
+                } else {
+                  LOG.info("Cannot find config group with id = " + groupId);
+                }
+              } catch (Exception e) {
+                LOG.warn("Unable to retrieve config group info for id = " +
+                  overrideEntry.getKey());
+              }
+            }
           }
+
         }
       } finally {
         writeLock.unlock();
@@ -1586,7 +1623,7 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   }
   
   @Override
-  public Map<String, DesiredConfig> getActualConfigs() {
+  public Map<String, HostConfig> getActualConfigs() {
     clusterGlobalLock.readLock().lock();
     try {
       readLock.lock();

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java
index 7030889..4ef5561 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java
@@ -40,6 +40,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigFactory;
+import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.utils.StageUtils;
 import org.codehaus.jettison.json.JSONException;
@@ -88,11 +89,13 @@ public class ExecutionCommandWrapperTest {
   private static Injector injector;
   private static Clusters clusters;
   private static ConfigFactory configFactory;
+  private static ConfigHelper configHelper;
 
   @BeforeClass
   public static void setup() throws AmbariException {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
+    configHelper = injector.getInstance(ConfigHelper.class);
     configFactory = injector.getInstance(ConfigFactory.class);
     
     clusters = injector.getInstance(Clusters.class);
@@ -246,7 +249,8 @@ public class ExecutionCommandWrapperTest {
     overrideConfig.put(SERVICE_SITE_NAME6, SERVICE_SITE_VAL6_H);
     
     
-    Map<String, String> mergedConfig = ExecutionCommandWrapper.getMergedConfig(baseConfig, overrideConfig);
+    Map<String, String> mergedConfig = configHelper.getMergedConfig(baseConfig,
+      overrideConfig);
     
     
     Set<String> configsKeys = new HashSet<String>();

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/62926200/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
index 43313ec..bdf9e94 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
@@ -129,7 +129,8 @@ public class TestHeartbeatMonitor {
 
     ActionQueue aq = new ActionQueue();
     ActionManager am = mock(ActionManager.class);
-    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aq, am, heartbeatMonitorWakeupIntervalMS);
+    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aq, am,
+      heartbeatMonitorWakeupIntervalMS, ambariMetaInfo);
     HeartBeatHandler handler = new HeartBeatHandler(clusters, aq, am, injector);
     Register reg = new Register();
     reg.setHostname(hostname1);
@@ -216,7 +217,7 @@ public class TestHeartbeatMonitor {
     ActionQueue aq = new ActionQueue();
     ActionManager am = mock(ActionManager.class);
     HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aq, am,
-      heartbeatMonitorWakeupIntervalMS);
+      heartbeatMonitorWakeupIntervalMS, ambariMetaInfo);
     HeartBeatHandler handler = new HeartBeatHandler(clusters, aq, am, injector);
     Register reg = new Register();
     reg.setHostname(hostname1);
@@ -296,7 +297,8 @@ public class TestHeartbeatMonitor {
             forClass(AgentCommand.class);
 
     ActionManager am = mock(ActionManager.class);
-    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aqMock, am, heartbeatMonitorWakeupIntervalMS);
+    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aqMock, am,
+      heartbeatMonitorWakeupIntervalMS, ambariMetaInfo);
     HeartBeatHandler handler = new HeartBeatHandler(clusters, aqMock, am,
         injector);
     Register reg = new Register();
@@ -341,7 +343,7 @@ public class TestHeartbeatMonitor {
     fsm.addHost(hostname);
     ActionQueue aq = new ActionQueue();
     ActionManager am = mock(ActionManager.class);
-    HeartbeatMonitor hm = new HeartbeatMonitor(fsm, aq, am, 10);
+    HeartbeatMonitor hm = new HeartbeatMonitor(fsm, aq, am, 10, ambariMetaInfo);
     HeartBeatHandler handler = new HeartBeatHandler(fsm, aq, am, injector);
     Register reg = new Register();
     reg.setHostname(hostname);
@@ -398,7 +400,7 @@ public class TestHeartbeatMonitor {
     
     ActionQueue aq = new ActionQueue();
     ActionManager am = mock(ActionManager.class);
-    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aq, am, 10);
+    HeartbeatMonitor hm = new HeartbeatMonitor(clusters, aq, am, 10, ambariMetaInfo);
     HeartBeatHandler handler = new HeartBeatHandler(clusters, aq, am, injector);
     
     Register reg = new Register();