You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2013/03/05 17:52:49 UTC

svn commit: r1452892 - 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/da...

Author: ncole
Date: Tue Mar  5 16:52:48 2013
New Revision: 1452892

URL: http://svn.apache.org/r1452892
Log:
AMBARI-1511.  Add ability to override configurations at the host level

Added:
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAO.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntity.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntityPK.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/DesiredConfig.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAOTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/DesiredConfigTest.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/ConfigurationRequest.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.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/state/Host.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.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/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/host/HostTest.java

Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Tue Mar  5 16:52:48 2013
@@ -12,6 +12,8 @@ Trunk (unreleased changes):
 
  NEW FEATURES
 
+ AMBARI-1511. Add ability to override configurations at the host level (ncole)
+
  AMBARI-1550. Modify existing puppet manifests to allow installing/configuring 
  multiple masters. (swagle)
 

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -1179,6 +1179,8 @@ public class AmbariManagementControllerI
         if (clusters.getClustersForHost(h.getHostName()).contains(cluster)) {
           HostResponse r = h.convertToResponse();
           r.setClusterName(clusterName);
+          r.setDesiredConfigs(h.getDesiredConfigs(cluster.getClusterId()));
+          
           response.add(r);
         } else if (hostName != null) {
           throw new HostNotFoundException(clusterName, hostName);
@@ -2681,6 +2683,29 @@ public class AmbariManagementControllerI
       if (null != request.getPublicHostName()) {
         h.setPublicHostName(request.getPublicHostName());
       }
+      
+      if (null != request.getClusterName() && null != request.getDesiredConfig()) {
+        Cluster c = clusters.getCluster(request.getClusterName());
+        
+        if (clusters.getHostsForCluster(request.getClusterName()).containsKey(h.getHostName())) {
+          
+          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)
+            h.addDesiredConfig(c.getClusterId(), cr.getServiceName(), baseConfig);
+          
+        }
+        
+        
+
+        
+      }
 
       //todo: if attempt was made to update a property other than those
       //todo: that are allowed above, should throw exception

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -28,12 +28,10 @@ import java.util.Map;
 public class ConfigurationRequest {
 
   private String clusterName;
-
   private String type;
-
   private String tag;
-
   private Map<String, String> configs;
+  private String serviceName;
 
   public ConfigurationRequest() {
     configs = new HashMap<String, String>();
@@ -107,4 +105,20 @@ public class ConfigurationRequest {
   public void setClusterName(String clusterName) {
     this.clusterName = clusterName;
   }
+
+  /**
+   * Sets the service name (for host-level overrides)
+   * @param name the service name
+   */
+  public void setServiceName(String name) {
+    serviceName = name;
+  }
+  
+  /**
+   * Gets the service name.
+   * @return the service name
+   */
+  public String getServiceName() {
+    return serviceName;
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java Tue Mar  5 16:52:48 2013
@@ -29,6 +29,7 @@ public class HostRequest {
   private String clusterName; // CREATE/UPDATE
   private Map<String, String> hostAttributes; // CREATE/UPDATE
   private String rackInfo;
+  private ConfigurationRequest desiredConfig; // UPDATE
 
   public HostRequest(String hostname, String clusterName, Map<String, String> hostAttributes) {
     this.hostname = hostname;
@@ -75,6 +76,14 @@ public class HostRequest {
   public void setPublicHostName(String name) {
     publicHostname = name;
   }
+  
+  public void setDesiredConfig(ConfigurationRequest request) {
+    desiredConfig = request;
+  }
+  
+  public ConfigurationRequest getDesiredConfig() {
+    return desiredConfig;
+  }
 
   public String toString() {
     StringBuilder sb = new StringBuilder();

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java Tue Mar  5 16:52:48 2013
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.ambari.server.agent.AgentEnv;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.state.AgentVersion;
+import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.HostHealthStatus;
 
 public class HostResponse {
@@ -124,6 +125,8 @@ public class HostResponse {
    */
   private String hostState;
 
+  private Map<String, DesiredConfig> desiredConfigs;
+
   public HostResponse(String hostname, String clusterName,
                       String ipv4, String ipv6, int cpuCount, String osArch, String osType,
                       String osInfo, long availableMemBytes, long totalMemBytes,
@@ -455,5 +458,15 @@ public class HostResponse {
     lastAgentEnv = agentEnv;
   }
   
+  /**
+   * @param desired
+   */
+  public void setDesiredConfigs(Map<String, DesiredConfig> desired) {
+    desiredConfigs = desired;
+  }
+  
+  public Map<String, DesiredConfig> getDesiredConfigs() {
+    return desiredConfigs;
+  }
 
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java Tue Mar  5 16:52:48 2013
@@ -23,12 +23,14 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Map.Entry;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.DuplicateResourceException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.predicate.BasePredicate;
 import org.apache.ambari.server.controller.spi.*;
@@ -370,6 +372,40 @@ public abstract class AbstractResourcePr
         throw new IllegalArgumentException("Unknown type " + type);
     }
   }
+  
+  /**
+   * Helper method to get a configuration request, if one exists.
+   * @param parentCategory  the parent category name.  Checks for a property
+   *    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) {
+    
+    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")) {
+        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("service_name"))
+          config.setServiceName(entry.getValue().toString());
+        else if (absCategory.endsWith(".properties")) {
+          config.getProperties().put(propName, entry.getValue().toString());
+        }
+      }
+    }
+
+    return config;
+  }
 
 
   // ----- Inner interface ---------------------------------------------------

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -192,27 +192,12 @@ class ClusterResourceProvider extends Ab
         (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());
-        }
-        
-      }
-    }
+    ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
+    
+    if (null != configRequest)
+      cr.setDesiredConfig(configRequest);
     
     return cr;
   }

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -24,9 +24,18 @@ import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.HostRequest;
 import org.apache.ambari.server.controller.HostResponse;
-import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 
@@ -70,6 +79,8 @@ class HostResourceProvider extends Abstr
       PropertyHelper.getPropertyId("Hosts", "host_state");
   protected static final String HOST_LAST_AGENT_ENV_PROPERTY_ID =
       PropertyHelper.getPropertyId("Hosts", "last_agent_env");
+  protected static final String HOST_DESIRED_CONFIGS_PROPERTY_ID = 
+      PropertyHelper.getPropertyId("Hosts", "desired_configs");
 
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{
@@ -181,6 +192,8 @@ class HostResourceProvider extends Abstr
           response.getDisksInfo(), requestedIds);
       setResourceProperty(resource, HOST_STATE_PROPERTY_ID,
           response.getHostState(), requestedIds);
+      setResourceProperty(resource, HOST_DESIRED_CONFIGS_PROPERTY_ID,
+          response.getDesiredConfigs(), requestedIds);
       resources.add(resource);
     }
     return resources;
@@ -266,6 +279,10 @@ class HostResourceProvider extends Abstr
         null);
     hostRequest.setPublicHostName((String) properties.get(HOST_PUBLIC_NAME_PROPERTY_ID));
     hostRequest.setRackInfo((String) properties.get(HOST_RACK_INFO_PROPERTY_ID));
+    
+    ConfigurationRequest cr = getConfigurationRequest("Hosts", properties);
+    
+    hostRequest.setDesiredConfig(cr);
 
     return hostRequest;
   }

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAO.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAO.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAO.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAO.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.dao;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.orm.entities.HostConfigMappingEntity;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.persist.Transactional;
+
+/**
+ * Used for host configuration mapping operations.
+ */
+public class HostConfigMappingDAO {
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
+  
+  @Transactional
+  public void create(HostConfigMappingEntity entity) {
+    entityManagerProvider.get().persist(entity);
+  }
+
+  @Transactional
+  public HostConfigMappingEntity merge(HostConfigMappingEntity entity) {
+    return entityManagerProvider.get().merge(entity);
+  }
+
+  public List<HostConfigMappingEntity> findByType(long clusterId, String hostName, String type) {
+    TypedQuery<HostConfigMappingEntity> query = entityManagerProvider.get().createQuery(
+      "SELECT entity FROM HostConfigMappingEntity entity " +
+      "WHERE entity.clusterId = ?1 AND entity.hostName = ?2 AND entity.type = ?3",
+      HostConfigMappingEntity.class);        
+    
+    return daoUtils.selectList(query, Long.valueOf(clusterId), hostName, type);
+  }
+
+  public HostConfigMappingEntity findSelectedByType(long clusterId,
+      String hostName, String type) {
+
+    TypedQuery<HostConfigMappingEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT entity FROM HostConfigMappingEntity entity " +
+        "WHERE entity.clusterId = ?1 AND entity.hostName = ?2 " +
+            "AND entity.type = ?3 " +
+            "AND entity.selected > 0",
+        HostConfigMappingEntity.class);
+    
+    return daoUtils.selectSingle(query, Long.valueOf(clusterId), hostName, type);
+  }
+
+  public List<HostConfigMappingEntity> findSelected(long clusterId, String hostName) {
+    TypedQuery<HostConfigMappingEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT entity FROM HostConfigMappingEntity entity " +
+        "WHERE entity.clusterId = ?1 AND entity.hostName = ?2 " +
+            "AND entity.selected > 0",
+        HostConfigMappingEntity.class);
+    
+    return daoUtils.selectList(query, Long.valueOf(clusterId), hostName);
+  }
+  
+}

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntity.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntity.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntity.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntity.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,111 @@
+/**
+ * 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.Table;
+
+/**
+ * Entity that represents a host config mapping and override.
+ */
+@Table(name = "hostconfigmapping", schema = "ambari", catalog = "")
+@Entity
+@IdClass(HostConfigMappingEntityPK.class)
+public class HostConfigMappingEntity {
+  private Long clusterId;
+  private String hostName;
+  private String typeName;
+  private String versionTag;
+  private String serviceName;
+  private Long createTimestamp;
+  private int selectedInd = 0;
+  
+  @Column(name = "cluster_id", insertable = true, updatable = false, nullable = false)
+  @Id
+  public Long getClusterId() {
+    return clusterId;
+  }
+  
+  public void setClusterId(Long id) {
+    clusterId = id;
+  }
+  
+  @Column(name = "host_name", insertable = true, updatable = false, nullable = false)
+  @Id
+  public String getHostName() {
+    return hostName;
+  }
+  
+  public void setHostName(String name) {
+    hostName = name;
+  }
+  
+  @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;
+  }  
+  
+  
+  @Column(name = "service_name", insertable = true, updatable = true)
+  public String getServiceName() {
+    return serviceName;
+  }
+  
+  public void setServiceName(String name) {
+    serviceName = name;
+  }
+  
+}

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntityPK.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntityPK.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntityPK.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostConfigMappingEntityPK.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,100 @@
+/**
+ * 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 host config mappings.
+ *
+ */
+public class HostConfigMappingEntityPK {
+  private Long clusterId;
+  private String hostName;
+  private String typeName;
+  private Long createTimestamp;
+
+  @Column(name = "cluster_id", nullable = false, insertable = true, updatable = true, length = 10)
+  @Id
+  public Long getClusterId() {
+    return clusterId;
+  }
+  
+  public void setClusterId(Long id) {
+    clusterId = id;
+  }
+  
+  @Column(name = "host_name", insertable = true, updatable = true, nullable = false)
+  @Id
+  public String getHostName() {
+    return hostName;
+  }
+  
+  public void setHostName(String name) {
+    hostName = name;
+  }
+  
+  @Column(name = "type_name", insertable = true, updatable = true, nullable = false)
+  @Id
+  public String getType() {
+    return typeName;
+  }
+  
+  public void setType(String type) {
+    typeName = type;
+  }
+  
+  @Column(name = "create_timestamp", insertable = true, updatable = true, nullable = false)
+  @Id
+  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;
+
+    HostConfigMappingEntityPK that = (HostConfigMappingEntityPK) o;
+
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
+    if (hostName != null ? !hostName.equals(that.hostName) : that.hostName != 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 + (hostName != null ? hostName.hashCode() : 0);
+    result = 31 * result + createTimestamp.intValue();
+    return result;
+  }  
+  
+  
+}

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/DesiredConfig.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/DesiredConfig.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/DesiredConfig.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/DesiredConfig.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+/**
+ * Class that holds information about a desired config and is suitable for output
+ * in a web service response.
+ */
+public class DesiredConfig {
+
+  private String versionTag;
+  private String serviceName;
+  
+  
+  public void setVersion(String version) {
+    versionTag = version;
+  }
+  
+  @JsonProperty("tag")
+  public String getVersion() {
+    return versionTag;
+  }
+
+  /**
+   * Gets the service name (if any) for the desired config.
+   * @return the service name
+   */
+  @JsonSerialize(include = Inclusion.NON_NULL)
+  @JsonProperty("service_name")
+  public String getServiceName() {
+    return serviceName;
+  }  
+  
+  /**
+   * Sets the service name (if any) for the desired config.
+   * @param name
+   */
+  public void setServiceName(String name) {
+    serviceName = name;
+  }
+  
+
+  
+ 
+}

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java Tue Mar  5 16:52:48 2013
@@ -271,4 +271,19 @@ public interface Host {
   void refresh();
 
   void importHostInfo(HostInfo hostInfo);
+
+  /**
+   * Adds a desired configuration to the host instance.
+   * @param clusterId the cluster id that the config applies to
+   * @param serviceName the name of the service that is the parent.  Supply
+   *        <code>null</code> if the override applies to the cluster definition.
+   * @param config the configuration object
+   */
+  public void addDesiredConfig(long clusterId, String serviceName, Config config);
+  
+  /**
+   * Gets all the selected configurations for the host.
+   * return a map of type-to-{@link DesiredConfig} instances.
+   */
+  public Map<String, DesiredConfig> getDesiredConfigs(long clusterId);
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java Tue Mar  5 16:52:48 2013
@@ -20,37 +20,51 @@
 package org.apache.ambari.server.state.host;
 
 import java.lang.reflect.Type;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.assistedinject.Assisted;
-import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.AgentEnv;
+import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.HostInfo;
 import org.apache.ambari.server.controller.HostResponse;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
+import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostStateDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.HostConfigMappingEntity;
+import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostStateEntity;
-import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.AgentVersion;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.HostEvent;
+import org.apache.ambari.server.state.HostEventType;
+import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
+import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.SingleArcTransition;
 import org.apache.ambari.server.state.fsm.StateMachine;
 import org.apache.ambari.server.state.fsm.StateMachineFactory;
-import org.apache.ambari.server.orm.dao.HostDAO;
-import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.persist.Transactional;
+
 public class HostImpl implements Host {
 
   private static final Log LOG = LogFactory.getLog(HostImpl.class);
@@ -72,6 +86,7 @@ public class HostImpl implements Host {
   private HostStateDAO hostStateDAO;
   private ClusterDAO clusterDAO;
   private Clusters clusters;
+  private HostConfigMappingDAO hostConfigMappingDAO;
 
   private long lastHeartbeatTime = 0L;
   private AgentEnv lastAgentEnv = null;
@@ -198,6 +213,7 @@ public class HostImpl implements Host {
     this.gson = injector.getInstance(Gson.class);
     this.clusterDAO = injector.getInstance(ClusterDAO.class);
     this.clusters = injector.getInstance(Clusters.class);
+    this.hostConfigMappingDAO = injector.getInstance(HostConfigMappingDAO.class);
 
     hostStateEntity = hostEntity.getHostStateEntity();
     if (hostStateEntity == null) {
@@ -1019,4 +1035,64 @@ public class HostImpl implements Host {
       hostStateDAO.merge(hostStateEntity);
     }
   }
+  
+  @Override
+  @Transactional
+  public void addDesiredConfig(long clusterId, String serviceName, Config config) {
+    
+    HostConfigMappingEntity exist = getDesiredConfigEntity(clusterId, config.getType());
+    if (null != exist && exist.getVersion().equals(config.getVersionTag())) {
+      return;
+    }
+    
+    writeLock.lock();      
+    
+    try {
+      // set all old mappings for this type to empty
+      for (HostConfigMappingEntity e : hostConfigMappingDAO.findByType(clusterId,
+          hostEntity.getHostName(), config.getType())) {
+        e.setSelected(0);
+        hostConfigMappingDAO.merge(e);
+      }
+      
+      HostConfigMappingEntity entity = new HostConfigMappingEntity();
+      entity.setClusterId(Long.valueOf(clusterId));
+      entity.setCreateTimestamp(Long.valueOf(new Date().getTime()));
+      entity.setHostName(hostEntity.getHostName());
+      entity.setSelected(1);
+      entity.setServiceName(serviceName);
+      entity.setType(config.getType());
+      entity.setVersion(config.getVersionTag());
+      
+      hostConfigMappingDAO.create(entity);
+    }
+    finally {
+      writeLock.unlock();
+    }
+    
+    hostDAO.merge(hostEntity);
+  }
+  
+  @Override
+  public Map<String, DesiredConfig> getDesiredConfigs(long clusterId) {
+    Map<String, DesiredConfig> map = new HashMap<String, DesiredConfig>();
+    
+    for (HostConfigMappingEntity e : hostConfigMappingDAO.findSelected(
+        clusterId, hostEntity.getHostName())) {
+      
+      DesiredConfig dc = new DesiredConfig();
+      dc.setVersion(e.getVersion());
+      dc.setServiceName(e.getServiceName());
+      
+      map.put(e.getType(), dc);
+      
+    }
+    return map;
+  }
+  
+  private HostConfigMappingEntity getDesiredConfigEntity(long clusterId, String type) {
+    return hostConfigMappingDAO.findSelectedByType(clusterId,
+        hostEntity.getHostName(), type);
+  }
+      
 }

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -33,6 +33,7 @@ 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));
@@ -111,6 +112,10 @@ GRANT ALL PRIVILEGES ON TABLE ambari.use
 CREATE TABLE ambari.key_value_store ("key" VARCHAR(255), "value" VARCHAR, PRIMARY KEY("key"));
 GRANT ALL PRIVILEGES ON TABLE ambari.key_value_store TO :username;
 
+CREATE TABLE ambari.hostconfigmapping (cluster_id bigint NOT NULL, host_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, version_tag VARCHAR(255) NOT NULL, service_name VARCHAR(255), create_timestamp BIGINT NOT NULL, selected INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (cluster_id, host_name, type_name, create_timestamp));
+
+GRANT ALL PRIVILEGES ON TABLE ambari.hostconfigmapping TO :username;
+
 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);
@@ -139,6 +144,8 @@ ALTER TABLE ambari.ClusterHostMapping AD
 ALTER TABLE ambari.ClusterHostMapping ADD CONSTRAINT FK_ClusterHostMapping_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
 ALTER TABLE ambari.user_roles ADD CONSTRAINT FK_user_roles_user_id FOREIGN KEY (user_id) REFERENCES ambari.users (user_id);
 ALTER TABLE ambari.user_roles ADD CONSTRAINT FK_user_roles_role_name FOREIGN KEY (role_name) REFERENCES ambari.roles (role_name);
+ALTER TABLE ambari.hostconfigmapping ADD CONSTRAINT FK_hostconfigmapping_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
+ALTER TABLE ambari.hostconfigmapping ADD CONSTRAINT FK_hostconfigmapping_host_name FOREIGN KEY (host_name) REFERENCES ambari.hosts (host_name);
 
 CREATE SEQUENCE ambari.host_role_command_task_id_seq START WITH 1;
 

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -29,6 +29,8 @@ ALTER TABLE ambari.hostcomponentdesireds
 ALTER TABLE ambari.hostcomponentstate DROP CONSTRAINT FK_hostcomponentstate_component_name;
 ALTER TABLE ambari.hostcomponentstate DROP CONSTRAINT FK_hostcomponentstate_host_name;
 ALTER TABLE ambari.hoststate DROP CONSTRAINT FK_hoststate_host_name;
+ALTER TABLE ambari.hostconfigmapping DROP CONSTRAINT FK_hostconfigmapping_cluster_id;
+ALTER TABLE ambari.hostconfigmapping DROP CONSTRAINT FK_hostconfigmapping_host_name;
 ALTER TABLE ambari.servicecomponentdesiredstate DROP CONSTRAINT FK_servicecomponentdesiredstate_service_name;
 ALTER TABLE ambari.serviceconfigmapping DROP CONSTRAINT FK_serviceconfigmapping_service_name;
 ALTER TABLE ambari.servicedesiredstate DROP CONSTRAINT FK_servicedesiredstate_service_name;
@@ -49,6 +51,7 @@ DROP TABLE ambari.hostcomponentdesiredst
 DROP TABLE ambari.hostcomponentstate CASCADE;
 DROP TABLE ambari.hosts CASCADE;
 DROP TABLE ambari.hoststate CASCADE;
+DROP TABLE ambari.hostconfigmapping CASCADE;
 DROP TABLE ambari.servicecomponentdesiredstate CASCADE;
 DROP TABLE ambari.serviceconfigmapping CASCADE;
 DROP TABLE ambari.servicedesiredstate CASCADE;

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=1452892&r1=1452891&r2=1452892&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 Tue Mar  5 16:52:48 2013
@@ -36,6 +36,7 @@
     <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>
+    <class>org.apache.ambari.server.orm.entities.HostConfigMappingEntity</class>
 
     <properties>
       <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/ambari" />
@@ -68,6 +69,7 @@
     <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>
+    <class>org.apache.ambari.server.orm.entities.HostConfigMappingEntity</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=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/properties.json (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/properties.json Tue Mar  5 16:52:48 2013
@@ -35,6 +35,7 @@
         "Hosts/host_health_report",
         "Hosts/public_host_name",
         "Hosts/host_state",
+        "Hosts/desired_configs",
         "_"
     ],
     "Component":[

Modified: incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql (original)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql Tue Mar  5 16:52:48 2013
@@ -19,3 +19,12 @@
 
 ALTER TABLE ambari.clusterstate
   ADD COLUMN current_stack_version VARCHAR(255) NOT NULL;
+
+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;
+ALTER TABLE ambari.clusterconfigmapping ADD CONSTRAINT FK_clusterconfigmapping_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
+
+CREATE TABLE ambari.hostconfigmapping (cluster_id bigint NOT NULL, host_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, version_tag VARCHAR(255) NOT NULL, service_name VARCHAR(255), create_timestamp BIGINT NOT NULL, selected INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (cluster_id, host_name, type_name, create_timestamp));
+GRANT ALL PRIVILEGES ON TABLE ambari.hostconfigmapping TO :username;
+ALTER TABLE ambari.hostconfigmapping ADD CONSTRAINT FK_hostconfigmapping_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);
+ALTER TABLE ambari.hostconfigmapping ADD CONSTRAINT FK_hostconfigmapping_host_name FOREIGN KEY (host_name) REFERENCES ambari.hosts (host_name);

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java Tue Mar  5 16:52:48 2013
@@ -148,6 +148,63 @@ public class HostResourceProviderTest {
     // verify
     verify(managementController);
   }
+  
+  @Test
+  public void testUpdateDesiredConfig() throws Exception {
+    Resource.Type type = Resource.Type.Host;
+
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+
+    HostResponse hr = new HostResponse("Host100", "Cluster100",
+        "", "", 2, "", "", "", 100000L, 200000L, null, 10L,
+        0L, "rack info", null, null,
+        new HostHealthStatus(HostHealthStatus.HealthStatus.HEALTHY, "HEALTHY"), "HEALTHY");
+    
+    Set<HostResponse> hostResponseSet = new HashSet<HostResponse>();
+    hostResponseSet.add(hr);
+
+    // set expectations
+    expect(managementController.getHosts(
+        AbstractResourceProviderTest.Matcher.getHostRequestSet("Host100", "Cluster100", null))).
+        andReturn(hostResponseSet);
+    managementController.updateHosts(EasyMock.<Set<HostRequest>>anyObject());
+
+    // replay
+    replay(managementController, response);
+    
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    properties.put(HostResourceProvider.HOST_CLUSTER_NAME_PROPERTY_ID, "Cluster100");
+    properties.put(HostResourceProvider.HOST_NAME_PROPERTY_ID, "Host100");
+    
+    properties.put(PropertyHelper.getPropertyId("Hosts.desired_config", "type"), "global");
+    properties.put(PropertyHelper.getPropertyId("Hosts.desired_config", "tag"), "version1");
+    properties.put(PropertyHelper.getPropertyId("Hosts.desired_config.properties", "a"), "b");
+    properties.put(PropertyHelper.getPropertyId("Hosts.desired_config.properties", "x"), "y");
+
+    propertySet.add(properties);
+
+    // create the request
+    Request request = PropertyHelper.getUpdateRequest(properties);
+    
+    Predicate  predicate = new PredicateBuilder().property(HostResourceProvider.HOST_CLUSTER_NAME_PROPERTY_ID).
+        equals("Cluster100").
+        and().property(HostResourceProvider.HOST_NAME_PROPERTY_ID).equals("Host100").toPredicate();
+    
+    ResourceProvider provider = AbstractResourceProvider.getResourceProvider(
+        Resource.Type.Host,
+        PropertyHelper.getPropertyIds(Resource.Type.Host),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.Host),
+        managementController);
+    
+    provider.updateResources(request, predicate);
+    
+    // verify
+    verify(managementController, response);    
+  }
 
   @Test
   public void testUpdateResources() throws Exception {

Added: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAOTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAOTest.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAOTest.java (added)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostConfigMappingDAOTest.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
+import org.apache.ambari.server.orm.entities.HostConfigMappingEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+
+/**
+ * Tests host config mapping DAO and Entities
+ */
+public class HostConfigMappingDAOTest {
+
+  private Injector injector;
+  private HostConfigMappingDAO hostConfigMappingDAO;
+  
+  @Before
+   public void setup() throws AmbariException{
+    injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+    
+    hostConfigMappingDAO = injector.getInstance(HostConfigMappingDAO.class);
+  }
+
+  @After
+  public void teardown() throws AmbariException {
+    injector.getInstance(PersistService.class).stop();
+  }
+  
+  private HostConfigMappingEntity createEntity(long clusterId, String host, String type, String version) throws Exception {
+    HostConfigMappingEntity entity = new HostConfigMappingEntity();
+    entity.setClusterId(Long.valueOf(clusterId));
+    entity.setCreateTimestamp(Long.valueOf(new Date().getTime()));
+    entity.setHostName(host);
+    entity.setSelected(1);
+    entity.setType(type);
+    entity.setVersion(version);
+    
+    hostConfigMappingDAO.create(entity);
+    
+    return entity;
+  }
+  
+  @Test
+  public void testCreate() throws Exception {
+    createEntity(1L, "h1", "global", "v1");
+  }
+  
+
+  @Test
+  public void testFindByType() throws Exception {
+    HostConfigMappingEntity source = createEntity(1L, "h1", "global", "v1");
+    
+    List<HostConfigMappingEntity> target = hostConfigMappingDAO.findByType(1L, "h1", "global");
+
+    Assert.assertEquals("Expected one result", 1, target.size());
+    Assert.assertEquals("Expected version 'v1'", source.getVersion(), target.get(0).getVersion());
+  }
+  
+  @Test
+  public void testMerge() throws Exception {
+    HostConfigMappingEntity source = createEntity(1L, "h1", "global", "v1");
+    
+    List<HostConfigMappingEntity> target = hostConfigMappingDAO.findByType(1L, "h1", "global");
+
+    Assert.assertEquals("Expected one result", 1, target.size());
+    Assert.assertEquals("Expected version 'v1'", source.getVersion(), target.get(0).getVersion());
+    Assert.assertEquals("Expected selected flag 1", 1, target.get(0).isSelected());
+    
+    HostConfigMappingEntity toChange = target.get(0);
+    
+    toChange.setSelected(0);
+    
+    hostConfigMappingDAO.merge(toChange);
+    
+    target = hostConfigMappingDAO.findByType(1L, "h1", "global");
+
+    Assert.assertEquals("Expected one result", 1, target.size());
+    Assert.assertEquals("Expected version 'v1'", source.getVersion(), target.get(0).getVersion());
+    Assert.assertEquals("Expected selected flag 0", 0, target.get(0).isSelected());    
+  }
+  
+  @Test
+  public void testFindSelected() throws Exception {
+    createEntity(1L, "h1", "global", "version1");
+    HostConfigMappingEntity entity2 = createEntity(1L, "h1", "core-site", "version1");
+    
+    List<HostConfigMappingEntity> targets = hostConfigMappingDAO.findSelected(1L, "h1");
+    Assert.assertEquals("Expected two entities", 2, targets.size());
+    
+    entity2.setSelected(0);
+    hostConfigMappingDAO.merge(entity2);
+    
+    createEntity(1L, "h1", "core-site", "version2");
+
+    targets = hostConfigMappingDAO.findSelected(1L, "h1");
+    Assert.assertEquals("Expected two entities", 2, targets.size());
+  }
+  
+  @Test
+  public void testFindSelectedByType() throws Exception {
+    HostConfigMappingEntity entity1 = createEntity(1L, "h1", "global", "version1");
+    
+    HostConfigMappingEntity target = hostConfigMappingDAO.findSelectedByType(1L, "h1", "core-site");
+    Assert.assertNull("Expected null entity for type 'core-site'", target);
+    
+    target = hostConfigMappingDAO.findSelectedByType(1L, "h1", "global");
+    Assert.assertNotNull("Expected non-null entity for type 'global'", target);
+    Assert.assertEquals("Expected version to be '" + entity1.getVersion() + "'", entity1.getVersion(), target.getVersion());
+    
+    target.setSelected(0);
+    hostConfigMappingDAO.merge(target);
+    
+    HostConfigMappingEntity entity2 = createEntity(1L, "h1", "global", "version2");
+    
+    target = hostConfigMappingDAO.findSelectedByType(1L, "h1", "global");
+    Assert.assertNotNull("Expected non-null entity for type 'global'", target);
+    
+    Assert.assertEquals("Expected version to be '" + entity2.getVersion() + "'", entity2.getVersion(), target.getVersion());    
+    
+    Assert.assertEquals("Expected instance equality", entity2, target);
+  }
+  
+
+  
+  
+  
+  
+}

Added: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/DesiredConfigTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/DesiredConfigTest.java?rev=1452892&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/DesiredConfigTest.java (added)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/DesiredConfigTest.java Tue Mar  5 16:52:48 2013
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests desired config instances.
+ */
+public class DesiredConfigTest {
+
+  @Test
+  public void testDesiredConfig() throws Exception {
+    DesiredConfig dc = new DesiredConfig();
+    dc.setServiceName("service");
+    dc.setVersion("global");
+    
+    Assert.assertEquals("Expected service 'service'", "service", dc.getServiceName());
+    Assert.assertEquals("Expected version 'global'", "global", dc.getVersion());
+    
+  }
+  
+}

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/host/HostTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/host/HostTest.java?rev=1452892&r1=1452891&r2=1452892&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/host/HostTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/state/host/HostTest.java Tue Mar  5 16:52:48 2013
@@ -24,7 +24,9 @@ import static org.mockito.Mockito.doNoth
 import static org.mockito.Mockito.mock;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
@@ -33,16 +35,22 @@ import org.apache.ambari.server.agent.Ag
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.HeartBeatHandler;
 import org.apache.ambari.server.agent.HostInfo;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.entities.HostEntity;
 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.DesiredConfig;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.StackId;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.junit.After;
@@ -338,4 +346,52 @@ public class HostTest {
     registerHost(host, false);
 
   }
+  
+  @Test
+  public void testHostDesiredConfig() throws Exception {
+    AmbariMetaInfo metaInfo = injector.getInstance(AmbariMetaInfo.class);
+    metaInfo.init();
+    
+    clusters.addCluster("c1");
+    Cluster c1 = clusters.getCluster("c1");
+    Assert.assertEquals("c1", c1.getClusterName());
+    Assert.assertEquals(1, c1.getClusterId());
+    clusters.addHost("h1");
+    Host host = clusters.getHost("h1");
+    host.setIPv4("ipv4");
+    host.setIPv6("ipv6");
+    host.setOsType("centos5");
+    host.persist();
+    c1.setDesiredStackVersion(new StackId("HDP-0.1"));
+    clusters.mapHostToCluster("h1", "c1");
+    
+    ConfigFactory configFactory = injector.getInstance(ConfigFactory.class);
+    Config config = configFactory.createNew(c1, "global",
+        new HashMap<String,String>() {{ put("a", "b"); put("x", "y"); }});
+    
+    try {
+      host.addDesiredConfig(c1.getClusterId(), null, config);
+      Assert.fail("Expect failure when version is not specified.");
+    }
+    catch (Exception e) {
+      // testing exception
+    }
+    
+    config.setVersionTag("v1");
+    host.addDesiredConfig(c1.getClusterId(), null, config);
+    
+    Map<String, DesiredConfig> map = host.getDesiredConfigs(c1.getClusterId());
+    Assert.assertTrue("Expect desired config to contain global", map.containsKey("global"));
+    
+    config = configFactory.createNew(c1, "global",
+        new HashMap<String,String>() {{ put("c", "d"); }});
+    config.setVersionTag("v2");
+    host.addDesiredConfig(c1.getClusterId(), null, config);
+    
+    map = host.getDesiredConfigs(c1.getClusterId());
+    Assert.assertTrue("Expect desired config to contain global", map.containsKey("global"));
+    Assert.assertEquals("Expect version to be 'v2'",
+        "v2", map.get("global").getVersion());
+    
+  }
 }