You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/08/27 16:05:00 UTC

[19/35] git commit: AMBARI-7015 Config History: API should create exactly one SCV when instructed to save multiple configs in a batch (dsen)

AMBARI-7015 Config History: API should create exactly one SCV when instructed to save multiple configs in a batch (dsen)


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

Branch: refs/heads/branch-alerts-dev
Commit: 2cceee2ea3933b05cef97e6d48f029dcebe9c200
Parents: d566bca
Author: Dmytro Sen <ds...@hortonworks.com>
Authored: Tue Aug 26 20:10:18 2014 +0300
Committer: Dmytro Sen <ds...@hortonworks.com>
Committed: Tue Aug 26 20:10:18 2014 +0300

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         | 38 ++++----
 .../server/controller/ClusterRequest.java       | 16 ++--
 .../ambari/server/controller/HostRequest.java   | 11 +--
 .../internal/AbstractResourceProvider.java      | 92 +++++++++++++-------
 .../internal/ClusterResourceProvider.java       |  7 +-
 .../internal/HostResourceProvider.java          | 54 ++++++------
 .../org/apache/ambari/server/state/Cluster.java |  9 +-
 .../ambari/server/state/ConfigHelper.java       |  3 +-
 .../server/state/cluster/ClusterImpl.java       | 52 +++++++----
 .../server/upgrade/AbstractUpgradeCatalog.java  |  3 +-
 .../server/agent/TestHeartbeatMonitor.java      |  4 +-
 .../AmbariManagementControllerTest.java         | 76 ++++++++--------
 ...hYarnCapacitySchedulerReleaseConfigTest.java |  4 +-
 .../internal/ClusterResourceProviderTest.java   | 40 ++++-----
 .../internal/JMXHostProviderTest.java           | 10 +--
 .../ambari/server/state/ConfigHelperTest.java   |  6 +-
 .../server/state/cluster/ClusterTest.java       | 55 +++++++++---
 .../server/state/cluster/ClustersTest.java      |  3 +-
 .../svccomphost/ServiceComponentHostTest.java   |  3 +-
 .../server/upgrade/UpgradeCatalogTest.java      |  2 +-
 20 files changed, 293 insertions(+), 195 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 c465189..394f6ad 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
@@ -53,6 +53,7 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -676,7 +677,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         if (config != null) {
           String authName = getAuthName();
 
-          if (cluster.addDesiredConfig(authName, config) != null) {
+          if (cluster.addDesiredConfig(authName, Collections.singleton(config)) != null) {
             LOG.info("cluster '" + cluster.getClusterName() + "' "
                     + "changed by: '" + authName + "'; "
                     + "type='" + config.getType() + "' "
@@ -1151,14 +1152,15 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
     final Cluster cluster = clusters.getCluster(request.getClusterName());
     //save data to return configurations created
-    ConfigurationResponse configurationResponse = null;
+    List<ConfigurationResponse> configurationResponses =
+      new LinkedList<ConfigurationResponse>();
     ServiceConfigVersionResponse serviceConfigVersionResponse = null;
 
     // set or create configuration mapping (and optionally create the map of properties)
     if (null != request.getDesiredConfig()) {
-      ConfigurationRequest cr = request.getDesiredConfig();
-
-      Config oldConfig = cluster.getDesiredConfigByType(cr.getType());
+      Set<Config> configs = new HashSet<Config>();
+      String note = null;
+      for (ConfigurationRequest cr: request.getDesiredConfig()) {
 
       if (null != cr.getProperties()) {
         // !!! empty property sets are supported, and need to be able to use
@@ -1173,21 +1175,23 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
               request.getClusterName()));
 
           cr.setClusterName(cluster.getClusterName());
-          configurationResponse = createConfiguration(cr);
+          configurationResponses.add(createConfiguration(cr));
         }
       }
-
-      Config baseConfig = cluster.getConfig(cr.getType(), cr.getVersionTag());
-      if (null != baseConfig) {
+        note = cr.getServiceConfigVersionNote();
+        configs.add(cluster.getConfig(cr.getType(), cr.getVersionTag()));
+      }
+      if (!configs.isEmpty()) {
         String authName = getAuthName();
-        serviceConfigVersionResponse = cluster.addDesiredConfig(authName, baseConfig, cr.getServiceConfigVersionNote());
+        serviceConfigVersionResponse = cluster.addDesiredConfig(authName, configs, note);
         if (serviceConfigVersionResponse != null) {
           Logger logger = LoggerFactory.getLogger("configchange");
-          logger.info("cluster '" + request.getClusterName() + "' "
-              + "changed by: '" + authName + "'; "
-              + "type='" + baseConfig.getType() + "' "
-              + "tag='" + baseConfig.getTag() + "'"
-              + (null == oldConfig ? "" : " from='"+ oldConfig.getTag() + "'"));
+          for (Config config: configs) {
+            logger.info("cluster '" + request.getClusterName() + "' "
+                + "changed by: '" + authName + "'; "
+                + "type='" + config.getType() + "' "
+                + "tag='" + config.getTag() + "'");
+          }
         }
       }
     }
@@ -1261,8 +1265,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     }
 
     if (serviceConfigVersionResponse != null) {
-      if (configurationResponse != null) {
-        serviceConfigVersionResponse.setConfigurations(Collections.singletonList(configurationResponse));
+      if (!configurationResponses.isEmpty()) {
+        serviceConfigVersionResponse.setConfigurations(configurationResponses);
       }
 
       ClusterResponse clusterResponse =

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 14cc6be..caafb25 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
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -35,7 +36,7 @@ public class ClusterRequest {
   
   Set<String> hostNames; // CREATE/UPDATE
   
-  private ConfigurationRequest config = null;
+  private List<ConfigurationRequest> configs = null;
 
   private ServiceConfigVersionRequest serviceConfigVersionRequest = null;
 
@@ -128,19 +129,20 @@ public class ClusterRequest {
   }
   
   /**
-   * Sets the config request (if any)
+   * Sets the configs requests (if any)
    * @param configRequest
    */
-  public void setDesiredConfig(ConfigurationRequest configRequest) {
-    config = configRequest;
+  public void setDesiredConfig(List<ConfigurationRequest> configRequest) {
+    configs = configRequest;
   }
   
   /**
    * Gets any configuration-based request (if any).
-   * @return the configuration request, or <code>null</code> if none is set.
+   * @return the list of configuration requests,
+   * or <code>null</code> if none is set.
    */
-  public ConfigurationRequest getDesiredConfig() {
-    return config;
+  public List<ConfigurationRequest> getDesiredConfig() {
+    return configs;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
index f3668c1..b577bb0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -28,7 +29,7 @@ public class HostRequest {
   private String clusterName; // CREATE/UPDATE
   private Map<String, String> hostAttributes; // CREATE/UPDATE
   private String rackInfo;
-  private ConfigurationRequest desiredConfig; // UPDATE
+  private List<ConfigurationRequest> desiredConfigs; // UPDATE
   private String maintenanceState; // UPDATE
 
   public HostRequest(String hostname, String clusterName, Map<String, String> hostAttributes) {
@@ -77,12 +78,12 @@ public class HostRequest {
     publicHostname = name;
   }
   
-  public void setDesiredConfig(ConfigurationRequest request) {
-    desiredConfig = request;
+  public void setDesiredConfigs(List<ConfigurationRequest> request) {
+    desiredConfigs = request;
   }
   
-  public ConfigurationRequest getDesiredConfig() {
-    return desiredConfig;
+  public List<ConfigurationRequest> getDesiredConfigs() {
+    return desiredConfigs;
   }
   
   public void setMaintenanceState(String state) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 a881730..d14cdf3 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
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -343,50 +344,79 @@ public abstract class AbstractResourceProvider extends BaseProvider implements R
    *    whose category is the parent and marked as a desired config.
    * @param properties  the properties on the request.
    */
-  protected ConfigurationRequest getConfigurationRequest(String parentCategory, Map<String, Object> properties) {
+  protected List<ConfigurationRequest> getConfigurationRequests(String parentCategory, Map<String, Object> properties) {
+
+    List<ConfigurationRequest> configs = new LinkedList<ConfigurationRequest>();
+
+    String desiredConfigKey = parentCategory + "/desired_config";
+    // Multiple configs to be updated
+    if (properties.containsKey(desiredConfigKey)
+      && properties.get(desiredConfigKey) instanceof Set) {
+
+      Set<Map<String, Object>> configProperties =
+        (Set<Map<String, Object>>) properties.get(desiredConfigKey);
+      for (Map<String, Object> value: configProperties) {
+        ConfigurationRequest newConfig = new ConfigurationRequest();
+
+        for (Entry<String, Object> e : value.entrySet()) {
+          String propName =
+            PropertyHelper.getPropertyName(desiredConfigKey + '/' + e.getKey());
+          String absCatategory =
+            PropertyHelper.getPropertyCategory(desiredConfigKey + '/' + e.getKey());
+          parseProperties(newConfig, absCatategory, propName, e.getValue().toString());
+        }
+        configs.add(newConfig);
+      }
+      return configs;
+    }
 
     ConfigurationRequest config = null;
-
     // as a convenience, allow consumers to specify name/value overrides in this
     // call instead of forcing a cluster call to do that work
     for (Entry<String, Object> entry : properties.entrySet()) {
       String absCategory = PropertyHelper.getPropertyCategory(entry.getKey());
       String propName = PropertyHelper.getPropertyName(entry.getKey());
 
-      if (absCategory.startsWith(parentCategory + "/desired_config")) {
+      if (absCategory.startsWith(desiredConfigKey)) {
         config = (null == config) ? new ConfigurationRequest() : config;
 
-        if (propName.equals("type"))
-          config.setType(entry.getValue().toString());
-        else if (propName.equals("tag"))
-          config.setVersionTag(entry.getValue().toString());
-        else if (propName.equals("selected")) {
-          config.setSelected(Boolean.parseBoolean(entry.getValue().toString()));
-        }
-        else if (propName.equals("service_config_version_note")) {
-          config.setServiceConfigVersionNote(entry.getValue().toString());
-        }
-        else if (absCategory.endsWith("/properties")) {
-          config.getProperties().put(propName, entry.getValue().toString());
-        }
-        else if (propertiesAttributesPattern.matcher(absCategory).matches()) {
-          String attributeName = absCategory.substring(absCategory.lastIndexOf('/') + 1);
-          Map<String, Map<String, String>> configAttributesMap = config.getPropertiesAttributes();
-          if (null == configAttributesMap) {
-            configAttributesMap = new HashMap<String, Map<String,String>>();
-            config.setPropertiesAttributes(configAttributesMap);
-          }
-          Map<String, String> attributesMap = configAttributesMap.get(attributeName);
-          if (null == attributesMap) {
-            attributesMap = new HashMap<String, String>();
-            configAttributesMap.put(attributeName, attributesMap);
-          }
-          attributesMap.put(PropertyHelper.getPropertyName(entry.getKey()), entry.getValue().toString());
-        }
+        parseProperties(config, absCategory, propName, entry.getValue().toString());
       }
     }
+    if (config != null) {
+      configs.add(config);
+    }
+    return configs;
+  }
 
-    return config;
+  private void parseProperties(ConfigurationRequest config, String absCategory, String propName, String propValue) {
+    if (propName.equals("type"))
+      config.setType(propValue);
+    else if (propName.equals("tag"))
+      config.setVersionTag(propValue);
+    else if (propName.equals("selected")) {
+      config.setSelected(Boolean.parseBoolean(propValue));
+    }
+    else if (propName.equals("service_config_version_note")) {
+      config.setServiceConfigVersionNote(propValue);
+    }
+    else if (absCategory.endsWith("/properties")) {
+      config.getProperties().put(propName, propValue);
+    }
+    else if (propertiesAttributesPattern.matcher(absCategory).matches()) {
+      String attributeName = absCategory.substring(absCategory.lastIndexOf('/') + 1);
+      Map<String, Map<String, String>> configAttributesMap = config.getPropertiesAttributes();
+      if (null == configAttributesMap) {
+        configAttributesMap = new HashMap<String, Map<String,String>>();
+        config.setPropertiesAttributes(configAttributesMap);
+      }
+      Map<String, String> attributesMap = configAttributesMap.get(attributeName);
+      if (null == attributesMap) {
+        attributesMap = new HashMap<String, String>();
+        configAttributesMap.put(attributeName, attributesMap);
+      }
+      attributesMap.put(propName, propValue);
+    }
   }
 
   // get the resources (id fields only) for the given predicate.

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 b0e2dd4..3fcfcd4 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
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -319,12 +320,12 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         null);
 
-    ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
+    List<ConfigurationRequest> configRequests = getConfigurationRequests("Clusters", properties);
 
     ServiceConfigVersionRequest serviceConfigVersionRequest = getServiceConfigVersionRequest("Clusters", properties);
 
-    if (null != configRequest)
-      cr.setDesiredConfig(configRequest);
+    if (!configRequests.isEmpty())
+      cr.setDesiredConfig(configRequests);
 
     if (serviceConfigVersionRequest != null) {
       cr.setServiceConfigVersionRequest(serviceConfigVersionRequest);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 559f64d..03f7233 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
@@ -330,9 +330,9 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
     if (null != o)
       hostRequest.setMaintenanceState(o.toString());
     
-    ConfigurationRequest cr = getConfigurationRequest("Hosts", properties);
+    List<ConfigurationRequest> cr = getConfigurationRequests("Hosts", properties);
     
-    hostRequest.setDesiredConfig(cr);
+    hostRequest.setDesiredConfigs(cr);
 
     return hostRequest;
   }
@@ -588,40 +588,40 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
         }
       }
 
-      if (null != request.getClusterName() && null != request.getDesiredConfig()) {
+      if (null != request.getClusterName() && null != request.getDesiredConfigs()) {
         Cluster c = clusters.getCluster(request.getClusterName());
 
         if (clusters.getHostsForCluster(request.getClusterName()).containsKey(h.getHostName())) {
 
-          ConfigurationRequest cr = request.getDesiredConfig();
+          for (ConfigurationRequest cr : request.getDesiredConfigs()) {
 
-          if (null != cr.getProperties() && cr.getProperties().size() > 0) {
-            LOG.info(MessageFormat.format("Applying configuration with tag ''{0}'' to host ''{1}'' in cluster ''{2}''",
-                cr.getVersionTag(),
-                request.getHostname(),
-                request.getClusterName()));
+            if (null != cr.getProperties() && cr.getProperties().size() > 0) {
+              LOG.info(MessageFormat.format("Applying configuration with tag ''{0}'' to host ''{1}'' in cluster ''{2}''",
+                  cr.getVersionTag(),
+                  request.getHostname(),
+                  request.getClusterName()));
 
-            cr.setClusterName(c.getClusterName());
-            controller.createConfiguration(cr);
-          }
+              cr.setClusterName(c.getClusterName());
+              controller.createConfiguration(cr);
+            }
 
-          Config baseConfig = c.getConfig(cr.getType(), cr.getVersionTag());
-          if (null != baseConfig) {
-            String authName = controller.getAuthName();
-            DesiredConfig oldConfig = h.getDesiredConfigs(c.getClusterId()).get(cr.getType());
-
-            if (h.addDesiredConfig(c.getClusterId(), cr.isSelected(), authName,  baseConfig)) {
-              Logger logger = LoggerFactory.getLogger("configchange");
-              logger.info("cluster '" + c.getClusterName() + "', "
-                  + "host '" + h.getHostName() + "' "
-                  + "changed by: '" + authName + "'; "
-                  + "type='" + baseConfig.getType() + "' "
-                  + "version='" + baseConfig.getVersion() + "'"
-                  + "tag='" + baseConfig.getTag() + "'"
-                  + (null == oldConfig ? "" : ", from='" + oldConfig.getTag() + "'"));
+            Config baseConfig = c.getConfig(cr.getType(), cr.getVersionTag());
+            if (null != baseConfig) {
+              String authName = controller.getAuthName();
+              DesiredConfig oldConfig = h.getDesiredConfigs(c.getClusterId()).get(cr.getType());
+
+              if (h.addDesiredConfig(c.getClusterId(), cr.isSelected(), authName,  baseConfig)) {
+                Logger logger = LoggerFactory.getLogger("configchange");
+                logger.info("cluster '" + c.getClusterName() + "', "
+                    + "host '" + h.getHostName() + "' "
+                    + "changed by: '" + authName + "'; "
+                    + "type='" + baseConfig.getType() + "' "
+                    + "version='" + baseConfig.getVersion() + "'"
+                    + "tag='" + baseConfig.getTag() + "'"
+                    + (null == oldConfig ? "" : ", from='" + oldConfig.getTag() + "'"));
+              }
             }
           }
-
         }
       }
       //todo: if attempt was made to update a property other than those

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 8970961..2c83f1c 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
@@ -21,6 +21,7 @@ package org.apache.ambari.server.state;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.locks.ReadWriteLock;
 
 import com.google.common.collect.ListMultimap;
@@ -157,22 +158,22 @@ public interface Cluster {
    * Adds and sets a DESIRED configuration to be applied to a cluster.  There
    * can be only one selected config per type.
    * @param user the user making the change for audit purposes
-   * @param config  the {@link org.apache.ambari.server.state.Config} object to set as desired
+   * @param configs  the set of {@link org.apache.ambari.server.state.Config} objects to set as desired
    * @return <code>true</code> if the config was added, or <code>false</code>
    * if the config is already set as the current
    */
-  public ServiceConfigVersionResponse addDesiredConfig(String user, Config config);
+  public ServiceConfigVersionResponse addDesiredConfig(String user, Set<Config> configs);
 
   /**
    * Adds and sets a DESIRED configuration to be applied to a cluster.  There
    * can be only one selected config per type.
    * @param user the user making the change for audit purposes
-   * @param config  the {@link org.apache.ambari.server.state.Config} object to set as desired
+   * @param configs  the set of {@link org.apache.ambari.server.state.Config} objects to set as desired
    * @param serviceConfigVersionNote note to attach to service config version if created
    * @return <code>true</code> if the config was added, or <code>false</code>
    * if the config is already set as the current
    */
-  ServiceConfigVersionResponse addDesiredConfig(String user, Config config, String serviceConfigVersionNote);
+  ServiceConfigVersionResponse addDesiredConfig(String user, Set<Config> configs, String serviceConfigVersionNote);
 
   ServiceConfigVersionResponse createServiceConfigVersion(String serviceName, String user, String note,
                                                           ConfigGroup configGroup);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 1161cc6..a0d9e6e 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
@@ -19,6 +19,7 @@ package org.apache.ambari.server.state;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -477,7 +478,7 @@ public class ConfigHelper {
     Config baseConfig = cluster.getConfig(cr.getType(), cr.getVersionTag());
     
     if (baseConfig != null) {
-      cluster.addDesiredConfig(authName, baseConfig);
+      cluster.addDesiredConfig(authName, Collections.singleton(baseConfig));
     }
   }
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 ee6952a..8e073f1 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
@@ -1333,12 +1333,12 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
-  public ServiceConfigVersionResponse addDesiredConfig(String user, Config config) {
-    return addDesiredConfig(user, config, null);
+  public ServiceConfigVersionResponse addDesiredConfig(String user, Set<Config> configs) {
+    return addDesiredConfig(user, configs, null);
   }
 
   @Override
-  public ServiceConfigVersionResponse addDesiredConfig(String user, Config config, String serviceConfigVersionNote) {
+  public ServiceConfigVersionResponse addDesiredConfig(String user, Set<Config> configs, String serviceConfigVersionNote) {
     if (null == user)
       throw new NullPointerException("User must be specified.");
 
@@ -1346,15 +1346,28 @@ public class ClusterImpl implements Cluster {
     try {
       readWriteLock.writeLock().lock();
       try {
-        Config currentDesired = getDesiredConfigByType(config.getType());
-
-        // do not set if it is already the current
-        if (null != currentDesired && currentDesired.getTag().equals(config.getTag())) {
+        if (configs == null) {
           return null;
         }
 
+        Iterator<Config> configIterator = configs.iterator();
+
+        while (configIterator.hasNext()) {
+          Config config = configIterator.next();
+          if (config == null) {
+            configIterator.remove();
+            continue;
+          }
+          Config currentDesired = getDesiredConfigByType(config.getType());
+
+          // do not set if it is already the current
+          if (null != currentDesired && currentDesired.getTag().equals(config.getTag())) {
+            configIterator.remove();
+          }
+        }
+
         ServiceConfigVersionResponse serviceConfigVersionResponse =
-            applyConfig(config.getType(), config.getTag(), user, serviceConfigVersionNote);
+            applyConfigs(configs, user, serviceConfigVersionNote);
 
         configHelper.invalidateStaleConfigsCache();
         return serviceConfigVersionResponse;
@@ -1705,16 +1718,23 @@ public class ClusterImpl implements Cluster {
   }
 
   @Transactional
-  ServiceConfigVersionResponse applyConfig(String type, String tag, String user, String serviceConfigVersionNote) {
-
-    selectConfig(type, tag, user);
+  ServiceConfigVersionResponse applyConfigs(Set<Config> configs, String user, String serviceConfigVersionNote) {
 
     String serviceName = null;
-    //find service name for config type
-    for (Entry<String, String> entry : serviceConfigTypes.entries()) {
-      if (StringUtils.equals(entry.getValue(), type)) {
-        serviceName = entry.getKey();
-        break;
+    for (Config config: configs) {
+
+      selectConfig(config.getType(), config.getTag(), user);
+      //find service name for config type
+      for (Entry<String, String> entry : serviceConfigTypes.entries()) {
+        if (StringUtils.equals(entry.getValue(), config.getType())) {
+          if (serviceName != null && !serviceName.equals(entry.getKey())) {
+            LOG.error("Updating configs for multiple services by a " +
+              "single API request isn't supported, config version not created");
+            return null;
+          }
+          serviceName = entry.getKey();
+          break;
+        }
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
index 4d68402..a53159c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.persistence.EntityManager;
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
@@ -227,7 +228,7 @@ public abstract class AbstractUpgradeCatalog implements UpgradeCatalog {
               if (baseConfig != null) {
                 String authName = "ambari-upgrade";
 
-                if (cluster.addDesiredConfig(authName, baseConfig) != null) {
+                if (cluster.addDesiredConfig(authName, Collections.singleton(baseConfig)) != null) {
                   String oldConfigString = (oldConfig != null) ? " from='" + oldConfig.getTag() + "'" : "";
                   LOG.info("cluster '" + cluster.getClusterName() + "' "
                     + "changed by: '" + authName + "'; "

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/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 847a34d..e80e3e5 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
@@ -127,7 +127,7 @@ public class TestHeartbeatMonitor {
         new HashMap<String,String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
     config.setTag("version1");
     cluster.addConfig(config);
-    cluster.addDesiredConfig("_test", config);
+    cluster.addDesiredConfig("_test", Collections.singleton(config));
     
     
     clusters.mapHostsToCluster(hostNames, clusterName);
@@ -218,7 +218,7 @@ public class TestHeartbeatMonitor {
       }}, new HashMap<String, Map<String,String>>());
     config.setTag("version1");
     cluster.addConfig(config);
-    cluster.addDesiredConfig("_test", config);
+    cluster.addDesiredConfig("_test", Collections.singleton(config));
 
 
     clusters.mapHostsToCluster(hostNames, clusterName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index ca76dc5..cf2bcbb 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -2274,7 +2274,7 @@ public class AmbariManagementControllerTest {
     cr1 = new ConfigurationRequest(clusterName, "hdfs-site", "version1",
         configs, null);
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Start
@@ -4220,8 +4220,8 @@ public class AmbariManagementControllerTest {
 
     cluster.addConfig(config1);
     cluster.addConfig(config2);
-    cluster.addDesiredConfig("_test", config1);
-    cluster.addDesiredConfig("_test", config2);
+    cluster.addDesiredConfig("_test", Collections.singleton(config1));
+    cluster.addDesiredConfig("_test", Collections.singleton(config2));
 
     Service hdfs = cluster.addService("HDFS");
     hdfs.persist();
@@ -4482,8 +4482,8 @@ public class AmbariManagementControllerTest {
 
     cluster.addConfig(config1);
     cluster.addConfig(config2);
-    cluster.addDesiredConfig("_test", config1);
-    cluster.addDesiredConfig("_test", config2);
+    cluster.addDesiredConfig("_test", Collections.singleton(config1));
+    cluster.addDesiredConfig("_test", Collections.singleton(config2));
 
     Service hdfs = cluster.addService("HDFS");
     Service mapReduce = cluster.addService("MAPREDUCE");
@@ -4666,8 +4666,8 @@ public class AmbariManagementControllerTest {
 
 
     ClusterRequest cr = new ClusterRequest(null, clusterName, null, null);
-    cr.setDesiredConfig(new ConfigurationRequest(clusterName, "global",
-        "v1", configs, null));
+    cr.setDesiredConfig(Collections.singletonList(new ConfigurationRequest(clusterName, "global",
+        "v1", configs, null)));
     controller.updateClusters(Collections.singleton(cr), Collections.<String, String>emptyMap());
 
     Set<ServiceRequest> sReqs = new HashSet<ServiceRequest>();
@@ -5268,10 +5268,10 @@ public class AmbariManagementControllerTest {
       configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Install
@@ -5294,7 +5294,7 @@ public class AmbariManagementControllerTest {
     cr3 = new ConfigurationRequest(clusterName, "core-site","version122",
       configs, null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr3);
+    crReq.setDesiredConfig(Collections.singletonList(cr3));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Stop HDFS & MAPREDUCE
@@ -5425,10 +5425,10 @@ public class AmbariManagementControllerTest {
       configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     installService(clusterName, serviceName, false, false);
@@ -5451,7 +5451,7 @@ public class AmbariManagementControllerTest {
     cr3 = new ConfigurationRequest(clusterName, "core-site","version122",
       configs, null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr3);
+    crReq.setDesiredConfig(Collections.singletonList(cr3));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     long id = startService(clusterName, serviceName, false, true);
@@ -6027,7 +6027,7 @@ public class AmbariManagementControllerTest {
     cr1 = new ConfigurationRequest(clusterName, "hive-site","version1",
       configs, null);
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Install
@@ -6105,7 +6105,7 @@ public class AmbariManagementControllerTest {
     cr1 = new ConfigurationRequest(clusterName, "hdfs-site","version1",
       configs, null);
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Start
@@ -6491,10 +6491,10 @@ public class AmbariManagementControllerTest {
       configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Install
@@ -6716,13 +6716,13 @@ public class AmbariManagementControllerTest {
       configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr3);
+    crReq.setDesiredConfig(Collections.singletonList(cr3));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Create Config group for core-site
@@ -6874,7 +6874,7 @@ public class AmbariManagementControllerTest {
     cr1 = new ConfigurationRequest(clusterName, "hdfs-site", "version1",
         configs, null);
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Start
@@ -6977,10 +6977,10 @@ public class AmbariManagementControllerTest {
       configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     // Install
@@ -8831,7 +8831,7 @@ public class AmbariManagementControllerTest {
 
       ConfigurationRequest configRequest = new ConfigurationRequest(CLUSTER_NAME, "global", "version1",
           new HashMap<String, String>() {{ put("a", "b"); }}, null);
-      cr.setDesiredConfig(configRequest);
+      cr.setDesiredConfig(Collections.singletonList(configRequest));
       amc.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
 
       // add some hosts
@@ -10067,22 +10067,22 @@ public class AmbariManagementControllerTest {
     ClusterRequest cr = new ClusterRequest(null, cluster.getClusterName(), null, null);
 
     // test null map with no prior
-    cr.setDesiredConfig(
-        new ConfigurationRequest(clusterName, "typeA", "v1", null, null));
+    cr.setDesiredConfig(Collections.singletonList(
+        new ConfigurationRequest(clusterName, "typeA", "v1", null, null)));
     controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
     Config config = cluster.getDesiredConfigByType("typeA");
     Assert.assertNull(config);
 
     // test empty map with no prior
-    cr.setDesiredConfig(
-        new ConfigurationRequest(clusterName, "typeA", "v1", new HashMap<String, String>(), new HashMap<String, Map<String,String>>()));
+    cr.setDesiredConfig(Collections.singletonList(
+        new ConfigurationRequest(clusterName, "typeA", "v1", new HashMap<String, String>(), new HashMap<String, Map<String,String>>())));
     controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
     config = cluster.getDesiredConfigByType("typeA");
     Assert.assertNotNull(config);
 
     // test empty properties on a new version
-    cr.setDesiredConfig(
-        new ConfigurationRequest(clusterName, "typeA", "v2", new HashMap<String, String>(), new HashMap<String, Map<String,String>>()));
+    cr.setDesiredConfig(Collections.singletonList(
+        new ConfigurationRequest(clusterName, "typeA", "v2", new HashMap<String, String>(), new HashMap<String, Map<String,String>>())));
     controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
     config = cluster.getDesiredConfigByType("typeA");
     Assert.assertNotNull(config);
@@ -10095,16 +10095,16 @@ public class AmbariManagementControllerTest {
     Map<String, Map<String, String>> attributesMap = new HashMap<String, Map<String,String>>();
     attributesMap.put("final", new HashMap<String, String>());
     attributesMap.get("final").put("c", "true");
-    cr.setDesiredConfig(
-        new ConfigurationRequest(clusterName, "typeA", "v3", map, attributesMap));
+    cr.setDesiredConfig(Collections.singletonList(
+        new ConfigurationRequest(clusterName, "typeA", "v3", map, attributesMap)));
     controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
     config = cluster.getDesiredConfigByType("typeA");
     Assert.assertNotNull(config);
     Assert.assertTrue(config.getProperties().containsKey("c"));
 
     // test reset to v2
-    cr.setDesiredConfig(
-        new ConfigurationRequest(clusterName, "typeA", "v2", new HashMap<String, String>(), new HashMap<String, Map<String,String>>()));
+    cr.setDesiredConfig(Collections.singletonList(
+        new ConfigurationRequest(clusterName, "typeA", "v2", new HashMap<String, String>(), new HashMap<String, Map<String,String>>())));
     controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
     config = cluster.getDesiredConfigByType("typeA");
     Assert.assertEquals("v2", config.getTag());
@@ -10112,11 +10112,11 @@ public class AmbariManagementControllerTest {
     Assert.assertEquals(Integer.valueOf(0), Integer.valueOf(config.getProperties().size()));
 
     // test v2, but with properties
-    cr.setDesiredConfig(
+    cr.setDesiredConfig(Collections.singletonList(
         new ConfigurationRequest(clusterName, "typeA", "v2", new HashMap<String, String>() {{ put("a", "b"); }},
             new HashMap<String, Map<String,String>>(){{put("final", new HashMap<String, String>(){{put("a", "true");}});
           }
-        }));
+        })));
     try {
       controller.updateClusters(Collections.singleton(cr), new HashMap<String, String>());
       Assert.fail("Expect failure when creating a config that exists");
@@ -10257,7 +10257,7 @@ public class AmbariManagementControllerTest {
 
     ConfigurationRequest cr1 = new ConfigurationRequest(clusterName, "hdfs-site", "version1", hdfsConfigs, hdfsConfigAttributes);
     ClusterRequest crReq1 = new ClusterRequest(null, clusterName, null, null);
-    crReq1.setDesiredConfig(cr1);
+    crReq1.setDesiredConfig(Collections.singletonList(cr1));
 
     controller.updateClusters(Collections.singleton(crReq1), null);
 
@@ -10340,7 +10340,7 @@ public class AmbariManagementControllerTest {
 
     ConfigurationRequest cr1 = new ConfigurationRequest(clusterName, "hdfs-site", "version1", hdfsConfigs, hdfsConfigAttributes);
     ClusterRequest crReq1 = new ClusterRequest(null, clusterName, null, null);
-    crReq1.setDesiredConfig(cr1);
+    crReq1.setDesiredConfig(Collections.singletonList(cr1));
 
     controller.updateClusters(Collections.singleton(crReq1), null);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
index e13c25e..6565219 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
@@ -86,7 +86,7 @@ public class RefreshYarnCapacitySchedulerReleaseConfigTest {
     // Start
     ClusterRequest cr = new ClusterRequest(cluster.getClusterId(), "c1", cluster.getDesiredStackVersion().getStackVersion(), null);
 
-    cr.setDesiredConfig(new ConfigurationRequest("c1","capacity-scheduler","version2",new HashMap<String, String>(), null));
+    cr.setDesiredConfig(Collections.singletonList(new ConfigurationRequest("c1","capacity-scheduler","version2",new HashMap<String, String>(), null)));
     
     controller.updateClusters(Collections.singleton(cr) , null);
     
@@ -106,7 +106,7 @@ public class RefreshYarnCapacitySchedulerReleaseConfigTest {
     // Start
     ClusterRequest cr = new ClusterRequest(cluster.getClusterId(), "c1", cluster.getDesiredStackVersion().getStackVersion(), null);
     
-    cr.setDesiredConfig(new ConfigurationRequest("c1","core-site","version2",new HashMap<String, String>(),null));
+    cr.setDesiredConfig(Collections.singletonList(new ConfigurationRequest("c1","core-site","version2",new HashMap<String, String>(),null)));
     
     controller.updateClusters(Collections.singleton(cr) , null);
     

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
index 7d51184..b5c50ff 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
@@ -517,13 +517,13 @@ public class ClusterResourceProviderTest {
     assertEquals(clusterName, ucr5.getClusterName());
     assertEquals(clusterName, ucr6.getClusterName());
     assertEquals(clusterName, ucr7.getClusterName());
-    ConfigurationRequest cr1 = ucr1.getDesiredConfig();
-    ConfigurationRequest cr2 = ucr2.getDesiredConfig();
-    ConfigurationRequest cr3 = ucr3.getDesiredConfig();
-    ConfigurationRequest cr4 = ucr4.getDesiredConfig();
-    ConfigurationRequest cr5 = ucr5.getDesiredConfig();
-    ConfigurationRequest cr6 = ucr6.getDesiredConfig();
-    ConfigurationRequest cr7 = ucr7.getDesiredConfig();
+    ConfigurationRequest cr1 = ucr1.getDesiredConfig().get(0);
+    ConfigurationRequest cr2 = ucr2.getDesiredConfig().get(0);
+    ConfigurationRequest cr3 = ucr3.getDesiredConfig().get(0);
+    ConfigurationRequest cr4 = ucr4.getDesiredConfig().get(0);
+    ConfigurationRequest cr5 = ucr5.getDesiredConfig().get(0);
+    ConfigurationRequest cr6 = ucr6.getDesiredConfig().get(0);
+    ConfigurationRequest cr7 = ucr7.getDesiredConfig().get(0);
     assertEquals("1", cr1.getVersionTag());
     assertEquals("1", cr2.getVersionTag());
     assertEquals("1", cr3.getVersionTag());
@@ -1718,12 +1718,12 @@ public class ClusterResourceProviderTest {
     assertEquals(clusterName, ucr4.getClusterName());
     assertEquals(clusterName, ucr5.getClusterName());
     assertEquals(clusterName, ucr6.getClusterName());
-    ConfigurationRequest cr1 = ucr1.getDesiredConfig();
-    ConfigurationRequest cr2 = ucr2.getDesiredConfig();
-    ConfigurationRequest cr3 = ucr3.getDesiredConfig();
-    ConfigurationRequest cr4 = ucr4.getDesiredConfig();
-    ConfigurationRequest cr5 = ucr5.getDesiredConfig();
-    ConfigurationRequest cr6 = ucr6.getDesiredConfig();
+    ConfigurationRequest cr1 = ucr1.getDesiredConfig().get(0);
+    ConfigurationRequest cr2 = ucr2.getDesiredConfig().get(0);
+    ConfigurationRequest cr3 = ucr3.getDesiredConfig().get(0);
+    ConfigurationRequest cr4 = ucr4.getDesiredConfig().get(0);
+    ConfigurationRequest cr5 = ucr5.getDesiredConfig().get(0);
+    ConfigurationRequest cr6 = ucr6.getDesiredConfig().get(0);
 
     assertEquals("1", cr1.getVersionTag());
     assertEquals("1", cr2.getVersionTag());
@@ -2413,13 +2413,13 @@ public class ClusterResourceProviderTest {
     assertEquals(clusterName, ucr5.getClusterName());
     assertEquals(clusterName, ucr6.getClusterName());
     assertEquals(clusterName, ucr7.getClusterName());
-    ConfigurationRequest cr1 = ucr1.getDesiredConfig();
-    ConfigurationRequest cr2 = ucr2.getDesiredConfig();
-    ConfigurationRequest cr3 = ucr3.getDesiredConfig();
-    ConfigurationRequest cr4 = ucr4.getDesiredConfig();
-    ConfigurationRequest cr5 = ucr5.getDesiredConfig();
-    ConfigurationRequest cr6 = ucr6.getDesiredConfig();
-    ConfigurationRequest cr7 = ucr7.getDesiredConfig();
+    ConfigurationRequest cr1 = ucr1.getDesiredConfig().get(0);
+    ConfigurationRequest cr2 = ucr2.getDesiredConfig().get(0);
+    ConfigurationRequest cr3 = ucr3.getDesiredConfig().get(0);
+    ConfigurationRequest cr4 = ucr4.getDesiredConfig().get(0);
+    ConfigurationRequest cr5 = ucr5.getDesiredConfig().get(0);
+    ConfigurationRequest cr6 = ucr6.getDesiredConfig().get(0);
+    ConfigurationRequest cr7 = ucr7.getDesiredConfig().get(0);
     assertEquals("1", cr1.getVersionTag());
     assertEquals("1", cr2.getVersionTag());
     assertEquals("1", cr3.getVersionTag());

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
index 94bd0c2..a11dc43 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
@@ -188,7 +188,7 @@ public class JMXHostProviderTest {
       ConfigurationRequest cr = new ConfigurationRequest(clusterName,
         "hdfs-site", "version1", configs, null);
       ClusterRequest crequest = new ClusterRequest(null, clusterName, null, null);
-      crequest.setDesiredConfig(cr);
+      crequest.setDesiredConfig(Collections.singletonList(cr));
       controller.updateClusters(Collections.singleton(crequest), new HashMap<String,String>());
       
     } else {
@@ -200,7 +200,7 @@ public class JMXHostProviderTest {
         "hdfs-site", "version2", configs, null);
       
       ClusterRequest crequest = new ClusterRequest(null, clusterName, null, null);
-      crequest.setDesiredConfig(cr);
+      crequest.setDesiredConfig(Collections.singletonList(cr));
       controller.updateClusters(Collections.singleton(crequest), new HashMap<String,String>());
     }
   }
@@ -272,7 +272,7 @@ public class JMXHostProviderTest {
       "hdfs-site", "versionN", configs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, clusterName, null, null);
-    crReq.setDesiredConfig(cr1);
+    crReq.setDesiredConfig(Collections.singletonList(cr1));
     controller.updateClusters(Collections.singleton(crReq), null);
     Cluster cluster = clusters.getCluster(clusterName);
     Assert.assertEquals("versionN", cluster.getDesiredConfigByType("hdfs-site")
@@ -280,7 +280,7 @@ public class JMXHostProviderTest {
 
     ConfigurationRequest cr2 = new ConfigurationRequest(clusterName,
       "yarn-site", "versionN", yarnConfigs, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
 
     Assert.assertEquals("versionN", cluster.getDesiredConfigByType("yarn-site")
@@ -400,7 +400,7 @@ public class JMXHostProviderTest {
       "yarn-site", "versionN+1", yarnConfigs, null);
 
     ClusterRequest crReq = new ClusterRequest(null, "c1", null, null);
-    crReq.setDesiredConfig(cr2);
+    crReq.setDesiredConfig(Collections.singletonList(cr2));
     controller.updateClusters(Collections.singleton(crReq), null);
     Assert.assertEquals("50030", providerModule.getPort("c1", "RESOURCEMANAGER"));
     Assert.assertEquals("11111", providerModule.getPort("c1", "NODEMANAGER"));

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
index ffd4358..73004ba 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
@@ -36,11 +36,11 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 public class ConfigHelperTest {
   private Clusters clusters;
@@ -97,7 +97,7 @@ public class ConfigHelperTest {
       new ClusterRequest(cluster.getClusterId(), clusterName,
         cluster.getDesiredStackVersion().getStackVersion(), null);
 
-    clusterRequest1.setDesiredConfig(cr);
+    clusterRequest1.setDesiredConfig(Collections.singletonList(cr));
     managementController.updateClusters(new HashSet<ClusterRequest>()
     {{ add(clusterRequest1); }}, null);
 
@@ -119,7 +119,7 @@ public class ConfigHelperTest {
       new ClusterRequest(cluster.getClusterId(), clusterName,
         cluster.getDesiredStackVersion().getStackVersion(), null);
 
-    clusterRequest2.setDesiredConfig(cr);
+    clusterRequest2.setDesiredConfig(Collections.singletonList(cr));
     managementController.updateClusters(new HashSet<ClusterRequest>()
     {{ add(clusterRequest2); }}, null);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
index 222924b..201702b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
@@ -354,7 +354,7 @@ public class ClusterTest {
     c1.addConfig(config2);
     c1.addConfig(config3);
     
-    c1.addDesiredConfig("_test", config1);
+    c1.addDesiredConfig("_test", Collections.singleton(config1));
     Config res = c1.getDesiredConfigByType("global");
     Assert.assertNotNull("Expected non-null config", res);
     Assert.assertEquals("true", res.getPropertiesAttributes().get("final").get("a"));
@@ -362,7 +362,7 @@ public class ClusterTest {
     res = c1.getDesiredConfigByType("core-site");
     Assert.assertNull("Expected null config", res);
     
-    c1.addDesiredConfig("_test", config2);
+    c1.addDesiredConfig("_test", Collections.singleton(config2));
     res = c1.getDesiredConfigByType("global");
     Assert.assertEquals("Expected version tag to be 'version2'", "version2", res.getTag());
     Assert.assertEquals("true", res.getPropertiesAttributes().get("final").get("x"));
@@ -387,15 +387,15 @@ public class ClusterTest {
     c1.addConfig(config3);
     
     try {
-      c1.addDesiredConfig(null, config1);
+      c1.addDesiredConfig(null, Collections.singleton(config1));
       fail("Cannot set a null user with config");
     }
     catch (Exception e) {
       // test failure
     }
     
-    c1.addDesiredConfig("_test1", config1);
-    c1.addDesiredConfig("_test3", config3);
+    c1.addDesiredConfig("_test1", Collections.singleton(config1));
+    c1.addDesiredConfig("_test3", Collections.singleton(config3));
     
     Map<String, DesiredConfig> desiredConfigs = c1.getDesiredConfigs();
     Assert.assertFalse("Expect desired config not contain 'mapred-site'", desiredConfigs.containsKey("mapred-site"));
@@ -409,10 +409,10 @@ public class ClusterTest {
     Assert.assertTrue("Expect no host-level overrides",
         (null == dc.getHostOverrides() || dc.getHostOverrides().size() == 0));
     
-    c1.addDesiredConfig("_test2", config2);
+    c1.addDesiredConfig("_test2", Collections.singleton(config2));
     Assert.assertEquals("_test2", c1.getDesiredConfigs().get(config2.getType()).getUser());
     
-    c1.addDesiredConfig("_test1", config1);
+    c1.addDesiredConfig("_test1", Collections.singleton(config1));
 
     // setup a host that also has a config override
     Host host = clusters.getHost("h1");
@@ -647,7 +647,7 @@ public class ClusterTest {
     c1.addConfig(config1);
     c1.addConfig(config2);
 
-    c1.addDesiredConfig("admin", config1);
+    c1.addDesiredConfig("admin", Collections.singleton(config1));
     List<ServiceConfigVersionResponse> serviceConfigVersions =
       c1.getServiceConfigVersions();
     Assert.assertNotNull(serviceConfigVersions);
@@ -663,7 +663,7 @@ public class ClusterTest {
     Assert.assertEquals("admin", mapredResponse.getUserName());
     Assert.assertEquals(Long.valueOf(1), mapredResponse.getVersion());
 
-    c1.addDesiredConfig("admin", config2);
+    c1.addDesiredConfig("admin", Collections.singleton(config2));
     serviceConfigVersions = c1.getServiceConfigVersions();
     Assert.assertNotNull(serviceConfigVersions);
     // created new ServiceConfigVersion
@@ -676,7 +676,7 @@ public class ClusterTest {
     Assert.assertEquals("admin", mapredResponse.getUserName());
 
     // Rollback , clonning version1 config, created new ServiceConfigVersion
-    c1.addDesiredConfig("admin", config1);
+    c1.addDesiredConfig("admin", Collections.singleton(config1));
     serviceConfigVersions = c1.getServiceConfigVersions();
     Assert.assertNotNull(serviceConfigVersions);
     // created new ServiceConfigVersion
@@ -688,4 +688,39 @@ public class ClusterTest {
     Assert.assertEquals("c1", mapredResponse.getClusterName());
     Assert.assertEquals("admin", mapredResponse.getUserName());
   }
+
+  @Test
+  public void testSingleServiceVersionForMultipleConfigs() {
+    Config config1 = configFactory.createNew(c1, "hdfs-site",
+      new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
+    config1.setTag("version1");
+
+    Config config2 = configFactory.createNew(c1, "core-site",
+      new HashMap<String, String>() {{ put("x", "y"); }}, new HashMap<String, Map<String,String>>());
+    config2.setTag("version2");
+
+    c1.addConfig(config1);
+    c1.addConfig(config2);
+
+    Set<Config> configs = new HashSet<Config>();
+    configs.add(config1);
+    configs.add(config2);
+
+    c1.addDesiredConfig("admin", configs);
+    List<ServiceConfigVersionResponse> serviceConfigVersions =
+      c1.getServiceConfigVersions();
+    Assert.assertNotNull(serviceConfigVersions);
+    // Single serviceConfigVersion for multiple configs
+    Assert.assertEquals(1, serviceConfigVersions.size());
+    Assert.assertEquals(Long.valueOf(1), serviceConfigVersions.get(0).getVersion());
+    Assert.assertEquals(2, c1.getDesiredConfigs().size());
+    Assert.assertEquals("version1", c1.getDesiredConfigByType("hdfs-site").getTag());
+    Assert.assertEquals("version2", c1.getDesiredConfigByType("core-site").getTag());
+
+    Map<String, ServiceConfigVersionResponse> activeServiceConfigVersions =
+      c1.getActiveServiceConfigVersions();
+    Assert.assertEquals(1, activeServiceConfigVersions.size());
+
+
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
index e794e01..2baa5c5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.state.cluster;
 import static org.junit.Assert.fail;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -330,7 +331,7 @@ public class ClustersTest {
     config2.persist();
     
     // cluster desired config
-    cluster.addDesiredConfig("_test", config1);
+    cluster.addDesiredConfig("_test", Collections.singleton(config1));
 
     clusters.addHost(h1);
     clusters.addHost(h2);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index c0bdaa2..5d85b0d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.state.svccomphost;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -1041,7 +1042,7 @@ public class ServiceComponentHostTest {
     config.setTag(tag);
     config.persist();
     cluster.addConfig(config);
-    cluster.addDesiredConfig("user", config);
+    cluster.addDesiredConfig("user", Collections.singleton(config));
   }
   
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/2cceee2e/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalogTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalogTest.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalogTest.java
index f8d16c8..b0c8fd9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalogTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalogTest.java
@@ -147,7 +147,7 @@ public class UpgradeCatalogTest {
     cr.setVersionTag("version1");
     cr.setProperties(properties);
 
-    cl.setDesiredConfig(cr);
+    cl.setDesiredConfig(Collections.singletonList(cr));
 
     controller.updateClusters(new HashSet<ClusterRequest>() {{ add(cl); }}, null);