ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From swa...@apache.org
Subject [1/2] AMBARI-3606. Add ConfigGroup resource provider to support API calls. (swagle)
Date Fri, 01 Nov 2013 18:53:34 GMT
Updated Branches:
  refs/heads/trunk 12ac556f4 -> aa8e98f46


http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 6ee0d9c..6f69d5e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -32,12 +32,15 @@ import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterStateDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
 import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 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;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
 import org.apache.ambari.server.orm.entities.HostConfigMappingEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -49,6 +52,8 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
+import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,6 +92,11 @@ public class ClusterImpl implements Cluster {
   private Map<String, List<ServiceComponentHost>>
       serviceComponentHostsByHost;
 
+  /**
+   * Map of existing config groups
+   */
+  private Map<Long, ConfigGroup> clusterConfigGroups;
+
   private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
   private Lock readLock = readWriteLock.readLock();
   private Lock writeLock = readWriteLock.writeLock();
@@ -107,6 +117,10 @@ public class ClusterImpl implements Cluster {
   private Gson gson;
   @Inject
   private HostConfigMappingDAO hostConfigMappingDAO;
+  @Inject
+  private ConfigGroupFactory configGroupFactory;
+  @Inject
+  private ConfigGroupHostMappingDAO configGroupHostMappingDAO;
 
   private volatile boolean svcHostsLoaded = false;
 
@@ -229,6 +243,125 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  private void loadConfigGroups() {
+    if (clusterConfigGroups == null) {
+      clusterGlobalLock.writeLock().lock();
+      try {
+        writeLock.lock();
+        try {
+          if (clusterConfigGroups == null) {
+            clusterConfigGroups = new HashMap<Long, ConfigGroup>();
+            if (!clusterEntity.getConfigGroupEntities().isEmpty()) {
+              for (ConfigGroupEntity configGroupEntity :
+                clusterEntity.getConfigGroupEntities()) {
+                clusterConfigGroups.put(configGroupEntity.getGroupId(),
+                  configGroupFactory.createExisting(this, configGroupEntity));
+              }
+            }
+          }
+        } finally {
+          writeLock.unlock();
+        }
+      } finally {
+        clusterGlobalLock.writeLock().unlock();
+      }
+    }
+  }
+
+  @Override
+  public void addConfigGroup(ConfigGroup configGroup) throws AmbariException {
+    loadConfigGroups();
+    clusterGlobalLock.writeLock().lock();
+    try {
+      writeLock.lock();
+      try {
+        LOG.debug("Adding a new Config group"
+          + ", clusterName = " + getClusterName()
+          + ", groupName = " + configGroup.getName()
+          + ", tag = " + configGroup.getTag());
+
+        if (clusterConfigGroups.containsKey(configGroup.getId())) {
+          throw new AmbariException("Config group already exists"
+            + ", clusterName = " + getClusterName()
+            + ", groupName = " + configGroup.getName()
+            + ", groupId = " + configGroup.getId()
+            + ", tag = " + configGroup.getTag());
+        }
+
+        clusterConfigGroups.put(configGroup.getId(), configGroup);
+
+      } finally {
+        writeLock.unlock();
+      }
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
+  @Override
+  public Map<Long, ConfigGroup> getConfigGroups() throws AmbariException {
+    loadConfigGroups();
+    clusterGlobalLock.readLock().lock();
+    try {
+      readLock.lock();
+      try {
+        return Collections.unmodifiableMap(clusterConfigGroups);
+      } finally {
+        readLock.unlock();
+      }
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public Map<Long, ConfigGroup> getConfigGroupsByHostname(String hostname) {
+    Map<Long, ConfigGroup> configGroups = new HashMap<Long, ConfigGroup>();
+
+    List<ConfigGroupHostMappingEntity> hostMappingEntities =
+      configGroupHostMappingDAO.findByHost(hostname);
+
+    if (hostMappingEntities != null && !hostMappingEntities.isEmpty()) {
+      for (ConfigGroupHostMappingEntity entity : hostMappingEntities) {
+        ConfigGroup configGroup = clusterConfigGroups.get(entity
+          .getConfigGroupId());
+        if (configGroup != null && !configGroups.containsKey(configGroup.getId())) {
+          configGroups.put(configGroup.getId(), configGroup);
+        }
+      }
+    }
+
+    return configGroups;
+  }
+
+  @Override
+  public void deleteConfigGroup(Long id) throws AmbariException {
+    loadConfigGroups();
+    clusterGlobalLock.writeLock().lock();
+    try {
+      readWriteLock.writeLock().lock();
+      try {
+        ConfigGroup configGroup = clusterConfigGroups.get(id);
+        if (configGroup == null) {
+          throw new AmbariException("Config group does not exist, id = " + id);
+        }
+        LOG.debug("Deleting Config group"
+          + ", clusterName = " + getClusterName()
+          + ", groupName = " + configGroup.getName()
+          + ", groupId = " + configGroup.getId()
+          + ", tag = " + configGroup.getTag());
+
+        configGroup.delete();
+        clusterConfigGroups.remove(id);
+
+      } finally {
+        readWriteLock.writeLock().unlock();
+      }
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
   public ServiceComponentHost getServiceComponentHost(String serviceName,
       String serviceComponentName, String hostname) throws AmbariException {
     loadServiceHostComponents();

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index 246d84d..4916d0b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -39,9 +39,12 @@ import org.apache.ambari.server.HostNotFoundException;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
 import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.Cluster;
@@ -52,6 +55,7 @@ import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.host.HostFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroup.java
new file mode 100644
index 0000000..fc51ff1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroup.java
@@ -0,0 +1,150 @@
+/**
+ * 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.configgroup;
+
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.controller.ConfigGroupResponse;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.Host;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Configuration group or Config group is a type of Ambari resource that
+ * supports grouping of configuration resources and host resources for a
+ * service, service component or host component.
+ */
+public interface ConfigGroup {
+  /**
+   * Primary key of config group
+   * @return
+   */
+  public Long getId();
+
+  /**
+   * Unique config group name
+   * @return
+   */
+  public String getName();
+
+  /**
+   * Update Group name
+   * @param name
+   */
+  public void setName(String name);
+
+  /**
+   * Cluster name to which config group belongs
+   * @return
+   */
+  public String getClusterName();
+
+  /**
+   * Tag which associates config group to service
+   * @return
+   */
+  public String getTag();
+
+  /**
+   * Update tag
+   * @param tag
+   */
+  public void setTag(String tag);
+
+  /**
+   * Config group description
+   * @return
+   */
+  public String getDescription();
+
+  /**
+   * Update description
+   * @param description
+   */
+  public void setDescription(String description);
+
+  /**
+   * List of hosts to which configs are applied
+   * @return
+   */
+  public Map<String, Host> getHosts();
+
+  /**
+   * List of @Config objects
+   * @return
+   */
+  public Map<String, Config> getConfigurations();
+
+  /**
+   * Persist the Config group along with the related host and config mapping
+   * entities to the persistence store
+   */
+  @Transactional
+  void persist();
+
+  /**
+   * Delete config group and the related host and config mapping
+   * entities from the persistence store
+   */
+  public void delete();
+
+  /**
+   * Add host to Config group
+   * @param host
+   * @throws AmbariException
+   */
+  public void addHost(Host host) throws AmbariException;
+
+  /**
+   * Add config to the config group
+   * @param config
+   * @throws AmbariException
+   */
+  public void addConfiguration(Config config) throws AmbariException;
+
+  /**
+   * Return @ConfigGroupResponse for the config group
+   *
+   * @return @ConfigGroupResponse
+   * @throws AmbariException
+   */
+  public ConfigGroupResponse convertToResponse() throws AmbariException;
+
+  /**
+   * Refresh Config group and the host and config mappings for the group
+   */
+  @Transactional
+  public void refresh();
+
+  /**
+   * Reassign the set of hosts associated with this config group
+   * @param hosts
+   */
+  public void setHosts(Map<String, Host> hosts);
+
+  /**
+   * Reassign the set of configs associated with this config group
+   * @param configs
+   */
+  public void setConfigurations(Map<String, Config> configs);
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupFactory.java
new file mode 100644
index 0000000..4ba569d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupFactory.java
@@ -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.configgroup;
+
+import com.google.inject.assistedinject.Assisted;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ConfigGroupFactory {
+  ConfigGroup createNew(@Assisted("cluster") Cluster cluster,
+                       @Assisted("name") String name,
+                       @Assisted("tag") String tag,
+                       @Assisted("description") String description,
+                       @Assisted("configs") Map<String, Config> configs,
+                       @Assisted("hosts") Map<String, Host> hosts);
+
+  ConfigGroup createExisting(Cluster cluster, ConfigGroupEntity entity);
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
new file mode 100644
index 0000000..9fb1330
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
@@ -0,0 +1,513 @@
+/**
+ * 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.configgroup;
+
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.controller.ConfigGroupResponse;
+import org.apache.ambari.server.controller.internal.ConfigGroupResourceProvider;
+import org.apache.ambari.server.controller.internal.ConfigurationResourceProvider;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupConfigMappingDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupDAO;
+import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
+import org.apache.ambari.server.orm.entities.ClusterConfigEntityPK;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
+import org.apache.ambari.server.orm.entities.HostEntity;
+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.eclipse.persistence.sessions.UnitOfWork;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class ConfigGroupImpl implements ConfigGroup {
+  private static final Logger LOG = LoggerFactory.getLogger(ConfigGroupImpl.class);
+  //private final ReadWriteLock clusterGlobalLock;
+  private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+
+  private Cluster cluster;
+  private ConfigGroupEntity configGroupEntity;
+  private Map<String, Host> hosts;
+  private Map<String, Config> configurations;
+  private volatile boolean isPersisted = false;
+
+  @Inject
+  private Gson gson;
+  @Inject
+  private ConfigGroupDAO configGroupDAO;
+  @Inject
+  private ConfigGroupConfigMappingDAO configGroupConfigMappingDAO;
+  @Inject
+  private ConfigGroupHostMappingDAO configGroupHostMappingDAO;
+  @Inject
+  private HostDAO hostDAO;
+  @Inject
+  private ClusterDAO clusterDAO;
+  @Inject
+  Clusters clusters;
+  @Inject
+  private ConfigFactory configFactory;
+
+  @AssistedInject
+  public ConfigGroupImpl(@Assisted("cluster") Cluster cluster,
+                         @Assisted("name") String name,
+                         @Assisted("tag") String tag,
+                         @Assisted("description") String description,
+                         @Assisted("configs") Map<String, Config> configs,
+                         @Assisted("hosts") Map<String, Host> hosts,
+                         Injector injector) {
+    injector.injectMembers(this);
+    this.cluster = cluster;
+
+    configGroupEntity = new ConfigGroupEntity();
+    configGroupEntity.setClusterId(cluster.getClusterId());
+    configGroupEntity.setGroupName(name);
+    configGroupEntity.setTag(tag);
+    configGroupEntity.setDescription(description);
+
+    if (hosts != null) {
+      this.hosts = hosts;
+    } else {
+      this.hosts = new HashMap<String, Host>();
+    }
+
+    if (configs != null) {
+      this.configurations = configs;
+    } else {
+      this.configurations = new HashMap<String, Config>();
+    }
+  }
+
+  @AssistedInject
+  public ConfigGroupImpl(@Assisted Cluster cluster,
+                         @Assisted ConfigGroupEntity configGroupEntity,
+                         Injector injector) {
+    injector.injectMembers(this);
+    this.cluster = cluster;
+
+    this.configGroupEntity = configGroupEntity;
+    this.configurations = new HashMap<String, Config>();
+    this.hosts = new HashMap<String, Host>();
+
+    // Populate configs
+    for (ConfigGroupConfigMappingEntity configMappingEntity : configGroupEntity
+      .getConfigGroupConfigMappingEntities()) {
+
+      Config config = cluster.getConfig(configMappingEntity.getConfigType(),
+        configMappingEntity.getVersionTag());
+
+      if (config != null) {
+        this.configurations.put(config.getType(), config);
+      } else {
+        LOG.warn("Unable to find config mapping for config group"
+          + ", clusterName = " + cluster.getClusterName()
+          + ", type = " + configMappingEntity.getConfigType()
+          + ", tag = " + configMappingEntity.getVersionTag());
+      }
+    }
+
+    // Populate Hosts
+    for (ConfigGroupHostMappingEntity hostMappingEntity : configGroupEntity
+      .getConfigGroupHostMappingEntities()) {
+
+      try {
+        Host host = clusters.getHost(hostMappingEntity.getHostname());
+        if (host != null) {
+          this.hosts.put(host.getHostName(), host);
+        }
+      } catch (AmbariException e) {
+        String msg = "Host seems to be deleted but Config group mapping still " +
+          "exists !";
+        LOG.warn(msg);
+        LOG.debug(msg, e);
+      }
+    }
+
+    isPersisted = true;
+  }
+
+  @Override
+  public Long getId() {
+    return configGroupEntity.getGroupId();
+  }
+
+  @Override
+  public String getName() {
+    readWriteLock.readLock().lock();
+    try {
+      return configGroupEntity.getGroupName();
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public void setName(String name) {
+    this.configGroupEntity.setGroupName(name);
+  }
+
+  @Override
+  public String getClusterName() {
+    return configGroupEntity.getClusterEntity().getClusterName();
+  }
+
+  @Override
+  public String getTag() {
+    readWriteLock.readLock().lock();
+    try {
+      return configGroupEntity.getTag();
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public void setTag(String tag) {
+    this.configGroupEntity.setTag(tag);
+  }
+
+  @Override
+  public String getDescription() {
+    readWriteLock.readLock().lock();
+    try {
+      return configGroupEntity.getDescription();
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public void setDescription(String description) {
+    this.configGroupEntity.setDescription(description);
+  }
+
+  @Override
+  public Map<String, Host> getHosts() {
+    readWriteLock.readLock().lock();
+    try {
+      return Collections.unmodifiableMap(hosts);
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public Map<String, Config> getConfigurations() {
+    readWriteLock.readLock().lock();
+    try {
+      return Collections.unmodifiableMap(configurations);
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+
+  }
+
+  /**
+   * Helper method to recreate host mapping
+   * @param hosts
+   */
+  @Override
+  public void setHosts(Map<String, Host> hosts) {
+    this.hosts = hosts;
+  }
+
+  /**
+   * Helper method to recreate configs mapping
+   * @param configs
+   */
+  @Override
+  public void setConfigurations(Map<String, Config> configs) {
+    this.configurations = configs;
+  }
+
+  @Override
+  @Transactional
+
+  public void persist() {
+    readWriteLock.writeLock().lock();
+    try {
+      if (!isPersisted) {
+        persistEntities();
+        refresh();
+        cluster.refresh();
+        isPersisted = true;
+      } else {
+        saveIfPersisted();
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  /**
+   * Persist Config group with host mapping and configurations
+   *
+   * @throws Exception
+   */
+  @Transactional
+  private void persistEntities() {
+    ClusterEntity clusterEntity = clusterDAO.findById(cluster.getClusterId());
+    configGroupEntity.setClusterEntity(clusterEntity);
+    configGroupEntity.setTimestamp(System.currentTimeMillis());
+    configGroupDAO.create(configGroupEntity);
+
+    persistConfigMapping(clusterEntity);
+    persistHostMapping();
+  }
+
+  // TODO: Test rollback scenario
+
+  /**
+   * Persist host mapping
+   *
+   * @throws Exception
+   */
+  @Transactional
+  private void persistHostMapping() {
+    if (isPersisted) {
+      // Delete existing mappings and create new ones
+      configGroupHostMappingDAO.removeAllByGroup(configGroupEntity.getGroupId());
+      configGroupEntity.getConfigGroupHostMappingEntities().clear();
+    }
+
+    if (hosts != null && !hosts.isEmpty()) {
+      for (Host host : hosts.values()) {
+        HostEntity hostEntity = hostDAO.findByName(host.getHostName());
+        if (hostEntity != null) {
+          ConfigGroupHostMappingEntity hostMappingEntity = new
+            ConfigGroupHostMappingEntity();
+          hostMappingEntity.setHostname(host.getHostName());
+          hostMappingEntity.setHostEntity(hostEntity);
+          hostMappingEntity.setConfigGroupEntity(configGroupEntity);
+          hostMappingEntity.setConfigGroupId(configGroupEntity.getGroupId());
+          configGroupHostMappingDAO.create(hostMappingEntity);
+          // TODO: Make sure this does not throw Nullpointer based on JPA docs
+          configGroupEntity.getConfigGroupHostMappingEntities().add
+            (hostMappingEntity);
+          configGroupDAO.merge(configGroupEntity);
+        } else {
+          LOG.warn("Host seems to be deleted, cannot create host to config " +
+            "group mapping, host = " + host.getHostName());
+        }
+      }
+    }
+  }
+
+  /**
+   * Persist config group config mapping and create configs if not in DB
+   *
+   * @param clusterEntity
+   * @throws Exception
+   */
+  @Transactional
+  private void persistConfigMapping(ClusterEntity clusterEntity) {
+    if (isPersisted) {
+      configGroupConfigMappingDAO.removeAllByGroup(configGroupEntity.getGroupId());
+      configGroupEntity.getConfigGroupConfigMappingEntities().clear();
+    }
+
+    if (configurations != null && !configurations.isEmpty()) {
+      for (Config config : configurations.values()) {
+        ClusterConfigEntityPK clusterConfigEntityPK = new ClusterConfigEntityPK();
+        clusterConfigEntityPK.setClusterId(cluster.getClusterId());
+        clusterConfigEntityPK.setTag(config.getVersionTag());
+        clusterConfigEntityPK.setType(config.getType());
+        ClusterConfigEntity clusterConfigEntity = clusterDAO.findConfig
+          (clusterConfigEntityPK);
+
+        if (clusterConfigEntity == null) {
+          // Create configuration
+          clusterConfigEntity = new ClusterConfigEntity();
+          clusterConfigEntity.setClusterId(clusterEntity.getClusterId());
+          clusterConfigEntity.setClusterEntity(clusterEntity);
+          clusterConfigEntity.setType(config.getType());
+          clusterConfigEntity.setTag(config.getVersionTag());
+          clusterConfigEntity.setData(gson.toJson(config.getProperties()));
+          clusterConfigEntity.setTimestamp(System.currentTimeMillis());
+
+          // TODO: Is locking necessary and functional ?
+          cluster.getClusterGlobalLock().writeLock().lock();
+          try {
+            clusterDAO.createConfig(clusterConfigEntity);
+            clusterEntity.getClusterConfigEntities().add(clusterConfigEntity);
+            cluster.addConfig(config);
+            clusterDAO.merge(clusterEntity);
+            cluster.refresh();
+          } finally {
+            cluster.getClusterGlobalLock().writeLock().unlock();
+          }
+        }
+
+        ConfigGroupConfigMappingEntity configMappingEntity =
+          new ConfigGroupConfigMappingEntity();
+        configMappingEntity.setTimestamp(System.currentTimeMillis());
+        configMappingEntity.setClusterId(clusterEntity.getClusterId());
+        configMappingEntity.setClusterConfigEntity(clusterConfigEntity);
+        configMappingEntity.setConfigGroupEntity(configGroupEntity);
+        configMappingEntity.setConfigGroupId(configGroupEntity.getGroupId());
+        configMappingEntity.setConfigType(clusterConfigEntity.getType());
+        configMappingEntity.setVersionTag(clusterConfigEntity.getTag());
+        configGroupConfigMappingDAO.create(configMappingEntity);
+        configGroupEntity.getConfigGroupConfigMappingEntities().add
+          (configMappingEntity);
+
+        configGroupDAO.merge(configGroupEntity);
+      }
+    }
+  }
+
+  @Transactional
+  private void saveIfPersisted() {
+    ClusterEntity clusterEntity = clusterDAO.findById(cluster.getClusterId());
+
+    if (isPersisted) {
+      configGroupDAO.merge(configGroupEntity);
+      persistHostMapping();
+      persistConfigMapping(clusterEntity);
+    }
+  }
+
+  @Override
+  @Transactional
+  public void delete() {
+    readWriteLock.writeLock().lock();
+    try {
+      configGroupConfigMappingDAO.removeAllByGroup(configGroupEntity.getGroupId());
+      configGroupHostMappingDAO.removeAllByGroup(configGroupEntity.getGroupId());
+      configGroupDAO.removeByPK(configGroupEntity.getGroupId());
+      cluster.refresh();
+      isPersisted = false;
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
+  public void addHost(Host host) throws AmbariException {
+    readWriteLock.writeLock().lock();
+    try {
+      if (hosts != null && !hosts.isEmpty()) {
+        for (Host h : hosts.values()) {
+          if (h.getHostName().equals(host.getHostName())) {
+            throw new DuplicateResourceException("Host " + h.getHostName() +
+              "is already associated with Config Group " +
+              configGroupEntity.getGroupName());
+          }
+        }
+        hosts.put(host.getHostName(), host);
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
+  public void addConfiguration(Config config) throws AmbariException {
+    readWriteLock.writeLock().lock();
+    try {
+      if (configurations != null && !configurations.isEmpty()) {
+        for (Config c : configurations.values()) {
+          if (c.getType().equals(config.getType()) && c.getVersionTag().equals
+            (config.getVersionTag())) {
+            throw new DuplicateResourceException("Config " + config.getType() +
+              " with tag " + config.getVersionTag() + " is already associated " +
+              "with Config Group " + configGroupEntity.getGroupName());
+          }
+        }
+        configurations.put(config.getType(), config);
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
+  public ConfigGroupResponse convertToResponse() throws AmbariException {
+    readWriteLock.readLock().lock();
+    try {
+      Set<Map<String, Object>> hostnames = new HashSet<Map<String, Object>>();
+      for (Host host : hosts.values()) {
+        Map<String, Object> hostMap = new HashMap<String, Object>();
+        hostMap.put("host_name", host.getHostName());
+        hostnames.add(hostMap);
+      }
+
+      Set<Map<String, Object>> configObjMap = new HashSet<Map<String,
+        Object>>();
+
+      for (Config config : configurations.values()) {
+        Map<String, Object> configMap = new HashMap<String, Object>();
+        configMap.put(ConfigurationResourceProvider
+          .CONFIGURATION_CONFIG_TYPE_PROPERTY_ID, config.getType());
+        configMap.put(ConfigurationResourceProvider
+          .CONFIGURATION_CONFIG_TAG_PROPERTY_ID, config.getVersionTag());
+        configObjMap.add(configMap);
+      }
+
+      ConfigGroupResponse configGroupResponse = new ConfigGroupResponse(
+        configGroupEntity.getGroupId(), cluster.getClusterName(),
+        configGroupEntity.getGroupName(), configGroupEntity.getTag(),
+        configGroupEntity.getDescription(),
+        hostnames, configObjMap);
+      return configGroupResponse;
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Transactional
+  public void refresh() {
+    readWriteLock.writeLock().lock();
+    try {
+      if (isPersisted) {
+        ConfigGroupEntity groupEntity = configGroupDAO.findById
+          (configGroupEntity.getGroupId());
+        configGroupDAO.refresh(groupEntity);
+        // TODO What other entities should refresh?
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql
index 0b749a3..7c88d2a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql
@@ -93,7 +93,9 @@ select 'cluster_id_seq', 1
 union all
 select 'user_id_seq', 2
 union all
-select 'host_role_command_id_seq', 1;
+select 'host_role_command_id_seq', 1
+union all
+select 'configgroup_id_seq', 1;
 
 insert into ambari.Roles(role_name)
 select 'admin'

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 090feaa..684a756 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -100,5 +100,9 @@
     "Host":"RootServiceHostComponents/host_name",
     "RootServiceComponent":"RootServiceHostComponents/component_name",
     "RootServiceHostComponent":"RootServiceHostComponents/component_name"
+  },
+  "ConfigGroup" : {
+      "Cluster" : "ConfigGroup/cluster_name",
+      "ConfigGroup" : "ConfigGroup/id"
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 2a985c7..fd02437 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -76,6 +76,15 @@
         "Config/type",
         "Config/cluster_name"
     ],
+    "ConfigGroup": [
+        "ConfigGroup/id",
+        "ConfigGroup/cluster_name",
+        "ConfigGroup/group_name",
+        "ConfigGroup/tag",
+        "ConfigGroup/description",
+        "ConfigGroup/hosts",
+        "ConfigGroup/desired_configs"
+    ],
     "Action":[
         "Actions/cluster_name",
         "Actions/service_name",

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
new file mode 100644
index 0000000..1e13355
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
+import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+
+public class ConfigGroupServiceTest extends BaseServiceTest {
+
+  @Override
+  public List<ServiceTestInvocation> getTestInvocations() throws Exception {
+    List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
+
+    // Get Config Groups
+    ConfigGroupService configGroupService = new TestConfigGroupService
+      ("clusterName", null);
+    Method m = configGroupService.getClass().getMethod("getConfigGroups",
+      HttpHeaders.class, UriInfo.class);
+    Object[] args = new Object[] {getHttpHeaders(), getUriInfo()};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET,
+      configGroupService, m, args, null));
+
+    // Get Config Group
+    configGroupService = new TestConfigGroupService("clusterName", "groupId");
+    m = configGroupService.getClass().getMethod("getConfigGroup",
+      HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo(), "groupId"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET,
+      configGroupService, m, args, null));
+
+    // Create Config group
+    configGroupService = new TestConfigGroupService("clusterName", null);
+    m = configGroupService.getClass().getMethod("createConfigGroup",
+      String.class, HttpHeaders.class, UriInfo.class);
+    args = new Object[] {"body", getHttpHeaders(), getUriInfo()};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.POST,
+      configGroupService, m, args, "body"));
+
+    // Delete Config group
+    configGroupService = new TestConfigGroupService("clusterName", "groupId");
+    m = configGroupService.getClass().getMethod("deleteConfigGroup",
+      HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo(), "groupId"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE,
+      configGroupService, m, args, null));
+
+    // Update Config group
+    configGroupService = new TestConfigGroupService("clusterName", "groupId");
+    m = configGroupService.getClass().getMethod("updateConfigGroup",
+      String.class, HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "groupId"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.PUT,
+      configGroupService, m, args, "body"));
+
+    return listInvocations;
+  }
+
+  private class TestConfigGroupService extends ConfigGroupService {
+    private String m_clusterName;
+    private String m_groupId;
+
+    public TestConfigGroupService(String m_clusterName, String groupId) {
+      super(m_clusterName);
+      this.m_clusterName = m_clusterName;
+      this.m_groupId = groupId;
+    }
+
+    @Override
+    ResourceInstance createConfigGroupResource(String clusterName,
+                                               String groupId) {
+      assertEquals(m_clusterName, clusterName);
+      assertEquals(m_groupId, groupId);
+      return getTestResource();
+    }
+
+    @Override
+    RequestFactory getRequestFactory() {
+      return getTestRequestFactory();
+    }
+
+    @Override
+    protected RequestBodyParser getBodyParser() {
+      return getTestBodyParser();
+    }
+
+    @Override
+    protected ResultSerializer getResultSerializer() {
+      return getTestResultSerializer();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProviderTest.java
new file mode 100644
index 0000000..6163b47
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProviderTest.java
@@ -0,0 +1,446 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ConfigGroupResponse;
+import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+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.ConfigImpl;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
+import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
+import org.easymock.Capture;
+import org.easymock.IAnswer;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+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;
+
+public class ConfigGroupResourceProviderTest {
+
+  ConfigGroupResourceProvider getConfigGroupResourceProvider
+    (AmbariManagementController managementController) {
+
+    Resource.Type type = Resource.Type.ConfigGroup;
+
+    return (ConfigGroupResourceProvider) AbstractControllerResourceProvider.getResourceProvider(
+      type,
+      PropertyHelper.getPropertyIds(type),
+      PropertyHelper.getKeyPropertyIds(type),
+      managementController);
+  }
+
+  @Test
+  public void testCreateConfigGroup() throws Exception {
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+    Clusters clusters = createNiceMock(Clusters.class);
+    Cluster cluster = createNiceMock(Cluster.class);
+    Host h1 = createNiceMock(Host.class);
+    Host h2 = createNiceMock(Host.class);
+    ConfigGroupFactory configGroupFactory = createNiceMock(ConfigGroupFactory.class);
+    ConfigGroup configGroup = createNiceMock(ConfigGroup.class);
+
+    expect(managementController.getClusters()).andReturn(clusters);
+    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
+    expect(clusters.getHost("h1")).andReturn(h1);
+    expect(clusters.getHost("h2")).andReturn(h2);
+    expect(managementController.getConfigGroupFactory()).andReturn(configGroupFactory);
+    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
+
+    Capture<Cluster> clusterCapture = new Capture<Cluster>();
+    Capture<String> captureName = new Capture<String>();
+    Capture<String> captureDesc = new Capture<String>();
+    Capture<String> captureTag = new Capture<String>();
+    Capture<Map<String, Config>> captureConfigs = new Capture<Map<String,
+      Config>>();
+    Capture<Map<String, Host>> captureHosts = new Capture<Map<String, Host>>();
+
+    expect(configGroupFactory.createNew(capture(clusterCapture),
+      capture(captureName), capture(captureTag), capture(captureDesc),
+      capture(captureConfigs), capture(captureHosts))).andReturn(configGroup);
+
+    replay(managementController, clusters, cluster, configGroupFactory,
+      configGroup, response);
+
+    ResourceProvider provider = getConfigGroupResourceProvider
+      (managementController);
+
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    Set<Map<String, Object>> hostSet = new HashSet<Map<String, Object>>();
+    Map<String, Object> host1 = new HashMap<String, Object>();
+    host1.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID, "h1");
+    hostSet.add(host1);
+    Map<String, Object> host2 = new HashMap<String, Object>();
+    host2.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID, "h2");
+    hostSet.add(host2);
+
+    Set<Map<String, Object>> configSet = new HashSet<Map<String, Object>>();
+    Map<String, String> configMap = new HashMap<String, String>();
+    Map<String, Object> configs = new HashMap<String, Object>();
+    configs.put("type", "core-site");
+    configs.put("tag", "version100");
+    configMap.put("key1", "value1");
+    configs.put("properties", configMap);
+    configSet.add(configs);
+
+    properties.put(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID, "Cluster100");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_NAME_PROPERTY_ID,
+      "test-1");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_TAG_PROPERTY_ID,
+      "tag-1");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTS_PROPERTY_ID,
+      hostSet);
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_CONFIGS_PROPERTY_ID,
+      configSet);
+
+    propertySet.add(properties);
+
+    Request request = PropertyHelper.getCreateRequest(propertySet, null);
+
+    provider.createResources(request);
+
+    verify(managementController, clusters, cluster, configGroupFactory,
+      configGroup, response);
+
+    assertEquals("version100", captureConfigs.getValue().get("core-site")
+      .getVersionTag());
+    assertTrue(captureHosts.getValue().containsKey("h1"));
+    assertTrue(captureHosts.getValue().containsKey("h2"));
+  }
+
+  @Test
+  public void testUpdateConfigGroup() throws Exception {
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
+    Clusters clusters = createNiceMock(Clusters.class);
+    Cluster cluster = createNiceMock(Cluster.class);
+    Host h1 = createNiceMock(Host.class);
+    Host h2 = createNiceMock(Host.class);
+    final ConfigGroup configGroup = createNiceMock(ConfigGroup.class);
+    ConfigGroupResponse configGroupResponse = createNiceMock
+      (ConfigGroupResponse.class);
+
+    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
+    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
+    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
+    expect(clusters.getHost("h1")).andReturn(h1);
+    expect(clusters.getHost("h2")).andReturn(h2);
+
+    expect(configGroup.getName()).andReturn("test-1").anyTimes();
+    expect(configGroup.getId()).andReturn(25L).anyTimes();
+    expect(configGroup.getTag()).andReturn("tag-1").anyTimes();
+
+    expect(configGroup.convertToResponse()).andReturn(configGroupResponse).anyTimes();
+    expect(configGroupResponse.getClusterName()).andReturn("Cluster100").anyTimes();
+    expect(configGroupResponse.getId()).andReturn(25L).anyTimes();
+
+    expect(cluster.getConfigGroups()).andStubAnswer(new IAnswer<Map<Long, ConfigGroup>>() {
+      @Override
+      public Map<Long, ConfigGroup> answer() throws Throwable {
+        Map<Long, ConfigGroup> configGroupMap = new HashMap<Long, ConfigGroup>();
+        configGroupMap.put(configGroup.getId(), configGroup);
+        return configGroupMap;
+      }
+    });
+
+    replay(managementController, clusters, cluster,
+      configGroup, response, configGroupResponse);
+
+    ResourceProvider provider = getConfigGroupResourceProvider
+      (managementController);
+
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+
+    Set<Map<String, Object>> hostSet = new HashSet<Map<String, Object>>();
+    Map<String, Object> host1 = new HashMap<String, Object>();
+    host1.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID, "h1");
+    hostSet.add(host1);
+    Map<String, Object> host2 = new HashMap<String, Object>();
+    host2.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID, "h2");
+    hostSet.add(host2);
+
+    Set<Map<String, Object>> configSet = new HashSet<Map<String, Object>>();
+    Map<String, String> configMap = new HashMap<String, String>();
+    Map<String, Object> configs = new HashMap<String, Object>();
+    configs.put("type", "core-site");
+    configs.put("tag", "version100");
+    configMap.put("key1", "value1");
+    configs.put("properties", configMap);
+    configSet.add(configs);
+
+    properties.put(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID, "Cluster100");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_NAME_PROPERTY_ID,
+      "test-1");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_TAG_PROPERTY_ID,
+      "tag-1");
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_HOSTS_PROPERTY_ID,
+      hostSet );
+    properties.put(ConfigGroupResourceProvider.CONFIGGROUP_CONFIGS_PROPERTY_ID,
+      configSet);
+
+    Map<String, String> mapRequestProps = new HashMap<String, String>();
+    mapRequestProps.put("context", "Called from a test");
+
+    Request request = PropertyHelper.getUpdateRequest(properties, mapRequestProps);
+
+    Predicate predicate = new PredicateBuilder().property
+      (ConfigGroupResourceProvider.CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID).equals
+      ("Cluster100").and().
+      property(ConfigGroupResourceProvider.CONFIGGROUP_ID_PROPERTY_ID).equals
+      (25L).toPredicate();
+
+    provider.updateResources(request, predicate);
+
+    verify(managementController, clusters, cluster,
+      configGroup, response, configGroupResponse);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testGetConfigGroup() throws Exception {
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    Clusters clusters = createNiceMock(Clusters.class);
+    Cluster cluster = createNiceMock(Cluster.class);
+    Host h1 = createNiceMock(Host.class);
+
+    ConfigGroup configGroup1 = createNiceMock(ConfigGroup.class);
+    ConfigGroup configGroup2 = createNiceMock(ConfigGroup.class);
+    ConfigGroup configGroup3 = createNiceMock(ConfigGroup.class);
+    ConfigGroup configGroup4 = createNiceMock(ConfigGroup.class);
+    ConfigGroupResponse response1 = createNiceMock(ConfigGroupResponse.class);
+    ConfigGroupResponse response2 = createNiceMock(ConfigGroupResponse.class);
+    ConfigGroupResponse response3 = createNiceMock(ConfigGroupResponse.class);
+    ConfigGroupResponse response4 = createNiceMock(ConfigGroupResponse.class);
+
+    Map<Long, ConfigGroup> configGroupMap = new HashMap<Long, ConfigGroup>();
+    configGroupMap.put(1L, configGroup1);
+    configGroupMap.put(2L, configGroup2);
+    configGroupMap.put(3L, configGroup3);
+    configGroupMap.put(4L, configGroup4);
+
+    Map<Long, ConfigGroup> configGroupByHostname = new HashMap<Long, ConfigGroup>();
+    configGroupByHostname.put(4L, configGroup4);
+
+    expect(configGroup1.convertToResponse()).andReturn(response1).anyTimes();
+    expect(configGroup2.convertToResponse()).andReturn(response2).anyTimes();
+    expect(configGroup3.convertToResponse()).andReturn(response3).anyTimes();
+    expect(configGroup4.convertToResponse()).andReturn(response4).anyTimes();
+
+    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
+    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
+    expect(cluster.getConfigGroups()).andReturn(configGroupMap).anyTimes();
+
+    expect(configGroup1.getName()).andReturn("g1").anyTimes();
+    expect(configGroup2.getName()).andReturn("g2").anyTimes();
+    expect(configGroup3.getName()).andReturn("g3").anyTimes();
+    expect(configGroup4.getName()).andReturn("g4").anyTimes();
+    expect(configGroup1.getTag()).andReturn("t1").anyTimes();
+    expect(configGroup2.getTag()).andReturn("t2").anyTimes();
+    expect(configGroup3.getTag()).andReturn("t3").anyTimes();
+    expect(configGroup4.getTag()).andReturn("t4").anyTimes();
+
+    Map<String, Host> hostMap = new HashMap<String, Host>();
+    hostMap.put("h1", h1);
+    expect(configGroup4.getHosts()).andReturn(hostMap).anyTimes();
+
+
+    expect(response1.getClusterName()).andReturn("Cluster100").anyTimes();
+    expect(response2.getClusterName()).andReturn("Cluster100").anyTimes();
+    expect(response3.getClusterName()).andReturn("Cluster100").anyTimes();
+    expect(response4.getClusterName()).andReturn("Cluster100").anyTimes();
+    expect(response1.getId()).andReturn(1L).anyTimes();
+    expect(response2.getId()).andReturn(2L).anyTimes();
+    expect(response3.getId()).andReturn(3L).anyTimes();
+    expect(response4.getId()).andReturn(4L).anyTimes();
+    expect(response2.getGroupName()).andReturn("g2").anyTimes();
+    expect(response3.getTag()).andReturn("t3").anyTimes();
+    expect(cluster.getConfigGroupsByHostname("h1")).andReturn(configGroupByHostname).anyTimes();
+
+    Set<Map<String, Object>> hostObj = new HashSet<Map<String, Object>>();
+    Map<String, Object> hostnames = new HashMap<String, Object>();
+    hostnames.put("host_name", "h1");
+    hostObj.add(hostnames);
+    expect(response4.getHosts()).andReturn(hostObj).anyTimes();
+
+    replay(managementController, clusters, cluster, configGroup1,
+      configGroup2, configGroup3, configGroup4, response1, response2,
+      response3, response4);
+
+    ResourceProvider resourceProvider = getConfigGroupResourceProvider
+      (managementController);
+
+    Set<String> propertyIds = new HashSet<String>();
+
+    propertyIds.add(ConfigGroupResourceProvider.CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID);
+    propertyIds.add(ConfigGroupResourceProvider.CONFIGGROUP_ID_PROPERTY_ID);
+
+    // Read all
+    Predicate predicate = new PredicateBuilder().property
+      (ConfigGroupResourceProvider.CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID)
+      .equals("Cluster100").toPredicate();
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    Set<Resource> resources = resourceProvider.getResources(request,
+      predicate);
+
+    assertEquals(4, resources.size());
+
+    // Read by id
+    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
+      .CONFIGGROUP_ID_PROPERTY_ID).equals(1L).and().property
+      (ConfigGroupResourceProvider.CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID)
+      .equals("Cluster100").toPredicate();
+
+    resources = resourceProvider.getResources(request, predicate);
+
+    assertEquals(1, resources.size());
+    assertEquals(1L, resources.iterator().next().getPropertyValue
+      (ConfigGroupResourceProvider.CONFIGGROUP_ID_PROPERTY_ID));
+
+    // Read by Name
+    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").and()
+      .property(ConfigGroupResourceProvider.CONFIGGROUP_NAME_PROPERTY_ID)
+      .equals("g2").toPredicate();
+
+    resources = resourceProvider.getResources(request, predicate);
+
+    assertEquals(1, resources.size());
+    assertEquals("g2", resources.iterator().next().getPropertyValue
+      (ConfigGroupResourceProvider.CONFIGGROUP_NAME_PROPERTY_ID));
+
+    // Read by tag
+    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").and()
+      .property(ConfigGroupResourceProvider.CONFIGGROUP_TAG_PROPERTY_ID)
+      .equals("t3").toPredicate();
+
+    resources = resourceProvider.getResources(request, predicate);
+
+    assertEquals(1, resources.size());
+    assertEquals("t3", resources.iterator().next().getPropertyValue
+      (ConfigGroupResourceProvider.CONFIGGROUP_TAG_PROPERTY_ID));
+
+    // Read by hostname
+    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").and()
+      .property(ConfigGroupResourceProvider.CONFIGGROUP_HOSTS_PROPERTY_ID)
+      .equals("h1").toPredicate();
+
+    resources = resourceProvider.getResources(request, predicate);
+
+    assertEquals(1, resources.size());
+    Set<Map<String, Object>> hostSet = (Set<Map<String, Object>>)
+      resources.iterator().next()
+      .getPropertyValue(ConfigGroupResourceProvider
+        .CONFIGGROUP_HOSTS_PROPERTY_ID);
+    assertEquals("h1", hostSet.iterator().next().get
+      (ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID));
+
+
+    // Read by tag and hostname - Positive
+    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
+      .CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").and()
+      .property(ConfigGroupResourceProvider.CONFIGGROUP_TAG_PROPERTY_ID)
+      .equals("t4").and().property(ConfigGroupResourceProvider
+        .CONFIGGROUP_HOSTS_PROPERTY_ID).equals("h1").toPredicate();
+
+    resources = resourceProvider.getResources(request, predicate);
+
+    assertEquals(1, resources.size());
+    hostSet = (Set<Map<String, Object>>)
+      resources.iterator().next()
+        .getPropertyValue(ConfigGroupResourceProvider
+          .CONFIGGROUP_HOSTS_PROPERTY_ID);
+    assertEquals("h1", hostSet.iterator().next().get
+      (ConfigGroupResourceProvider.CONFIGGROUP_HOSTNAME_PROPERTY_ID));
+
+    verify(managementController, clusters, cluster, configGroup1,
+      configGroup2, configGroup3, configGroup4, response1, response2,
+      response3, response4);
+  }
+
+  @Test
+  public void testDeleteConfigGroup() throws Exception {
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    Clusters clusters = createNiceMock(Clusters.class);
+    Cluster cluster = createNiceMock(Cluster.class);
+
+    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
+    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
+    cluster.deleteConfigGroup(1L);
+
+    replay(managementController, clusters, cluster);
+
+    ResourceProvider resourceProvider = getConfigGroupResourceProvider
+      (managementController);
+
+    AbstractResourceProviderTest.TestObserver observer = new AbstractResourceProviderTest.TestObserver();
+
+    ((ObservableResourceProvider) resourceProvider).addObserver(observer);
+
+    Predicate predicate = new PredicateBuilder().property
+      (ConfigGroupResourceProvider.CONFIGGROUP_CLUSTER_NAME_PROPERTY_ID)
+      .equals("Cluster100").and().property(ConfigGroupResourceProvider
+        .CONFIGGROUP_ID_PROPERTY_ID).equals(1L).toPredicate();
+
+    resourceProvider.deleteResources(predicate);
+
+    ResourceProviderEvent lastEvent = observer.getLastEvent();
+    Assert.assertNotNull(lastEvent);
+    Assert.assertEquals(Resource.Type.ConfigGroup, lastEvent.getResourceType());
+    Assert.assertEquals(ResourceProviderEvent.Type.Delete, lastEvent.getType());
+    Assert.assertEquals(predicate, lastEvent.getPredicate());
+    Assert.assertNull(lastEvent.getRequest());
+
+    verify(managementController, clusters, cluster);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/aa8e98f4/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigGroupTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigGroupTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigGroupTest.java
new file mode 100644
index 0000000..36c4aac
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigGroupTest.java
@@ -0,0 +1,214 @@
+/**
+ * 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 com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+import com.google.inject.persist.Transactional;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+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.ConfigGroupDAO;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
+import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
+import org.apache.ambari.server.state.configgroup.ConfigGroup;
+import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ConfigGroupTest {
+
+  private Clusters clusters;
+  private Cluster cluster;
+  private String clusterName;
+  private Injector injector;
+  private AmbariMetaInfo metaInfo;
+  private ConfigGroupFactory configGroupFactory;
+  private ConfigFactory configFactory;
+  private HostDAO hostDAO;
+  private ConfigGroupDAO configGroupDAO;
+
+  @Before
+  public void setup() throws Exception {
+    injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+    clusters = injector.getInstance(Clusters.class);
+    metaInfo = injector.getInstance(AmbariMetaInfo.class);
+    configFactory = injector.getInstance(ConfigFactory.class);
+    configGroupFactory = injector.getInstance(ConfigGroupFactory.class);
+    hostDAO = injector.getInstance(HostDAO.class);
+    configGroupDAO = injector.getInstance(ConfigGroupDAO.class);
+
+    metaInfo.init();
+    clusterName = "foo";
+    clusters.addCluster(clusterName);
+    cluster = clusters.getCluster(clusterName);
+    cluster.setDesiredStackVersion(new StackId("HDP-0.1"));
+    Assert.assertNotNull(cluster);
+    clusters.addHost("h1");
+    clusters.addHost("h2");
+    Assert.assertNotNull(clusters.getHost("h1"));
+    Assert.assertNotNull(clusters.getHost("h2"));
+    clusters.getHost("h1").persist();
+    clusters.getHost("h2").persist();
+  }
+
+  @After
+  public void teardown() throws AmbariException {
+    injector.getInstance(PersistService.class).stop();
+  }
+
+  @Transactional
+  private ConfigGroup createConfigGroup() throws AmbariException {
+    // Create config without persisting and save group
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put("a", "b");
+    properties.put("c", "d");
+    Config config = configFactory.createNew(cluster, "hdfs-site", properties);
+    config.setVersionTag("testversion");
+
+    Host host = clusters.getHost("h1");
+
+    Map<String, Config> configs = new HashMap<String, Config>();
+    Map<String, Host> hosts = new HashMap<String, Host>();
+
+    configs.put(config.getType(), config);
+    hosts.put(host.getHostName(), host);
+
+    ConfigGroup configGroup = configGroupFactory.createNew(cluster, "cg-test",
+      "HDFS", "New HDFS configs for h1", configs, hosts);
+
+    configGroup.persist();
+    return configGroup;
+  }
+
+  @Test
+  public void testCreateNewConfigGroup() throws Exception {
+    ConfigGroup configGroup = createConfigGroup();
+    Assert.assertNotNull(configGroup);
+
+    ConfigGroupEntity configGroupEntity = configGroupDAO.findByName("cg-test");
+    Assert.assertNotNull(configGroupEntity);
+    Assert.assertEquals("HDFS", configGroupEntity.getTag());
+    ConfigGroupConfigMappingEntity configMappingEntity = configGroupEntity
+      .getConfigGroupConfigMappingEntities().iterator().next();
+    Assert.assertNotNull(configMappingEntity);
+    Assert.assertEquals("hdfs-site", configMappingEntity.getConfigType());
+    Assert.assertEquals("testversion", configMappingEntity.getVersionTag());
+    Assert.assertNotNull(configMappingEntity.getClusterConfigEntity());
+    Assert.assertTrue(configMappingEntity
+      .getClusterConfigEntity().getData().contains("a"));
+    ConfigGroupHostMappingEntity hostMappingEntity = configGroupEntity
+      .getConfigGroupHostMappingEntities().iterator().next();
+    Assert.assertNotNull(hostMappingEntity);
+    Assert.assertEquals("h1", hostMappingEntity.getHostname());
+  }
+
+  @Test
+  @Transactional
+  public void testUpdateConfigGroup() throws Exception {
+    ConfigGroup configGroup = createConfigGroup();
+    Assert.assertNotNull(configGroup);
+    ConfigGroupEntity configGroupEntity = configGroupDAO.findById(configGroup.getId());
+    Assert.assertNotNull(configGroupEntity);
+
+    configGroup = configGroupFactory.createExisting(cluster, configGroupEntity);
+
+    // Add new host
+    Host host = clusters.getHost("h2");
+    configGroup.addHost(host);
+    Assert.assertEquals(2, configGroup.getHosts().values().size());
+
+    // Create a new config
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put("key1", "value1");
+    Config config = new ConfigImpl("test-site");
+    config.setProperties(properties);
+    config.setVersionTag("version100");
+
+    configGroup.addConfiguration(config);
+    Assert.assertEquals(2, configGroup.getConfigurations().values().size());
+
+    configGroup.setName("NewName");
+    configGroup.setDescription("NewDesc");
+    configGroup.setTag("NewTag");
+
+    // Save
+    configGroup.persist();
+
+    configGroupEntity = configGroupDAO.findByName("NewName");
+
+    Assert.assertNotNull(configGroupEntity);
+    Assert.assertEquals(2, configGroupEntity
+      .getConfigGroupHostMappingEntities().size());
+    Assert.assertEquals(2, configGroupEntity
+      .getConfigGroupConfigMappingEntities().size());
+    Assert.assertEquals("NewTag", configGroupEntity.getTag());
+    Assert.assertEquals("NewDesc", configGroupEntity.getDescription());
+
+    Assert.assertNotNull(cluster.getConfig("test-site", "version100"));
+  }
+
+  @Test
+  public void testDeleteConfigGroup() throws Exception {
+    ConfigGroup configGroup = createConfigGroup();
+    Assert.assertNotNull(configGroup);
+    Long id = configGroup.getId();
+
+    configGroup.delete();
+
+    Assert.assertNull(configGroupDAO.findById(id));
+    Assert.assertNull(cluster.getConfigGroups().get(id));
+  }
+
+  @Test
+  public void testGetConfigGroup() throws Exception {
+    ConfigGroup configGroup = createConfigGroup();
+    Assert.assertNotNull(configGroup);
+    Assert.assertNotNull(cluster.getConfigGroups().get(configGroup.getId()));
+
+    ConfigGroupEntity configGroupEntity = configGroupDAO.findById(configGroup
+      .getId());
+    Collection<ConfigGroupConfigMappingEntity> configMappingEntities =
+      configGroupEntity.getConfigGroupConfigMappingEntities();
+    Collection<ConfigGroupHostMappingEntity> hostMappingEntities =
+      configGroupEntity.getConfigGroupHostMappingEntities();
+
+    Assert.assertEquals(configGroup.getId(), configGroupEntity.getGroupId());
+    Assert.assertEquals(configGroup.getTag(), configGroupEntity.getTag());
+    Assert.assertNotNull(configMappingEntities);
+    Assert.assertNotNull(hostMappingEntities);
+    Assert.assertEquals("h1", hostMappingEntities.iterator().next()
+      .getHostname());
+    ConfigGroupConfigMappingEntity configMappingEntity =
+      configMappingEntities.iterator().next();
+    Assert.assertEquals("hdfs-site", configMappingEntity.getConfigType());
+    Assert.assertEquals("testversion", configMappingEntity.getVersionTag());
+  }
+}


Mime
View raw message