You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2013/02/27 17:40:34 UTC

svn commit: r1450837 - in /incubator/ambari/trunk: ./ ambari-server/src/main/java/org/apache/ambari/server/controller/ ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ ambari-server/src/main/java/org/apache/ambari/server/orm/en...

Author: tbeerbower
Date: Wed Feb 27 16:40:34 2013
New Revision: 1450837

URL: http://svn.apache.org/r1450837
Log:
AMBARI-1502. Add the ability to assign configuration to a cluster.

Added:
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntityPK.java
Modified:
    incubator/ambari/trunk/CHANGES.txt
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseProvider.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
    incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
    incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-DROP.sql
    incubator/ambari/trunk/ambari-server/src/main/resources/META-INF/persistence.xml
    incubator/ambari/trunk/ambari-server/src/main/resources/properties.json
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java

Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Wed Feb 27 16:40:34 2013
@@ -67,6 +67,8 @@ Trunk (unreleased changes):
 
  IMPROVEMENTS
 
+ AMBARI-1502. Add the ability to assign configuration to a cluster. (Nate Cole via tbeerbower)
+
  AMBARI-1505. Hosts page: add filtering by host status. (yusaku)
 
  AMBARI-1496. Make all service properties reconfigurable. (jaimin)

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java Wed Feb 27 16:40:34 2013
@@ -19,11 +19,29 @@
 package org.apache.ambari.server.controller;
 
 import java.net.InetAddress;
-import java.util.*;
+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.inject.persist.Transactional;
-import org.apache.ambari.server.*;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterNotFoundException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.HostNotFoundException;
+import org.apache.ambari.server.ObjectNotFoundException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.ServiceComponentHostNotFoundException;
+import org.apache.ambari.server.ServiceComponentNotFoundException;
+import org.apache.ambari.server.ServiceNotFoundException;
+import org.apache.ambari.server.StackNotFoundException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestStatus;
@@ -836,7 +854,7 @@ public class AmbariManagementControllerI
     if (null == request.getClusterName() || request.getClusterName().isEmpty()
         || null == request.getType() || request.getType().isEmpty()
         || null == request.getVersionTag() || request.getVersionTag().isEmpty()
-        || null == request.getConfigs() || request.getConfigs().isEmpty()) {
+        || null == request.getProperties() || request.getProperties().isEmpty()) {
       throw new IllegalArgumentException("Invalid Arguments,"
           + " clustername, config type, config version and configs should not"
           + " be null or empty");
@@ -844,7 +862,7 @@ public class AmbariManagementControllerI
 
     Cluster cluster = clusters.getCluster(request.getClusterName());
 
-    Map<String, Config> configs = cluster.getDesiredConfigsByType(
+    Map<String, Config> configs = cluster.getConfigsByType(
         request.getType());
     if (null == configs) {
       configs = new HashMap<String, Config>();
@@ -857,12 +875,12 @@ public class AmbariManagementControllerI
     }
 
     config = configFactory.createNew (cluster, request.getType(),
-        request.getConfigs());
+        request.getProperties());
     config.setVersionTag(request.getVersionTag());
 
     config.persist();
 
-    cluster.addDesiredConfig(config);
+    cluster.addConfig(config);
   }
 
   @Override
@@ -1328,7 +1346,7 @@ public class AmbariManagementControllerI
 
     // !!! if only one, then we need full properties
     if (null != request.getType() && null != request.getVersionTag()) {
-      Config config = cluster.getDesiredConfig(request.getType(),
+      Config config = cluster.getConfig(request.getType(),
           request.getVersionTag());
       if (null != config) {
         ConfigurationResponse response = new ConfigurationResponse(
@@ -1339,7 +1357,7 @@ public class AmbariManagementControllerI
     }
     else {
       if (null != request.getType()) {
-        Map<String, Config> configs = cluster.getDesiredConfigsByType(
+        Map<String, Config> configs = cluster.getConfigsByType(
             request.getType());
 
         if (null != configs) {
@@ -1386,14 +1404,32 @@ public class AmbariManagementControllerI
     }
 
     final Cluster c = clusters.getCluster(request.getClusterName());
-    clusters.mapHostsToCluster(request.getHostNames(),
-        request.getClusterName());
+    if (null != request.getHostNames()) {
+      clusters.mapHostsToCluster(request.getHostNames(),
+          request.getClusterName());
+    }
 
     if (!request.getStackVersion().equals(
         c.getDesiredStackVersion().getStackId())) {
       throw new IllegalArgumentException("Update of desired stack version"
           + " not supported");
     }
+    
+    // set or create configuration mapping (and optionally create the map of properties)
+    if (null != request.getDesiredConfig()) {
+      ConfigurationRequest cr = request.getDesiredConfig();
+      
+      if (null != cr.getProperties() && cr.getProperties().size() > 0) {
+        cr.setClusterName(c.getClusterName());
+        createConfiguration(cr);
+      }
+      
+      Config baseConfig = c.getConfig(cr.getType(), cr.getVersionTag());
+      if (null != baseConfig)
+        c.addDesiredConfig(baseConfig);
+      
+    }
+    
 
     return null;
   }
@@ -1948,7 +1984,7 @@ public class AmbariManagementControllerI
                 + ", configType=" + entry.getKey()
                 + ", configTag=" + entry.getValue());
           }
-          Config config = cluster.getDesiredConfig(
+          Config config = cluster.getConfig(
               entry.getKey(), entry.getValue());
           if (null == config) {
             // throw error for invalid config
@@ -2105,7 +2141,7 @@ public class AmbariManagementControllerI
         Map<String, Config> updated = new HashMap<String, Config>();
 
         for (Entry<String,String> entry : request.getConfigVersions().entrySet()) {
-          Config config = cluster.getDesiredConfig(entry.getKey(), entry.getValue());
+          Config config = cluster.getConfig(entry.getKey(), entry.getValue());
           updated.put(config.getType(), config);
         }
 
@@ -2243,7 +2279,7 @@ public class AmbariManagementControllerI
 
         for (Entry<String,String> entry :
             request.getConfigVersions().entrySet()) {
-          Config config = cluster.getDesiredConfig(
+          Config config = cluster.getConfig(
               entry.getKey(), entry.getValue());
           if (null == config) {
             // throw error for invalid config
@@ -2374,7 +2410,7 @@ public class AmbariManagementControllerI
 
         for (Entry<String,String> entry :
           request.getConfigVersions().entrySet()) {
-          Config config = cluster.getDesiredConfig(
+          Config config = cluster.getConfig(
               entry.getKey(), entry.getValue());
           updated.put(config.getType(), config);
         }
@@ -2563,7 +2599,7 @@ public class AmbariManagementControllerI
 
         for (Entry<String,String> entry :
             request.getConfigVersions().entrySet()) {
-          Config config = cluster.getDesiredConfig(
+          Config config = cluster.getConfig(
               entry.getKey(), entry.getValue());
           if (null == config) {
             throw new AmbariException("Trying to update servicecomponenthost"
@@ -2664,7 +2700,7 @@ public class AmbariManagementControllerI
         Map<String, Config> updated = new HashMap<String, Config>();
 
         for (Entry<String,String> entry : request.getConfigVersions().entrySet()) {
-          Config config = cluster.getDesiredConfig(
+          Config config = cluster.getConfig(
               entry.getKey(), entry.getValue());
           updated.put(config.getType(), config);
 
@@ -3202,7 +3238,7 @@ public class AmbariManagementControllerI
           + " when decommissioning datanodes");
     }
 
-    Config config = clusters.getCluster(clusterName).getDesiredConfig(
+    Config config = clusters.getCluster(clusterName).getConfig(
         "hdfs-exclude-file", excludeFileTag);
 
     Map<String, Map<String, String>> configurations =

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java Wed Feb 27 16:40:34 2013
@@ -32,6 +32,8 @@ public class ClusterRequest {
   private String stackVersion; // for CREATE/UPDATE
 
   Set<String> hostNames; // CREATE/UPDATE
+  
+  private ConfigurationRequest config = null;
 
   public ClusterRequest(Long clusterId, String clusterName,
       String stackVersion, Set<String> hostNames) {
@@ -41,7 +43,7 @@ public class ClusterRequest {
     this.stackVersion = stackVersion;
     this.hostNames = hostNames;
   }
-
+  
   /**
    * @return the clusterId
    */
@@ -91,6 +93,22 @@ public class ClusterRequest {
   public void setHostNames(Set<String> hostNames) {
     this.hostNames = hostNames;
   }
+  
+  /**
+   * Sets the config request (if any)
+   * @param configRequest
+   */
+  public void setDesiredConfig(ConfigurationRequest configRequest) {
+    config = configRequest;
+  }
+  
+  /**
+   * Gets any configuration-based request (if any).
+   * @return the configuration request, or <code>null</code> if none is set.
+   */
+  public ConfigurationRequest getDesiredConfig() {
+    return config;
+  }
 
   @Override
   public String toString() {
@@ -112,5 +130,6 @@ public class ClusterRequest {
     sb.append("] }");
     return sb.toString();
   }
+  
 
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationRequest.java Wed Feb 27 16:40:34 2013
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.controller;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -34,11 +35,15 @@ public class ConfigurationRequest {
 
   private Map<String, String> configs;
 
+  public ConfigurationRequest() {
+    configs = new HashMap<String, String>();
+  }
+  
   public ConfigurationRequest(String clusterName,
                               String type,
                               String tag,
                               Map<String, String> configs) {
-    super();
+
     this.clusterName = clusterName;
     this.configs = configs;
     this.type = type;
@@ -77,14 +82,14 @@ public class ConfigurationRequest {
   /**
    * @return the configs
    */
-  public Map<String, String> getConfigs() {
+  public Map<String, String> getProperties() {
     return configs;
   }
 
   /**
    * @param configs the configs to set
    */
-  public void setConfigs(Map<String, String> configs) {
+  public void setProperties(Map<String, String> configs) {
     this.configs = configs;
   }
 

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseProvider.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseProvider.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseProvider.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseProvider.java Wed Feb 27 16:40:34 2013
@@ -74,6 +74,27 @@ public abstract class BaseProvider {
 
 
   // ----- BaseProvider --------------------------------------------------
+  /**
+   * Checks for properties ids that are not recognized to the provider.
+   * @param base  the base set of properties
+   * @param configCategory  the config category that would have a <code>desired_config</code> element.
+   * @return the set of properties that are NOT known to the provider
+   */
+  protected Set<String> checkConfigPropertyIds(Set<String> base, String configCategory) {
+    
+    if (0 == base.size())
+      return base;
+    
+    Set<String> unsupported = new HashSet<String>();
+    
+    for (String propertyId : base)
+    {
+      if (!propertyId.startsWith (configCategory + ".desired_config"))
+        unsupported.add(propertyId);
+    }
+    
+    return unsupported;    
+  }
 
   public Set<String> checkPropertyIds(Set<String> propertyIds) {
     if (!this.propertyIds.containsAll(propertyIds)) {

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java Wed Feb 27 16:40:34 2013
@@ -17,10 +17,18 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ClusterRequest;
 import org.apache.ambari.server.controller.ClusterResponse;
+import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -34,12 +42,6 @@ import org.apache.ambari.server.controll
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * Resource provider for cluster resources.
  */
@@ -137,6 +139,7 @@ class ClusterResourceProvider extends Ab
   public RequestStatus updateResources(Request request, Predicate predicate)
       throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
+    
     for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
       final ClusterRequest clusterRequest = getRequest(propertyMap);
 
@@ -184,10 +187,43 @@ class ClusterResourceProvider extends Ab
    * @return the cluster request object
    */
   private ClusterRequest getRequest(Map<String, Object> properties) {
-    return new ClusterRequest(
+    ClusterRequest cr = new ClusterRequest(
         (Long) properties.get(CLUSTER_ID_PROPERTY_ID),
         (String) properties.get(CLUSTER_NAME_PROPERTY_ID),
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         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("Clusters.desired_config")) {
+        ConfigurationRequest config = (null == cr.getDesiredConfig()) ? new ConfigurationRequest() : cr.getDesiredConfig();
+        cr.setDesiredConfig(config);
+        
+        if (propName.equals ("type"))
+          config.setType(entry.getValue().toString());
+        else if (propName.equals ("tag"))
+          config.setVersionTag(entry.getValue().toString());
+        else if (absCategory.endsWith(".properties")) {
+          config.getProperties().put(propName, entry.getValue().toString());
+        }
+        
+      }
+    }
+    
+    return cr;
+  }
+  
+  /**
+   * {@inheritDoc}  Overridden to support configuration.
+   */
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    Set<String> baseUnsupported = super.checkPropertyIds(propertyIds);
+    
+    return checkConfigPropertyIds(baseUnsupported, "Clusters");
   }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java Wed Feb 27 16:40:34 2013
@@ -236,6 +236,16 @@ class HostResourceProvider extends Abstr
   protected Set<String> getPKPropertyIds() {
     return pkPropertyIds;
   }
+  
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+      Set<String> baseUnsupported = super.checkPropertyIds(propertyIds);
+      
+      return checkConfigPropertyIds(baseUnsupported, "Hosts");
+  }
 
   /**
    * Get a host request object from a map of property values.

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java?rev=1450837&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java Wed Feb 27 16:40:34 2013
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Entity that maps to a cluster config mapping.
+ */
+@IdClass(ClusterConfigMappingEntityPK.class)
+@Table(name = "clusterconfigmapping", schema = "ambari", catalog = "")
+@Entity
+public class ClusterConfigMappingEntity {
+
+  private Long clusterId;
+  private String typeName;
+  private String versionTag;
+  private int selectedInd = 0;
+  private Long createTimestamp;
+  private ClusterEntity clusterEntity;
+  
+  @Column(name = "cluster_id", insertable = false, updatable = false, nullable = false)
+  @Id
+  public Long getClusterId() {
+    return clusterId;
+  }
+  
+  public void setClusterId(Long id) {
+    clusterId = id;
+  }
+  
+  @Column(name = "type_name", insertable = true, updatable = false, nullable = false)
+  @Id
+  public String getType() {
+    return typeName;
+  }
+  public void setType(String type) {
+    typeName = type;
+  }
+
+  @Column(name = "create_timestamp", insertable = true, updatable = false, nullable = false)
+  @Id
+  public Long getCreateTimestamp() {
+    return createTimestamp;
+  }
+
+  public void setCreateTimestamp(Long timestamp) {
+    createTimestamp = timestamp;
+  }  
+  
+  @Column(name = "version_tag", insertable = true, updatable = false, nullable = false)
+  public String getVersion() {
+    return versionTag;
+  }
+  
+  public void setVersion(String version) {
+    versionTag = version;
+  }
+ 
+
+  @Column(name = "selected", insertable = true, updatable = true, nullable = false)
+  public int isSelected() {
+    return selectedInd;
+  }
+
+  public void setSelected(int selected) {
+    selectedInd = selected;
+  }
+  
+  @ManyToOne
+  @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false)
+  public ClusterEntity getClusterEntity() {
+    return clusterEntity;
+  }
+
+  public void setClusterEntity(ClusterEntity entity) {
+    clusterEntity = entity;
+  }
+  
+  
+}

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntityPK.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntityPK.java?rev=1450837&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntityPK.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntityPK.java Wed Feb 27 16:40:34 2013
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+
+/**
+ * PK class for cluster config mappings.
+ */
+public class ClusterConfigMappingEntityPK {
+  private Long clusterId;
+  private String typeName;
+  private Long createTimestamp;
+  
+  @Id
+  @Column(name = "cluster_id", nullable = false, insertable = true, updatable = true, length = 10)
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  @Id
+  @Column(name = "type_name", nullable = false, insertable = true, updatable = false)
+  public String getType() {
+    return typeName;
+  }
+
+  public void setType(String type) {
+    typeName = type;
+  }
+
+  @Id
+  @Column(name = "create_timestamp", nullable = false, insertable = true, updatable = false)
+  public Long getCreateTimestamp() {
+    return createTimestamp;
+  }
+
+  public void setCreateTimestamp(Long timestamp) {
+    createTimestamp = timestamp;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ClusterConfigMappingEntityPK that = (ClusterConfigMappingEntityPK) o;
+
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
+    if (typeName != null ? !typeName.equals(that.typeName) : that.typeName != null) return false;
+    if (createTimestamp != null ? !createTimestamp.equals (that.createTimestamp) : that.createTimestamp != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = clusterId !=null ? clusterId.intValue() : 0;
+    result = 31 * result + (typeName != null ? typeName.hashCode() : 0);
+    result = 31 * result + createTimestamp.intValue();
+    return result;
+  }
+}

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java Wed Feb 27 16:40:34 2013
@@ -177,4 +177,16 @@ public class ClusterEntity {
   public void setClusterConfigEntities(Collection<ClusterConfigEntity> entities) {
     configEntities = entities;
   }
+  
+  private Collection<ClusterConfigMappingEntity> configMappingEntities;
+  @OneToMany(mappedBy = "clusterEntity", cascade = CascadeType.ALL)
+  public Collection<ClusterConfigMappingEntity> getConfigMappingEntities() {
+    return configMappingEntities;
+  }
+  
+  public void setConfigMappingEntities(Collection<ClusterConfigMappingEntity> entities) {
+    configMappingEntities = entities;
+  }
+  
+
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java Wed Feb 27 16:40:34 2013
@@ -79,7 +79,8 @@ public interface Cluster {
    * @param stackVersion
    */
   public void setDesiredStackVersion(StackId stackVersion);
-
+  
+  
   /**
    * Get current stack version
    * @return
@@ -93,31 +94,51 @@ public interface Cluster {
   public void setCurrentStackVersion(StackId stackVersion) throws AmbariException;
 
   /**
-   * Get desired config based on the given config type name
-   * @param configType
-   * @return
+   * Gets all configs that match the specified type.  Result is not the
+   * DESIRED configuration for a cluster.
+   * @param configType  the config type to return
+   * @return  a map of configuration objects that have been set for the given type 
    */
-  public Map<String, Config> getDesiredConfigsByType(String configType);
+  public Map<String, Config> getConfigsByType(String configType);
 
   /**
-   * Get the desired config of given type and version
-   * @param configType
-   * @param versionTag
-   * @return
+   * Gets the specific config that matches the specified type and tag.  This not
+   * necessarily a DESIRED configuration that applies to a cluster.
+   * @param configType  the config type to find
+   * @param versionTag  the config version to find
+   * @return  a {@link Config} object, or <code>null</code> if the specific type
+   *          and version have not been set.
    */
-  public Config getDesiredConfig(String configType, String versionTag);
+  public Config getConfig(String configType, String versionTag);
 
   /**
-   * Add the desired config for the cluster
-   * @param config
+   * Sets a specific config.  NOTE:  This is not a DESIRED configuration that
+   * applies to a cluster.
+   * @param config  the config instance to add
    */
-  public void addDesiredConfig(Config config);
+  public void addConfig(Config config);
 
   /**
-   * Get all configs associated with the cluster
-   * @return
+   * Gets all configurations defined for a cluster.
+   * @return  the collection of all configs that have been defined.
    */
   public Collection<Config> getAllConfigs();
+  
+  /**
+   * Adds and sets a DESIRED configuration to be applied to a cluster.  There
+   * can be only one selected config per type.
+   * @param config  the {@link Config} object to set as desired
+   */
+  public void addDesiredConfig(Config config);
+  
+  /**
+   * Gets the desired (and selected) config by type.
+   * @param configType  the type of configuration
+   * @return  the {@link Config} instance, or <code>null</code> if the type has
+   * not been set.
+   */
+  public Config getDesiredConfigByType(String configType);
+  
 
   /**
    * Creates a cluster response based on the current cluster definition

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java Wed Feb 27 16:40:34 2013
@@ -286,7 +286,7 @@ public class ServiceComponentImpl implem
   public synchronized Map<String, Config> getDesiredConfigs() {
     Map<String, Config> map = new HashMap<String, Config>();
     for (Entry<String, String> entry : desiredConfigs.entrySet()) {
-      Config config = service.getCluster().getDesiredConfig(entry.getKey(), entry.getValue());
+      Config config = service.getCluster().getConfig(entry.getKey(), entry.getValue());
       if (null != config) {
         map.put(entry.getKey(), config);
       }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java Wed Feb 27 16:40:34 2013
@@ -239,7 +239,7 @@ public class ServiceImpl implements Serv
   public synchronized Map<String, Config> getDesiredConfigs() {
     Map<String, Config> map = new HashMap<String, Config>();
     for (Entry<String, String> entry : desiredConfigs.entrySet()) {
-      Config config = cluster.getDesiredConfig(entry.getKey(), entry.getValue());
+      Config config = cluster.getConfig(entry.getKey(), entry.getValue());
       if (null != config) {
         map.put(entry.getKey(), config);
       } else {

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java Wed Feb 27 16:40:34 2013
@@ -39,6 +39,7 @@ import org.apache.ambari.server.controll
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterStateDAO;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
+import org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
@@ -77,7 +78,7 @@ public class ClusterImpl implements Clus
   /**
    * [ Config Type -> [ Config Version Tag -> Config ] ]
    */
-  private Map<String, Map<String, Config>> configs;
+  private Map<String, Map<String, Config>> allConfigs;
 
   /**
    * [ ServiceName -> [ ServiceComponentName -> [ HostName -> [ ... ] ] ] ]
@@ -124,17 +125,17 @@ public class ClusterImpl implements Clus
         List<ServiceComponentHost>>();
     this.desiredStackVersion = gson.fromJson(
         clusterEntity.getDesiredStackVersion(), StackId.class);
-    configs = new HashMap<String, Map<String, Config>>();
+    allConfigs = new HashMap<String, Map<String, Config>>();
     if (!clusterEntity.getClusterConfigEntities().isEmpty()) {
       for (ClusterConfigEntity entity : clusterEntity.getClusterConfigEntities()) {
 
-        if (!configs.containsKey(entity.getType())) {
-          configs.put(entity.getType(), new HashMap<String, Config>());
+        if (!allConfigs.containsKey(entity.getType())) {
+          allConfigs.put(entity.getType(), new HashMap<String, Config>());
         }
 
         Config config = configFactory.createExisting(this, entity);
 
-        configs.get(entity.getType()).put(entity.getTag(), config);
+        allConfigs.get(entity.getType()).put(entity.getTag(), config);
       }
     }
   }
@@ -501,34 +502,34 @@ public class ClusterImpl implements Clus
   }
 
   @Override
-  public Map<String, Config> getDesiredConfigsByType(String configType) {
+  public Map<String, Config> getConfigsByType(String configType) {
     readWriteLock.writeLock().lock();
     try {
-      if (!configs.containsKey(configType))
+      if (!allConfigs.containsKey(configType))
         return null;
 
-      return Collections.unmodifiableMap(configs.get(configType));
+      return Collections.unmodifiableMap(allConfigs.get(configType));
     } finally {
       readWriteLock.writeLock().unlock();
     }
   }
 
   @Override
-  public Config getDesiredConfig(String configType, String versionTag) {
+  public Config getConfig(String configType, String versionTag) {
     readWriteLock.readLock().lock();
     try {
-      if (!configs.containsKey(configType)
-          || !configs.get(configType).containsKey(versionTag)) {
+      if (!allConfigs.containsKey(configType)
+          || !allConfigs.get(configType).containsKey(versionTag)) {
         return null;
       }
-      return configs.get(configType).get(versionTag);
+      return allConfigs.get(configType).get(versionTag);
     } finally {
       readWriteLock.readLock().unlock();
     }
   }
 
   @Override
-  public void addDesiredConfig(Config config) {
+  public void addConfig(Config config) {
     readWriteLock.writeLock().lock();
     try {
       if (config.getType() == null
@@ -537,21 +538,21 @@ public class ClusterImpl implements Clus
           || config.getVersionTag().isEmpty()) {
         // TODO throw error
       }
-      if (!configs.containsKey(config.getType())) {
-        configs.put(config.getType(), new HashMap<String, Config>());
+      if (!allConfigs.containsKey(config.getType())) {
+        allConfigs.put(config.getType(), new HashMap<String, Config>());
       }
 
-      configs.get(config.getType()).put(config.getVersionTag(), config);
+      allConfigs.get(config.getType()).put(config.getVersionTag(), config);
     } finally {
       readWriteLock.writeLock().unlock();
     }
   }
-
+  
   public Collection<Config> getAllConfigs() {
     readWriteLock.readLock().lock();
     try {
       List<Config> list = new ArrayList<Config>();
-      for (Entry<String, Map<String, Config>> entry : configs.entrySet()) {
+      for (Entry<String, Map<String, Config>> entry : allConfigs.entrySet()) {
         for (Config config : entry.getValue().values()) {
           list.add(config);
         }
@@ -689,7 +690,7 @@ public class ClusterImpl implements Clus
     try {
       deleteAllServices();
       removeEntities();
-      configs.clear();
+      allConfigs.clear();
     } finally {
       readWriteLock.writeLock().unlock();
     }
@@ -699,4 +700,45 @@ public class ClusterImpl implements Clus
   protected void removeEntities() throws AmbariException {
     clusterDAO.removeByPK(getClusterId());
   }
+  
+  @Override
+  public void addDesiredConfig(Config config) {
+    
+    Config currentDesired = getDesiredConfigByType(config.getType());
+    
+    // do not set if it is already the current
+    if (null != currentDesired && currentDesired.getVersionTag().equals(config.getVersionTag())) {
+      return;
+    }
+
+    for (ClusterConfigMappingEntity e : clusterEntity.getConfigMappingEntities()) {
+      if (e.isSelected() > 0 && e.getType().equals(config.getType()))
+        e.setSelected(0);
+    }
+    
+    ClusterConfigMappingEntity entity = new ClusterConfigMappingEntity();
+    entity.setClusterEntity(clusterEntity);
+    entity.setClusterId(clusterEntity.getClusterId());
+    entity.setCreateTimestamp(Long.valueOf (new java.util.Date().getTime()));
+    entity.setSelected(1);
+    entity.setType(config.getType());
+    entity.setVersion(config.getVersionTag());
+    clusterEntity.getConfigMappingEntities().add(entity);
+    
+    clusterDAO.merge(clusterEntity);
+    
+  }
+  
+  @Override
+  public Config getDesiredConfigByType(String configType) {
+    
+    for (ClusterConfigMappingEntity e : clusterEntity.getConfigMappingEntities()) {
+      if (e.isSelected() > 0 && e.getType().equals(configType)) {
+        return getConfig(e.getType(), e.getVersion());
+      }
+    }    
+    
+    return null;
+  }
+  
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java Wed Feb 27 16:40:34 2013
@@ -782,7 +782,7 @@ public class ServiceComponentHostImpl im
       Map<String, Config> map = new HashMap<String, Config>();
       Cluster cluster = clusters.getClusterById(getClusterId());
       for (Entry<String, String> entry : configs.entrySet()) {
-        Config config = cluster.getDesiredConfig(
+        Config config = cluster.getConfig(
             entry.getKey(), entry.getValue());
         if (null != config) {
           map.put(entry.getKey(), config);
@@ -957,7 +957,7 @@ public class ServiceComponentHostImpl im
     try {
       readLock.lock();
       for (Entry<String, String> entry : desiredConfigs.entrySet()) {
-        Config config = clusters.getClusterById(getClusterId()).getDesiredConfig(
+        Config config = clusters.getClusterById(getClusterId()).getConfig(
             entry.getKey(), entry.getValue());
         if (null != config) {
           map.put(entry.getKey(), config);

Modified: incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql Wed Feb 27 16:40:34 2013
@@ -32,6 +32,9 @@ CREATE TABLE ambari.clusterconfig (versi
 
 GRANT ALL PRIVILEGES ON TABLE ambari.clusterconfig TO :username;
 
+CREATE TABLE ambari.clusterconfigmapping (cluster_id bigint NOT NULL, type_name VARCHAR(255) NOT NULL, version_tag VARCHAR(255) NOT NULL, create_timestamp BIGINT NOT NULL, selected INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (cluster_id, type_name, create_timestamp));
+GRANT ALL PRIVILEGES ON TABLE ambari.clusterconfigmapping TO :username;
+
 CREATE TABLE ambari.clusterservices (service_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, service_enabled INTEGER NOT NULL, PRIMARY KEY (service_name, cluster_id));
 
 GRANT ALL PRIVILEGES ON TABLE ambari.clusterservices TO :username;
@@ -110,6 +113,7 @@ GRANT ALL PRIVILEGES ON TABLE ambari.key
 
 ALTER TABLE ambari.clusterconfig ADD CONSTRAINT FK_clusterconfig_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
 ALTER TABLE ambari.clusterservices ADD CONSTRAINT FK_clusterservices_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
+ALTER TABLE ambari.clusterconfigmapping ADD CONSTRAINT FK_clusterconfigmapping_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
 ALTER TABLE ambari.clusterstate ADD CONSTRAINT FK_clusterstate_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
 ALTER TABLE ambari.componentconfigmapping ADD CONSTRAINT FK_componentconfigmapping_config_tag FOREIGN KEY (config_tag, config_type, cluster_id) REFERENCES ambari.clusterconfig (version_tag, type_name, cluster_id);
 ALTER TABLE ambari.componentconfigmapping ADD CONSTRAINT FK_componentconfigmapping_component_name FOREIGN KEY (component_name, cluster_id, service_name) REFERENCES ambari.servicecomponentdesiredstate (component_name, cluster_id, service_name);

Modified: incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-DROP.sql
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-DROP.sql?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-DROP.sql (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/Ambari-DDL-Postgres-DROP.sql Wed Feb 27 16:40:34 2013
@@ -19,6 +19,7 @@
 ALTER TABLE ambari.clusterconfig DROP CONSTRAINT FK_clusterconfig_cluster_id;
 ALTER TABLE ambari.clusterservices DROP CONSTRAINT FK_clusterservices_cluster_id;
 ALTER TABLE ambari.clusterstate DROP CONSTRAINT FK_clusterstate_cluster_id;
+ALTER TABLE ambari.clusterconfigmapping DROP CONSTRAINT FK_clusterconfigmapping_cluster_id;
 ALTER TABLE ambari.componentconfigmapping DROP CONSTRAINT FK_componentconfigmapping_component_name;
 ALTER TABLE ambari.hostcomponentconfigmapping DROP CONSTRAINT FK_hostcomponentconfigmapping_cluster_id;
 ALTER TABLE ambari.hostcomponentdesiredconfigmapping DROP CONSTRAINT FK_hostcomponentdesiredconfigmapping_config_tag;
@@ -42,9 +43,7 @@ ALTER TABLE ambari.user_roles DROP CONST
 ALTER TABLE ambari.user_roles DROP CONSTRAINT FK_user_roles_role_name;
 DROP TABLE ambari.clusters CASCADE;
 DROP TABLE ambari.clusterservices CASCADE;
-DROP TABLE ambari.clusterstate CASCADE;
-DROP TABLE ambari.componentconfigmapping CASCADE;
-DROP TABLE ambari.hostcomponentconfigmapping CASCADE;
+DROP TABLE ambari.clusterstate CASCADE; DROP TABLE ambari.componentconfigmapping CASCADE; DROP TABLE ambari.hostcomponentconfigmapping CASCADE;
 DROP TABLE ambari.hostcomponentdesiredconfigmapping CASCADE;
 DROP TABLE ambari.hostcomponentdesiredstate CASCADE;
 DROP TABLE ambari.hostcomponentstate CASCADE;
@@ -61,6 +60,7 @@ DROP TABLE ambari.role_success_criteria 
 DROP TABLE ambari.stage CASCADE;
 DROP TABLE ambari.ClusterHostMapping CASCADE;
 DROP TABLE ambari.clusterconfig CASCADE;
+DROP TABLE ambari.clusterconfigmapping CASCADE;
 DROP TABLE ambari.user_roles CASCADE;
 DROP TABLE ambari.key_value_store CASCADE;
 DROP SEQUENCE ambari.host_role_command_task_id_seq;

Modified: incubator/ambari/trunk/ambari-server/src/main/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/META-INF/persistence.xml?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/META-INF/persistence.xml (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/META-INF/persistence.xml Wed Feb 27 16:40:34 2013
@@ -35,6 +35,7 @@
     <class>org.apache.ambari.server.orm.entities.RoleSuccessCriteriaEntity</class>
     <class>org.apache.ambari.server.orm.entities.StageEntity</class>
     <class>org.apache.ambari.server.orm.entities.KeyValueEntity</class>
+    <class>org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity</class>
 
     <properties>
       <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/ambari" />
@@ -66,7 +67,7 @@
     <class>org.apache.ambari.server.orm.entities.RoleSuccessCriteriaEntity</class>
     <class>org.apache.ambari.server.orm.entities.StageEntity</class>
     <class>org.apache.ambari.server.orm.entities.KeyValueEntity</class>
-
+    <class>org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity</class>
 
     <properties>
       <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:myDB;create=true" />

Modified: incubator/ambari/trunk/ambari-server/src/main/resources/properties.json
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/properties.json?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/properties.json (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/properties.json Wed Feb 27 16:40:34 2013
@@ -4,6 +4,7 @@
         "Clusters/cluster_name",
         "Clusters/version",
         "Clusters/state",
+        "Clusters/desired_config",
         "_"
     ],
     "Service":[

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java Wed Feb 27 16:40:34 2013
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -34,8 +33,17 @@ import java.util.Set;
 
 import junit.framework.Assert;
 
-import org.apache.ambari.server.*;
-import org.apache.ambari.server.actionmanager.*;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterNotFoundException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.actionmanager.ActionDBAccessor;
+import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
+import org.apache.ambari.server.actionmanager.HostRoleCommand;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
@@ -67,8 +75,6 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
 
-import javax.xml.bind.JAXBException;
-
 public class AmbariManagementControllerTest {
 
   private static final Logger LOG =
@@ -1271,9 +1277,9 @@ public class AmbariManagementControllerT
     c2.setVersionTag("v1");
     c3.setVersionTag("v1");
 
-    cluster.addDesiredConfig(c1);
-    cluster.addDesiredConfig(c2);
-    cluster.addDesiredConfig(c3);
+    cluster.addConfig(c1);
+    cluster.addConfig(c2);
+    cluster.addConfig(c3);
     c1.persist();
     c2.persist();
     c3.persist();

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java Wed Feb 27 16:40:34 2013
@@ -255,7 +255,7 @@ public class AbstractResourceProviderTes
           eq(((ConfigurationRequest) o).getClusterName(), getClusterName()) &&
           eq(((ConfigurationRequest) o).getType(), getType()) &&
           eq(((ConfigurationRequest) o).getVersionTag(), getVersionTag()) &&
-          eq(((ConfigurationRequest) o).getConfigs(), getConfigs());
+          eq(((ConfigurationRequest) o).getProperties(), getProperties());
 
     }
 
@@ -399,7 +399,7 @@ public class AbstractResourceProviderTes
           eq(((ConfigurationRequest) request).getClusterName(), configurationRequest.getClusterName()) &&
           eq(((ConfigurationRequest) request).getType(), configurationRequest.getType()) &&
           eq(((ConfigurationRequest) request).getVersionTag(), configurationRequest.getVersionTag()) &&
-          eq(((ConfigurationRequest) request).getConfigs(), configurationRequest.getConfigs());
+          eq(((ConfigurationRequest) request).getProperties(), configurationRequest.getProperties());
     }
 
     @Override

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java Wed Feb 27 16:40:34 2013
@@ -18,6 +18,18 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ClusterRequest;
 import org.apache.ambari.server.controller.ClusterResponse;
@@ -32,18 +44,6 @@ import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-
 /**
  * ClusterResourceProvider tests.
  */
@@ -251,6 +251,53 @@ public class ClusterResourceProviderTest
     // verify
     verify(managementController, response);
   }
+  
+  @Test
+  public void testUpdateWithConfiguration() throws Exception {
+
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+
+    Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
+    nameResponse.add(new ClusterResponse(100L, "Cluster100", null, null));
+
+    // set expectations
+    expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(nameResponse).once();
+    expect(managementController.updateCluster(EasyMock.anyObject(ClusterRequest.class))).andReturn(response).once();
+
+    // replay
+    replay(managementController, response);
+
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    properties.put(ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID, "Cluster100");
+    properties.put(PropertyHelper.getPropertyId("Clusters.desired_config", "type"), "global");
+    properties.put(PropertyHelper.getPropertyId("Clusters.desired_config", "tag"), "version1");
+    properties.put(PropertyHelper.getPropertyId("Clusters.desired_config.properties", "a"), "b");
+    properties.put(PropertyHelper.getPropertyId("Clusters.desired_config.properties", "x"), "y");
+
+    propertySet.add(properties);
+
+    // create the request
+    Request request = PropertyHelper.getUpdateRequest(properties);
+    
+    Predicate  predicate = new PredicateBuilder().property(
+        ClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").toPredicate();
+    
+    ResourceProvider provider = AbstractResourceProvider.getResourceProvider(
+        Resource.Type.Cluster,
+        PropertyHelper.getPropertyIds(Resource.Type.Cluster),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.Cluster),
+        managementController);
+    
+    provider.updateResources(request, predicate);
+
+    // verify
+    verify(managementController, response);
+
+  }
 
   @Test
   public void testDeleteResources() throws Exception{

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java Wed Feb 27 16:40:34 2013
@@ -20,13 +20,15 @@ package org.apache.ambari.server.state.c
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import static org.mockito.Mockito.*;
 
 import javax.persistence.EntityManager;
 
@@ -49,6 +51,8 @@ import org.apache.ambari.server.orm.enti
 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.ConfigFactory;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.Service;
@@ -82,6 +86,7 @@ public class ClusterTest {
   private ServiceComponentFactory serviceComponentFactory;
   private ServiceComponentHostFactory serviceComponentHostFactory;
   private AmbariMetaInfo metaInfo;
+  private ConfigFactory configFactory;
 
   @Before
   public void setup() throws Exception {
@@ -93,6 +98,7 @@ public class ClusterTest {
         ServiceComponentFactory.class);
     serviceComponentHostFactory = injector.getInstance(
         ServiceComponentHostFactory.class);
+    configFactory = injector.getInstance(ConfigFactory.class);
     metaInfo = injector.getInstance(AmbariMetaInfo.class);
     metaInfo.init();
     clusters.addCluster("c1");
@@ -286,10 +292,33 @@ public class ClusterTest {
 
   @Test
   public void testGetAndSetConfigs() {
-    // FIXME write unit tests
-    // public Map<String, Config> getConfigsByType(String configType);
-    // public Config getConfig(String configType, String versionTag);
-    // public void addConfig(Config config);
+    Config config1 = configFactory.createNew(c1, "global",
+        new HashMap<String, String>() {{ put("a", "b"); }});
+    config1.setVersionTag("version1");
+    
+    Config config2 = configFactory.createNew(c1, "global",
+        new HashMap<String, String>() {{ put("x", "y"); }});
+    config2.setVersionTag("version2");
+    
+    Config config3 = configFactory.createNew(c1, "core-site",
+        new HashMap<String, String>() {{ put("x", "y"); }});
+    config3.setVersionTag("version2");    
+    
+    c1.addConfig(config1);
+    c1.addConfig(config2);
+    c1.addConfig(config3);
+    
+    c1.addDesiredConfig(config1);
+    Config res = c1.getDesiredConfigByType("global");
+    Assert.assertNotNull("Expected non-null config", res);
+    
+    res = c1.getDesiredConfigByType("core-site");
+    Assert.assertNull("Expected null config", res);
+    
+    c1.addDesiredConfig(config2);
+    res = c1.getDesiredConfigByType("global");
+    Assert.assertEquals("Expected version tag to be 'version2'", "version2", res.getVersionTag());
+    
   }
   
   public ClusterEntity createDummyData() {

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java?rev=1450837&r1=1450836&r2=1450837&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java Wed Feb 27 16:40:34 2013
@@ -157,11 +157,11 @@ public class ServiceComponentHostTest {
     Map<String, String> configs = new HashMap<String, String>();
 
     Cluster c = clusters.getCluster("C1");
-    if (c.getDesiredConfig("time", "" + timestamp) == null) {
+    if (c.getConfig("time", "" + timestamp) == null) {
       Config config = configFactory.createNew (c, "time",
           new HashMap<String, String>());
       config.setVersionTag("" + timestamp);
-      c.addDesiredConfig(config);
+      c.addConfig(config);
       config.persist();
     }