AMBARI-19130 - Downgrade Can Create Multiple Mappings For Latest Configs (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/facfa8ce Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/facfa8ce Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/facfa8ce Branch: refs/heads/branch-feature-AMBARI-18901 Commit: facfa8cea364370434f9e3596147801d73c0d1f0 Parents: 82f9401 Author: Jonathan Hurley <[email protected]> Authored: Wed Dec 7 20:55:38 2016 -0500 Committer: Jonathan Hurley <[email protected]> Committed: Thu Dec 8 17:35:18 2016 -0500 ---------------------------------------------------------------------- .../entities/ClusterConfigMappingEntity.java | 20 ++- .../server/state/cluster/ClusterImpl.java | 104 +++++++++----- .../server/orm/dao/ServiceConfigDAOTest.java | 144 +++++++++---------- .../server/state/cluster/ClusterTest.java | 95 ++++++++++++ 4 files changed, 253 insertions(+), 110 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/facfa8ce/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java index 04c6030..5748dc9 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigMappingEntity.java @@ -27,15 +27,17 @@ import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; +import com.google.common.base.Objects; + /** * Entity that maps to a cluster config mapping. */ -@Table(name = "clusterconfigmapping") @Entity +@Table(name = "clusterconfigmapping") @IdClass(ClusterConfigMappingEntityPK.class) -@NamedQueries({ - @NamedQuery(name = "ClusterConfigMappingEntity.findLatestClusterConfigMappingsByType", - query = "SELECT mapping FROM ClusterConfigMappingEntity mapping WHERE mapping.clusterId = :clusterId AND mapping.selectedInd > 0 AND mapping.typeName = :typeName")}) +@NamedQueries({ @NamedQuery( + name = "ClusterConfigMappingEntity.findLatestClusterConfigMappingsByType", + query = "SELECT mapping FROM ClusterConfigMappingEntity mapping WHERE mapping.clusterId = :clusterId AND mapping.selectedInd > 0 AND mapping.typeName = :typeName") }) public class ClusterConfigMappingEntity { @@ -192,4 +194,14 @@ public class ClusterConfigMappingEntity { return true; } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this).add("clusterId", clusterId).add("type", typeName).add("tag", + tag).add("selected", selectedInd).add("created", createTimestamp).toString(); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/facfa8ce/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 649fe38..b62c834 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 @@ -22,6 +22,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -144,8 +145,10 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; @@ -3072,6 +3075,7 @@ public class ClusterImpl implements Cluster { * {@inheritDoc} */ @Override + @Transactional public void applyLatestConfigurations(StackId stackId) { clusterGlobalLock.writeLock().lock(); @@ -3079,36 +3083,33 @@ public class ClusterImpl implements Cluster { ClusterEntity clusterEntity = getClusterEntity(); Collection<ClusterConfigMappingEntity> configMappingEntities = clusterEntity.getConfigMappingEntities(); + // hash them for easier retrieval later - these are the same entity + // instances which exist on the cluster entity, so modification of the CCM + // entity here will affect the cluster CCM entities as well + ImmutableMap<Object, ClusterConfigMappingEntity> ccmMap = Maps.uniqueIndex(configMappingEntities, Functions.identity()); + // disable all configs for (ClusterConfigMappingEntity e : configMappingEntities) { LOG.debug("{} with tag {} is unselected", e.getType(), e.getTag()); e.setSelected(0); } - List<ClusterConfigMappingEntity> clusterConfigMappingsForStack = clusterDAO.getClusterConfigMappingsByStack( + // work through the in-memory list, finding only the most recent mapping per type + Collection<ClusterConfigMappingEntity> latestConfigMappingByStack = getLatestConfigMappingsForStack( clusterEntity.getClusterId(), stackId); - Collection<ClusterConfigMappingEntity> latestConfigMappingByStack = getLatestConfigMapping( - clusterConfigMappingsForStack); - - // loop through all configs and set the latest to enabled for the - // specified stack - for(ClusterConfigMappingEntity configMappingEntity: configMappingEntities){ - String type = configMappingEntity.getType(); - String tag = configMappingEntity.getTag(); + for( ClusterConfigMappingEntity latestConfigMapping : latestConfigMappingByStack ){ + ClusterConfigMappingEntity mapping = ccmMap.get(latestConfigMapping); + mapping.setSelected(1); - for (ClusterConfigMappingEntity latest : latestConfigMappingByStack) { - String latestType = latest.getType(); - String latestTag = latest.getTag(); - - // find the latest config of a given mapping entity - if (StringUtils.equals(type, latestType) && StringUtils.equals(tag, latestTag)) { - LOG.info("{} with version tag {} is selected for stack {}", type, tag, stackId.toString()); - configMappingEntity.setSelected(1); - } - } + LOG.info("Settting {} with version tag {} created on {} to selected for stack {}", + mapping.getType(), mapping.getTag(), new Date(mapping.getCreateTimestamp()), + stackId.toString()); } + // since the entities which were modified came from the cluster entity's + // list to begin with, we can just save them right back - no need for a + // new collection since the CCM entity instances were modified directly clusterEntity.setConfigMappingEntities(configMappingEntities); clusterEntity = clusterDAO.merge(clusterEntity); clusterDAO.mergeConfigMappings(configMappingEntities); @@ -3130,23 +3131,60 @@ public class ClusterImpl implements Cluster { jpaEventPublisher.publish(event); } - public Collection<ClusterConfigMappingEntity> getLatestConfigMapping(List<ClusterConfigMappingEntity> clusterConfigMappingEntities){ - Map<String, ClusterConfigMappingEntity> temp = new HashMap<String, ClusterConfigMappingEntity>(); - for (ClusterConfigMappingEntity e : clusterConfigMappingEntities) { - String type = e.getType(); - if(temp.containsKey(type)){ - ClusterConfigMappingEntity entityStored = temp.get(type); - Long timestampStored = entityStored.getCreateTimestamp(); - Long timestamp = e.getCreateTimestamp(); - if(timestamp > timestampStored){ - temp.put(type, e); //find a newer config for the given type - } - } else { - temp.put(type, e); //first time encounter a type, add it + /** + * Retrieves all of the configuration mappings (selected and unselected) for + * the specified stack and then iterates through them, returning the most + * recent mapping for every type/tag combination. + * <p/> + * Because of how configuration revert works, mappings can be created for the + * same type/tag combinations. The only difference being that the timestamp + * reflects when each mapping was created. + * <p/> + * JPQL cannot be used directly here easily because some databases cannot + * support the necessary grouping and IN clause. For example: <br/> + * + * <pre> + * SELECT mapping FROM clusterconfigmappingentity mapping + * WHERE (mapping.typename, mapping.createtimestamp) IN + * (SELECT latest.typename, MAX(latest.createtimestamp) + * FROM clusterconfigmappingentity latest + * GROUP BY latest.typename) + * </pre> + * + * @param clusterId + * the cluster ID + * @param stackId + * the stack to retrieve the mappings for (not {@code null}). + * @return the most recent mapping (selected or unselected) for the specified + * stack for every type. + */ + public Collection<ClusterConfigMappingEntity> getLatestConfigMappingsForStack(long clusterId, + StackId stackId) { + + // get all mappings for the specified stack (which could include + // duplicates since a config revert creates a duplicate mapping with a + // different timestamp) + List<ClusterConfigMappingEntity> clusterConfigMappingsForStack = clusterDAO.getClusterConfigMappingsByStack( + clusterId, stackId); + + Map<String, ClusterConfigMappingEntity> latestMappingsByType = new HashMap<String, ClusterConfigMappingEntity>(); + for (ClusterConfigMappingEntity mapping : clusterConfigMappingsForStack) { + String type = mapping.getType(); + + if (!latestMappingsByType.containsKey(type)) { + latestMappingsByType.put(type, mapping); + continue; + } + + ClusterConfigMappingEntity entityStored = latestMappingsByType.get(type); + Long timestampStored = entityStored.getCreateTimestamp(); + Long timestamp = mapping.getCreateTimestamp(); + if (timestamp > timestampStored) { + latestMappingsByType.put(type, mapping); } } - return temp.values(); + return latestMappingsByType.values(); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/facfa8ce/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/ServiceConfigDAOTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/ServiceConfigDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/ServiceConfigDAOTest.java index 2388c11..aafe557 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/ServiceConfigDAOTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/ServiceConfigDAOTest.java @@ -17,15 +17,11 @@ */ package org.apache.ambari.server.orm.dao; -import static org.easymock.EasyMock.createMockBuilder; - import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; -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; @@ -40,9 +36,12 @@ import org.apache.ambari.server.orm.entities.ResourceTypeEntity; import org.apache.ambari.server.orm.entities.ServiceConfigEntity; import org.apache.ambari.server.orm.entities.StackEntity; import org.apache.ambari.server.security.authorization.ResourceType; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.cluster.ClusterImpl; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -393,7 +392,7 @@ public class ServiceConfigDAOTest { serviceConfigs = serviceConfigDAO.getLatestServiceConfigs(clusterId, HDP_02); Assert.assertEquals(2, serviceConfigs.size()); } - + @Test public void testConfiguration() throws Exception{ initClusterEntities(); @@ -401,17 +400,17 @@ public class ServiceConfigDAOTest { Assert.assertTrue(!clusterEntity.getClusterConfigEntities().isEmpty()); Assert.assertTrue(!clusterEntity.getConfigMappingEntities().isEmpty()); - + Assert.assertEquals(5, clusterEntity.getClusterConfigEntities().size()); Assert.assertEquals(3, clusterEntity.getConfigMappingEntities().size()); } - + @Test public void testGetClusterConfigMappingByStack() throws Exception{ initClusterEntities(); - + ClusterEntity clusterEntity = clusterDAO.findByName("c1"); - + List<ClusterConfigMappingEntity> clusterConfigMappingEntities = clusterDAO.getClusterConfigMappingsByStack(clusterEntity.getClusterId(), HDP_01); Assert.assertEquals(2, clusterConfigMappingEntities .size()); @@ -420,14 +419,14 @@ public class ServiceConfigDAOTest { Assert.assertEquals("version1", tag1); String type1 = e1.getType(); Assert.assertEquals("oozie-site", type1); - + ClusterConfigMappingEntity e2 = clusterConfigMappingEntities.get(1); String tag2 = e2.getTag(); Assert.assertEquals("version2", tag2); String type2 = e2.getType(); Assert.assertEquals("oozie-site", type2); } - + /** * Test the get latest configuration query against clusterconfig table with configuration groups inserted * */ @@ -435,9 +434,9 @@ public class ServiceConfigDAOTest { public void testGetClusterConfigMappingByStackCG() throws Exception{ initClusterEntitiesWithConfigGroups(); ClusterEntity clusterEntity = clusterDAO.findByName("c1"); - + List<ConfigGroupEntity> configGroupEntities = configGroupDAO.findAllByTag("OOZIE"); - + Assert.assertNotNull(configGroupEntities); ConfigGroupEntity configGroupEntity = configGroupEntities.get(0); Assert.assertNotNull(configGroupEntity); @@ -447,7 +446,7 @@ public class ServiceConfigDAOTest { Assert.assertEquals("oozie_server", configGroupEntity.getGroupName()); Assert.assertEquals("OOZIE", configGroupEntity.getTag()); Assert.assertEquals("oozie server", configGroupEntity.getDescription()); - + List<ClusterConfigMappingEntity> clusterConfigMappingEntities = clusterDAO.getClusterConfigMappingsByStack(clusterEntity.getClusterId(), HDP_01); Assert.assertEquals(2, clusterConfigMappingEntities .size()); @@ -456,97 +455,95 @@ public class ServiceConfigDAOTest { Assert.assertEquals("version1", tag1); String type1 = e1.getType(); Assert.assertEquals("oozie-site", type1); - + ClusterConfigMappingEntity e2 = clusterConfigMappingEntities.get(1); String tag2 = e2.getTag(); Assert.assertEquals("version2", tag2); String type2 = e2.getType(); Assert.assertEquals("oozie-site", type2); } - + /** - * Test + * Test * - * When the last configuration of a given configuration type to be stored into the clusterconfig table is + * When the last configuration of a given configuration type to be stored into the clusterconfig table is * for a configuration group, there is no corresponding entry generated in the clusterconfigmapping. * * Therefore, the getlatestconfiguration query should skip configuration groups stored in the clusterconfig table. * - * Test to determine the latest configuration of a given type whose version_tag + * Test to determine the latest configuration of a given type whose version_tag * exists in the clusterconfigmapping table. * * */ @Test - public void testGetLatestClusterConfigMappingByStack() throws Exception{ - ClusterImpl cluster = - createMockBuilder(ClusterImpl.class). - addMockedMethod("getSessionManager"). - addMockedMethod("getClusterName"). - addMockedMethod("getSessionAttributes"). - createMock(); - + public void testGetLatestClusterConfigMappingByStack() throws Exception { + Clusters clusters = injector.getInstance(Clusters.class); + clusters.addCluster("c1", HDP_01); + + Cluster cluster = clusters.getCluster("c1"); + initClusterEntities(); - ClusterEntity clusterEntity = clusterDAO.findByName("c1"); - List<ClusterConfigMappingEntity> clusterConfigMappingEntities = clusterDAO.getClusterConfigMappingsByStack(clusterEntity.getClusterId(), HDP_01); - Collection<ClusterConfigMappingEntity> latestMapingEntities = cluster.getLatestConfigMapping(clusterConfigMappingEntities); + + Collection<ClusterConfigMappingEntity> latestMapingEntities = ((ClusterImpl) cluster).getLatestConfigMappingsForStack( + cluster.getClusterId(), HDP_01); + Assert.assertEquals(1, latestMapingEntities.size()); for(ClusterConfigMappingEntity e: latestMapingEntities){ Assert.assertEquals("version2", e.getTag()); Assert.assertEquals("oozie-site", e.getType()); } } - + /** - * Test + * Test * - * When the last configuration of a given configuration type to be stored into the clusterconfig table is + * When the last configuration of a given configuration type to be stored into the clusterconfig table is * for a configuration group, there is no corresponding entry generated in the clusterconfigmapping. * * Therefore, the getlatestconfiguration query should skip configuration groups stored in the clusterconfig table. * - * Test to determine the latest configuration of a given type whose version_tag + * Test to determine the latest configuration of a given type whose version_tag * exists in the clusterconfigmapping table. * * */ @Test public void testGetLatestClusterConfigMappingByStackCG() throws Exception{ - ClusterImpl cluster = - createMockBuilder(ClusterImpl.class). - addMockedMethod("getSessionManager"). - addMockedMethod("getClusterName"). - addMockedMethod("getSessionAttributes"). - createMock(); - + Clusters clusters = injector.getInstance(Clusters.class); + clusters.addCluster("c1", HDP_01); + + Cluster cluster = clusters.getCluster("c1"); + initClusterEntitiesWithConfigGroups(); - ClusterEntity clusterEntity = clusterDAO.findByName("c1"); - List<ClusterConfigMappingEntity> clusterConfigMappingEntities = clusterDAO.getClusterConfigMappingsByStack(clusterEntity.getClusterId(), HDP_01); - Collection<ClusterConfigMappingEntity> latestMapingEntities = cluster.getLatestConfigMapping(clusterConfigMappingEntities); + + Collection<ClusterConfigMappingEntity> latestMapingEntities = ((ClusterImpl) cluster).getLatestConfigMappingsForStack( + cluster.getClusterId(), HDP_01); + Assert.assertEquals(1, latestMapingEntities.size()); for(ClusterConfigMappingEntity e: latestMapingEntities){ Assert.assertEquals("version2", e.getTag()); Assert.assertEquals("oozie-site", e.getType()); } } - + private void initClusterEntities() throws Exception{ String userName = "admin"; - + ServiceConfigEntity oozieServiceConfigEntity = createServiceConfig("OOZIE", userName, 1L, 1L, System.currentTimeMillis(), null); ClusterEntity clusterEntity = oozieServiceConfigEntity.getClusterEntity(); - + Long clusterId = clusterEntity.getClusterId(); - + if(null == clusterId){ clusterId = 1L; clusterEntity.setClusterId(clusterId); clusterEntity = clusterDAO.merge(clusterEntity); } - + StackEntity stackEntityHDP01 = stackDAO.find(HDP_01.getStackName(),HDP_01.getStackVersion()); StackEntity stackEntityHDP02 = stackDAO.find(HDP_02.getStackName(),HDP_02.getStackVersion()); - + String oozieSite = "oozie-site"; - + for (int i = 1; i < 6; i++){ ClusterConfigEntity entity = new ClusterConfigEntity(); entity.setClusterEntity(clusterEntity); @@ -555,22 +552,23 @@ public class ServiceConfigDAOTest { entity.setVersion(Long.valueOf(i)); entity.setTag("version"+i); entity.setTimestamp(new Date().getTime()); - if(i < 4) + if(i < 4) { entity.setStack(stackEntityHDP01); - else + } else { entity.setStack(stackEntityHDP02); + } entity.setData(""); clusterDAO.createConfig(entity); clusterEntity.getClusterConfigEntities().add(entity); clusterDAO.merge(clusterEntity); } - + Collection<ClusterConfigMappingEntity> entities = clusterEntity.getConfigMappingEntities(); if(null == entities){ entities = new ArrayList<ClusterConfigMappingEntity>(); clusterEntity.setConfigMappingEntities(entities); - } - + } + ClusterConfigMappingEntity e1 = new ClusterConfigMappingEntity(); e1.setClusterEntity(clusterEntity); e1.setClusterId(clusterEntity.getClusterId()); @@ -581,7 +579,7 @@ public class ServiceConfigDAOTest { e1.setTag("version1"); entities.add(e1); clusterDAO.merge(clusterEntity); - + ClusterConfigMappingEntity e2 = new ClusterConfigMappingEntity(); e2.setClusterEntity(clusterEntity); e2.setClusterId(clusterEntity.getClusterId()); @@ -592,7 +590,7 @@ public class ServiceConfigDAOTest { e2.setTag("version2"); entities.add(e2); clusterDAO.merge(clusterEntity); - + ClusterConfigMappingEntity e3 = new ClusterConfigMappingEntity(); e3.setClusterEntity(clusterEntity); e3.setClusterId(clusterEntity.getClusterId()); @@ -603,25 +601,25 @@ public class ServiceConfigDAOTest { e3.setTag("version4"); entities.add(e3); clusterDAO.merge(clusterEntity); - } - + } + private void initClusterEntitiesWithConfigGroups() throws Exception{ String userName = "admin"; - + ServiceConfigEntity oozieServiceConfigEntity = createServiceConfig("OOZIE", userName, 1L, 1L, System.currentTimeMillis(), null); ClusterEntity clusterEntity = oozieServiceConfigEntity.getClusterEntity(); - + Long clusterId = clusterEntity.getClusterId(); - + if(null == clusterId){ clusterId = 1L; clusterEntity.setClusterId(clusterId); clusterEntity = clusterDAO.merge(clusterEntity); } - + StackEntity stackEntityHDP01 = stackDAO.find(HDP_01.getStackName(),HDP_01.getStackVersion()); String oozieSite = "oozie-site"; - + int count = 3; for (int i = 1; i < count; i++){ ClusterConfigEntity entity = new ClusterConfigEntity(); @@ -637,13 +635,13 @@ public class ServiceConfigDAOTest { clusterEntity.getClusterConfigEntities().add(entity); clusterDAO.merge(clusterEntity); } - + Collection<ClusterConfigMappingEntity> entities = clusterEntity.getConfigMappingEntities(); if(null == entities){ entities = new ArrayList<ClusterConfigMappingEntity>(); clusterEntity.setConfigMappingEntities(entities); - } - + } + ClusterConfigMappingEntity e1 = new ClusterConfigMappingEntity(); e1.setClusterEntity(clusterEntity); e1.setClusterId(clusterEntity.getClusterId()); @@ -654,7 +652,7 @@ public class ServiceConfigDAOTest { e1.setTag("version1"); entities.add(e1); clusterDAO.merge(clusterEntity); - + ClusterConfigMappingEntity e2 = new ClusterConfigMappingEntity(); e2.setClusterEntity(clusterEntity); e2.setClusterId(clusterEntity.getClusterId()); @@ -665,7 +663,7 @@ public class ServiceConfigDAOTest { e2.setTag("version2"); entities.add(e2); clusterDAO.merge(clusterEntity); - + ConfigGroupEntity configGroupEntity = new ConfigGroupEntity(); ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findById(ResourceType.CLUSTER.getId()); @@ -695,9 +693,9 @@ public class ServiceConfigDAOTest { List<ClusterConfigEntity> configEntities = new ArrayList<ClusterConfigEntity>(); configEntities.add(configEntity); - + configGroupDAO.create(configGroupEntity); - + if (configEntities != null && !configEntities.isEmpty()) { List<ConfigGroupConfigMappingEntity> configMappingEntities = new ArrayList<ConfigGroupConfigMappingEntity>(); @@ -719,7 +717,7 @@ public class ServiceConfigDAOTest { configMappingEntities.add(configMappingEntity); configGroupConfigMappingDAO.create(configMappingEntity); } - + configGroupEntity.setConfigGroupConfigMappingEntities(configMappingEntities); configGroupDAO.merge(configGroupEntity); } http://git-wip-us.apache.org/repos/asf/ambari/blob/facfa8ce/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java index fc3646a..daa3abc 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java @@ -2467,6 +2467,101 @@ public class ClusterTest { } /** + * Tests that {@link Cluster#applyLatestConfigurations(StackId)} sets the + * right configs to enabled when there are duplicate mappings for type/tag. + * Only the most recent should be enabled. + * + * @throws Exception + */ + @Test + public void testApplyLatestConfigurationsWithMultipleMappings() throws Exception { + createDefaultCluster(); + Cluster cluster = clusters.getCluster("c1"); + ClusterEntity clusterEntity = clusterDAO.findByName("c1"); + StackId stackId = cluster.getCurrentStackVersion(); + + StackEntity currentStack = stackDAO.find(stackId.getStackName(), stackId.getStackVersion()); + + String configType = "foo-type"; + String configTag = "version-1"; + + // create the config for the mappings + ClusterConfigEntity clusterConfig = new ClusterConfigEntity(); + clusterConfig.setClusterEntity(clusterEntity); + clusterConfig.setConfigId(1L); + clusterConfig.setStack(currentStack); + clusterConfig.setTag(configTag); + clusterConfig.setData("{}"); + clusterConfig.setType(configType); + clusterConfig.setTimestamp(1L); + clusterConfig.setVersion(1L); + + clusterDAO.createConfig(clusterConfig); + clusterEntity.getClusterConfigEntities().add(clusterConfig); + clusterEntity = clusterDAO.merge(clusterEntity); + + // create 3 mappings for the same type/tag, each with a different time + + // config mapping 1 + ClusterConfigMappingEntity configMapping = new ClusterConfigMappingEntity(); + configMapping.setClusterEntity(clusterEntity); + configMapping.setCreateTimestamp(1L); + configMapping.setSelected(0); + configMapping.setTag(configTag); + configMapping.setType(configType); + configMapping.setUser("admin"); + clusterDAO.persistConfigMapping(configMapping); + clusterEntity.getConfigMappingEntities().add(configMapping); + + // config mapping 2 + configMapping = new ClusterConfigMappingEntity(); + configMapping.setClusterEntity(clusterEntity); + configMapping.setCreateTimestamp(2L); + configMapping.setSelected(0); + configMapping.setTag(configTag); + configMapping.setType(configType); + configMapping.setUser("admin"); + clusterDAO.persistConfigMapping(configMapping); + clusterEntity.getConfigMappingEntities().add(configMapping); + + // config mapping 3 + configMapping = new ClusterConfigMappingEntity(); + configMapping.setClusterEntity(clusterEntity); + configMapping.setCreateTimestamp(3L); + configMapping.setSelected(0); + configMapping.setTag(configTag); + configMapping.setType(configType); + configMapping.setUser("admin"); + clusterDAO.persistConfigMapping(configMapping); + clusterEntity.getConfigMappingEntities().add(configMapping); + + clusterEntity = clusterDAO.merge(clusterEntity); + + // check all 3 mappings are disabled + Collection<ClusterConfigMappingEntity> clusterConfigMappings = clusterEntity.getConfigMappingEntities(); + Assert.assertEquals(3, clusterConfigMappings.size()); + for (ClusterConfigMappingEntity clusterConfigMapping : clusterConfigMappings) { + Assert.assertEquals(0, clusterConfigMapping.isSelected()); + } + + // apply configurations and check to see we've set the one with the latest + // timestamp ONLY + cluster.applyLatestConfigurations(cluster.getCurrentStackVersion()); + clusterEntity = clusterDAO.findByName("c1"); + + // now check that the new config mapping is enabled + clusterConfigMappings = clusterEntity.getConfigMappingEntities(); + Assert.assertEquals(3, clusterConfigMappings.size()); + for (ClusterConfigMappingEntity clusterConfigMapping : clusterConfigMappings) { + if (clusterConfigMapping.getCreateTimestamp() < 3) { + Assert.assertEquals(0, clusterConfigMapping.isSelected()); + } else { + Assert.assertEquals(1, clusterConfigMapping.isSelected()); + } + } + } + + /** * Tests that applying configurations for a given stack correctly sets * {@link DesiredConfig}s. */
