This is an automated email from the ASF dual-hosted git repository. krisztiankasa pushed a commit to branch branch-2.7 in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.7 by this push: new 1c25b10 AMBARI-24283 - DB consistency warning due to config group without service name (#1915) (#1928) 1c25b10 is described below commit 1c25b1019b8eaa6b03882ae4ee7bdd99b9ae1d5d Author: kasakrisz <33458261+kasakr...@users.noreply.github.com> AuthorDate: Wed Aug 1 07:00:25 2018 +0200 AMBARI-24283 - DB consistency warning due to config group without service name (#1915) (#1928) --- .../checks/DatabaseConsistencyCheckHelper.java | 248 ++++++++++++++++++++ .../ambari/server/upgrade/UpgradeCatalog271.java | 44 +++- .../checks/DatabaseConsistencyCheckHelperTest.java | 257 +++++++++++++++++++++ .../server/upgrade/UpgradeCatalog271Test.java | 5 + 4 files changed, 553 insertions(+), 1 deletion(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelper.java index 669ab81..375bcd9 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelper.java @@ -36,6 +36,7 @@ import java.util.Scanner; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.inject.Provider; @@ -59,14 +60,19 @@ import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity; import org.apache.ambari.server.orm.entities.HostComponentStateEntity; import org.apache.ambari.server.orm.entities.MetainfoEntity; import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity; +import org.apache.ambari.server.security.authorization.AuthorizationException; import org.apache.ambari.server.state.ClientConfigFileDefinition; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.ComponentInfo; +import org.apache.ambari.server.state.Host; +import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.State; import org.apache.ambari.server.state.UpgradeState; +import org.apache.ambari.server.state.configgroup.ConfigGroup; import org.apache.ambari.server.utils.VersionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -181,6 +187,9 @@ public class DatabaseConsistencyCheckHelper { if (fixIssues) { fixHostComponentStatesCountEqualsHostComponentsDesiredStates(); fixClusterConfigsNotMappedToAnyService(); + fixConfigGroupServiceNames(); + fixConfigGroupHostMappings(); + fixConfigGroupsForDeletedServices(); fixConfigsSelectedMoreThanOnce(); } checkSchemaName(); @@ -191,6 +200,9 @@ public class DatabaseConsistencyCheckHelper { checkHostComponentStates(); checkServiceConfigs(); checkForLargeTables(); + checkConfigGroupsHasServiceName(); + checkConfigGroupHostMapping(true); + checkConfigGroupsForDeletedServices(true); LOG.info("******************************* Check database completed *******************************"); return checkResult; } @@ -1147,6 +1159,242 @@ public class DatabaseConsistencyCheckHelper { } + /** + * This method collects the ConfigGroups with empty or null service name field + */ + static Map<Long, ConfigGroup> collectConfigGroupsWithoutServiceName() { + Map<Long, ConfigGroup> configGroupMap = new HashMap<>(); + Clusters clusters = injector.getInstance(Clusters.class); + Map<String, Cluster> clusterMap = clusters.getClusters(); + + if (MapUtils.isEmpty(clusterMap)) + return configGroupMap; + + for (Cluster cluster : clusterMap.values()) { + Map<Long, ConfigGroup> configGroups = cluster.getConfigGroups(); + + if (MapUtils.isEmpty(configGroups)) { + continue; + } + + for (ConfigGroup configGroup : configGroups.values()) { + if (StringUtils.isEmpty(configGroup.getServiceName())) { + configGroupMap.put(configGroup.getId(), configGroup); + } + } + } + + return configGroupMap; + } + + /** + * This method checks if there are any ConfigGroup with empty or null service name field + */ + static void checkConfigGroupsHasServiceName() { + Map<Long, ConfigGroup> configGroupMap = collectConfigGroupsWithoutServiceName(); + if (MapUtils.isEmpty(configGroupMap)) + return; + + String message = String.join(" ), ( ", + configGroupMap.values().stream().map(ConfigGroup::getName).collect(Collectors.toList())); + + warning("You have config groups present in the database with no " + + "service name, [(ConfigGroup) => ( {} )]. Run --auto-fix-database to fix " + + "this automatically. Please backup Ambari Server database before running --auto-fix-database.", message); + } + + /** + * Fix inconsistencies found by @collectConfigGroupsWithoutServiceName + */ + @Transactional + static void fixConfigGroupServiceNames() { + Map<Long, ConfigGroup> configGroupMap = collectConfigGroupsWithoutServiceName(); + if (MapUtils.isEmpty(configGroupMap)) + return; + + Clusters clusters = injector.getInstance(Clusters.class); + + for (Map.Entry<Long, ConfigGroup> configGroupEntry : configGroupMap.entrySet()) { + ConfigGroup configGroup = configGroupEntry.getValue(); + try { + Cluster cluster = clusters.getCluster(configGroup.getClusterName()); + Map<String, Service> serviceMap = cluster.getServices(); + if (serviceMap.containsKey(configGroup.getTag())) { + LOG.info("Setting service name of config group {} with id {} to {}", + configGroup.getName(), configGroupEntry.getKey(), configGroup.getTag()); + configGroup.setServiceName(configGroup.getTag()); + } + else { + LOG.info("Config group {} with id {} contains a tag {} which is not a service name in the cluster {}", + configGroup.getName(), configGroupEntry.getKey(), configGroup.getTag(), cluster.getClusterName()); + } + } catch (AmbariException e) { + // Ignore if cluster not found + } + } + } + + /** + * This method checks if there are any ConfigGroup host mappings with hosts + * that are not longer a part of the cluster. + */ + static Map<Long, Set<Long>> checkConfigGroupHostMapping(boolean warnIfFound) { + LOG.info("Checking config group host mappings"); + Map<Long, Set<Long>> nonMappedHostIds = new HashMap<>(); + Clusters clusters = injector.getInstance(Clusters.class); + Map<String, Cluster> clusterMap = clusters.getClusters(); + StringBuilder output = new StringBuilder("[(ConfigGroup, Service, HostCount) => "); + + if (!MapUtils.isEmpty(clusterMap)) { + for (Cluster cluster : clusterMap.values()) { + Map<Long, ConfigGroup> configGroups = cluster.getConfigGroups(); + Map<String, Host> clusterHosts = clusters.getHostsForCluster(cluster.getClusterName()); + + if (!MapUtils.isEmpty(configGroups) && !MapUtils.isEmpty(clusterHosts)) { + for (ConfigGroup configGroup : configGroups.values()) { + // Based on current implementation of ConfigGroupImpl the + // host mapping would be loaded only if the host actually exists + // in the host table + Map<Long, Host> hosts = configGroup.getHosts(); + boolean addToOutput = false; + Set<String> hostnames = new HashSet<>(); + if (!MapUtils.isEmpty(hosts)) { + for (Host host : hosts.values()) { + // Lookup by hostname - It does have a unique constraint + if (!clusterHosts.containsKey(host.getHostName())) { + Set<Long> hostIds = nonMappedHostIds.computeIfAbsent(configGroup.getId(), configGroupId -> new HashSet<>()); + hostIds.add(host.getHostId()); + hostnames.add(host.getHostName()); + addToOutput = true; + } + } + } + if (addToOutput) { + output.append("( "); + output.append(configGroup.getName()); + output.append(", "); + output.append(configGroup.getTag()); + output.append(", "); + output.append(hostnames); + output.append(" ), "); + } + } + } + } + } + if (!MapUtils.isEmpty(nonMappedHostIds) && warnIfFound) { + output.replace(output.lastIndexOf(","), output.length(), "]"); + warning("You have config group host mappings with hosts that are no " + + "longer associated with the cluster, {}. Run --auto-fix-database to " + + "fix this automatically. Alternatively, you can remove this mapping " + + "from the UI. Please backup Ambari Server database before running --auto-fix-database.", output.toString()); + } + + return nonMappedHostIds; + } + + static Map<Long, ConfigGroup> checkConfigGroupsForDeletedServices(boolean warnIfFound) { + Map<Long, ConfigGroup> configGroupMap = new HashMap<>(); + Clusters clusters = injector.getInstance(Clusters.class); + Map<String, Cluster> clusterMap = clusters.getClusters(); + StringBuilder output = new StringBuilder("[(ConfigGroup, Service) => "); + + if (!MapUtils.isEmpty(clusterMap)) { + for (Cluster cluster : clusterMap.values()) { + Map<Long, ConfigGroup> configGroups = cluster.getConfigGroups(); + Map<String, Service> services = cluster.getServices(); + + if (!MapUtils.isEmpty(configGroups)) { + for (ConfigGroup configGroup : configGroups.values()) { + if (!services.containsKey(configGroup.getServiceName())) { + configGroupMap.put(configGroup.getId(), configGroup); + output.append("( "); + output.append(configGroup.getName()); + output.append(", "); + output.append(configGroup.getServiceName()); + output.append(" ), "); + } + } + } + } + } + + if (warnIfFound && !configGroupMap.isEmpty()) { + output.replace(output.lastIndexOf(","), output.length(), "]"); + warning("You have config groups present in the database with no " + + "corresponding service found, {}. Run --auto-fix-database to fix " + + "this automatically. Please backup Ambari Server database before running --auto-fix-database.", output.toString()); + } + + return configGroupMap; + } + + @Transactional + static void fixConfigGroupsForDeletedServices() { + Map<Long, ConfigGroup> configGroupMap = checkConfigGroupsForDeletedServices(false); + Clusters clusters = injector.getInstance(Clusters.class); + + if (!MapUtils.isEmpty(configGroupMap)) { + for (Map.Entry<Long, ConfigGroup> configGroupEntry : configGroupMap.entrySet()) { + Long id = configGroupEntry.getKey(); + ConfigGroup configGroup = configGroupEntry.getValue(); + if (!StringUtils.isEmpty(configGroup.getServiceName())) { + LOG.info("Deleting config group {} with id {} for deleted service {}", + configGroup.getName(), id, configGroup.getServiceName()); + try { + Cluster cluster = clusters.getCluster(configGroup.getClusterName()); + cluster.deleteConfigGroup(id); + } catch (AuthorizationException e) { + // This call does not thrown Authorization Exception + } catch (AmbariException e) { + // Ignore if cluster not found + } + } + else { + warning("The config group {} with id {} can not be fixed automatically because service name is missing.", + configGroup.getName(), id); + } + } + } + } + + /** + * Fix inconsistencies found by @checkConfigGroupHostMapping + */ + @Transactional + static void fixConfigGroupHostMappings() { + Map<Long, Set<Long>> nonMappedHostIds = checkConfigGroupHostMapping(false); + Clusters clusters = injector.getInstance(Clusters.class); + + if (!MapUtils.isEmpty(nonMappedHostIds)) { + LOG.info("Fixing {} config groups with inconsistent host mappings", nonMappedHostIds.size()); + + for (Map.Entry<Long, Set<Long>> nonMappedHostEntry : nonMappedHostIds.entrySet()) { + if (!MapUtils.isEmpty(clusters.getClusters())) { + for (Cluster cluster : clusters.getClusters().values()) { + Map<Long, ConfigGroup> configGroups = cluster.getConfigGroups(); + if (!MapUtils.isEmpty(configGroups)) { + ConfigGroup configGroup = configGroups.get(nonMappedHostEntry.getKey()); + if (configGroup != null) { + for (Long hostId : nonMappedHostEntry.getValue()) { + try { + configGroup.removeHost(hostId); + } catch (AmbariException e) { + LOG.warn("Unable to fix inconsistency by removing host " + + "mapping for config group: {}, service: {}, hostId = {}", + configGroup.getName(), configGroup.getTag(), hostId); + } + } + } else { + LOG.warn("Unable to find config group with id = {}", nonMappedHostEntry.getKey()); + } + } + } + } + } + } + } + private static void ensureConnection() { if (connection == null) { if (dbAccessor == null) { diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog271.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog271.java index c8a4d99..010ab62 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog271.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog271.java @@ -17,6 +17,9 @@ */ package org.apache.ambari.server.upgrade; +import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_NEW_NAME; +import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_OLD_NAME; + import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -24,13 +27,17 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; + import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.orm.dao.DaoUtils; +import org.apache.ambari.server.orm.entities.ServiceConfigEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.Config; - +import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,6 +104,7 @@ public class UpgradeCatalog271 extends AbstractUpgradeCatalog { addNewConfigurationsFromXml(); updateRangerLogDirConfigs(); updateRangerKmsDbUrl(); + renameAmbariInfraInConfigGroups(); } /** @@ -195,4 +203,38 @@ public class UpgradeCatalog271 extends AbstractUpgradeCatalog { } } + protected void renameAmbariInfraInConfigGroups() { + LOG.info("Renaming service AMBARI_INFRA to AMBARI_INFRA_SOLR in config group records"); + AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class); + Clusters clusters = ambariManagementController.getClusters(); + if (clusters == null) + return; + + Map<String, Cluster> clusterMap = clusters.getClusters(); + if (MapUtils.isEmpty(clusterMap)) + return; + + EntityManager entityManager = getEntityManagerProvider().get(); + + executeInTransaction(() -> { + TypedQuery<ServiceConfigEntity> serviceConfigUpdate = entityManager.createQuery( + "UPDATE ConfigGroupEntity SET serviceName = :newServiceName WHERE serviceName = :oldServiceName", ServiceConfigEntity.class); + serviceConfigUpdate.setParameter("newServiceName", AMBARI_INFRA_NEW_NAME); + serviceConfigUpdate.setParameter("oldServiceName", AMBARI_INFRA_OLD_NAME); + serviceConfigUpdate.executeUpdate(); + }); + + executeInTransaction(() -> { + TypedQuery<ServiceConfigEntity> serviceConfigUpdate = entityManager.createQuery( + "UPDATE ConfigGroupEntity SET tag = :newServiceName WHERE tag = :oldServiceName", ServiceConfigEntity.class); + serviceConfigUpdate.setParameter("newServiceName", AMBARI_INFRA_NEW_NAME); + serviceConfigUpdate.setParameter("oldServiceName", AMBARI_INFRA_OLD_NAME); + serviceConfigUpdate.executeUpdate(); + }); + + + // Force the clusters object to reload to ensure the renamed service is accounted for + entityManager.getEntityManagerFactory().getCache().evictAll(); + clusters.invalidateAllClusters(); + } } \ No newline at end of file diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelperTest.java index 91b18e1..e38b24f 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/DatabaseConsistencyCheckHelperTest.java @@ -40,6 +40,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; @@ -52,9 +53,13 @@ import org.apache.ambari.server.orm.entities.ClusterConfigEntity; import org.apache.ambari.server.stack.StackManagerFactory; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.Host; +import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.server.state.configgroup.ConfigGroup; import org.apache.ambari.server.state.stack.OsFamily; import org.apache.ambari.server.testutils.PartialNiceMockBinder; +import org.apache.commons.collections.MapUtils; import org.easymock.EasyMockSupport; import org.junit.Assert; import org.junit.Test; @@ -523,6 +528,258 @@ public class DatabaseConsistencyCheckHelperTest { } @Test + public void testConfigGroupHostMappings() throws Exception { + EasyMockSupport easyMockSupport = new EasyMockSupport(); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + + final StackManagerFactory mockStackManagerFactory = easyMockSupport.createNiceMock(StackManagerFactory.class); + final EntityManager mockEntityManager = easyMockSupport.createNiceMock(EntityManager.class); + final Clusters mockClusters = easyMockSupport.createNiceMock(Clusters.class); + final OsFamily mockOSFamily = easyMockSupport.createNiceMock(OsFamily.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(StackManagerFactory.class).toInstance(mockStackManagerFactory); + bind(EntityManager.class).toInstance(mockEntityManager); + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(Clusters.class).toInstance(mockClusters); + bind(OsFamily.class).toInstance(mockOSFamily); + } + }); + + Map<String, Cluster> clusters = new HashMap<>(); + Cluster cluster = easyMockSupport.createNiceMock(Cluster.class); + clusters.put("c1", cluster); + expect(mockClusters.getClusters()).andReturn(clusters).anyTimes(); + + Map<Long, ConfigGroup> configGroupMap = new HashMap<>(); + ConfigGroup cg1 = easyMockSupport.createNiceMock(ConfigGroup.class); + ConfigGroup cg2 = easyMockSupport.createNiceMock(ConfigGroup.class); + configGroupMap.put(1L, cg1); + configGroupMap.put(2L, cg2); + + expect(cluster.getConfigGroups()).andReturn(configGroupMap).anyTimes(); + + expect(cluster.getClusterName()).andReturn("c1").anyTimes(); + + Map<String, Host> hosts = new HashMap<>(); + Host h1 = easyMockSupport.createNiceMock(Host.class); + Host h2 = easyMockSupport.createNiceMock(Host.class); + hosts.put("h1", h1); + expect(mockClusters.getHostsForCluster("c1")).andReturn(hosts); + + Map<Long, Host> cgHosts = new HashMap<>(); + cgHosts.put(1L, h1); + cgHosts.put(2L, h2); + + expect(cg1.getHosts()).andReturn(cgHosts); + + expect(h1.getHostName()).andReturn("h1").anyTimes(); + expect(h2.getHostName()).andReturn("h2").anyTimes() ; + expect(h1.getHostId()).andReturn(1L).anyTimes(); + expect(h2.getHostId()).andReturn(2L).anyTimes(); + + expect(cg1.getId()).andReturn(1L).anyTimes(); + expect(cg2.getId()).andReturn(2L).anyTimes(); + expect(cg1.getName()).andReturn("cg1").anyTimes(); + expect(cg2.getName()).andReturn("cg2").anyTimes(); + + DatabaseConsistencyCheckHelper.setInjector(mockInjector); + + easyMockSupport.replayAll(); + + Map<Long, Set<Long>> hostIds = DatabaseConsistencyCheckHelper.checkConfigGroupHostMapping(true); + + easyMockSupport.verifyAll(); + + Assert.assertNotNull(hostIds); + Assert.assertEquals(1, hostIds.size()); + Assert.assertEquals(1L, hostIds.keySet().iterator().next().longValue()); + Assert.assertEquals(2L, hostIds.get(1L).iterator().next().longValue()); + } + + @Test + public void testConfigGroupForDeletedServices() throws Exception { + EasyMockSupport easyMockSupport = new EasyMockSupport(); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + + final StackManagerFactory mockStackManagerFactory = easyMockSupport.createNiceMock(StackManagerFactory.class); + final EntityManager mockEntityManager = easyMockSupport.createNiceMock(EntityManager.class); + final Clusters mockClusters = easyMockSupport.createNiceMock(Clusters.class); + final OsFamily mockOSFamily = easyMockSupport.createNiceMock(OsFamily.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(StackManagerFactory.class).toInstance(mockStackManagerFactory); + bind(EntityManager.class).toInstance(mockEntityManager); + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(Clusters.class).toInstance(mockClusters); + bind(OsFamily.class).toInstance(mockOSFamily); + } + }); + + Map<String, Cluster> clusters = new HashMap<>(); + Cluster cluster = easyMockSupport.createStrictMock(Cluster.class); + clusters.put("c1", cluster); + expect(mockClusters.getClusters()).andReturn(clusters).anyTimes(); + + Map<Long, ConfigGroup> configGroupMap = new HashMap<>(); + ConfigGroup cg1 = easyMockSupport.createNiceMock(ConfigGroup.class); + ConfigGroup cg2 = easyMockSupport.createNiceMock(ConfigGroup.class); + ConfigGroup cgWithoutServiceName = easyMockSupport.createNiceMock(ConfigGroup.class); + configGroupMap.put(1L, cg1); + configGroupMap.put(2L, cg2); + configGroupMap.put(3L, cgWithoutServiceName); + + expect(cluster.getConfigGroups()).andStubReturn(configGroupMap); + expect(cg1.getName()).andReturn("cg1").anyTimes(); + expect(cg1.getId()).andReturn(1L).anyTimes(); + expect(cg1.getServiceName()).andReturn("YARN").anyTimes(); + expect(cg2.getServiceName()).andReturn("HDFS").anyTimes(); + expect(cgWithoutServiceName.getName()).andReturn("cg3").anyTimes(); + expect(cgWithoutServiceName.getId()).andReturn(3L).anyTimes(); + expect(cgWithoutServiceName.getServiceName()).andReturn(null).anyTimes(); + + Service service = easyMockSupport.createNiceMock(Service.class); + Map<String, Service> services = new HashMap<>(); + services.put("HDFS", service); + expect(cluster.getServices()).andReturn(services).anyTimes(); + + expect(cg1.getClusterName()).andReturn("c1"); + expect(mockClusters.getCluster("c1")).andReturn(cluster).anyTimes(); + cluster.deleteConfigGroup(1L); + expectLastCall(); + + DatabaseConsistencyCheckHelper.setInjector(mockInjector); + + easyMockSupport.replayAll(); + + Map<Long, ConfigGroup> configGroups = DatabaseConsistencyCheckHelper.checkConfigGroupsForDeletedServices(true); + DatabaseConsistencyCheckHelper.fixConfigGroupsForDeletedServices(); + + easyMockSupport.verifyAll(); + + Assert.assertFalse(MapUtils.isEmpty(configGroups)); + Assert.assertEquals(2, configGroups.size()); + Assert.assertTrue(configGroups.containsKey(1L)); + Assert.assertFalse(configGroups.containsKey(2L)); + Assert.assertTrue(configGroups.containsKey(3L)); + } + + @Test + public void testCollectConfigGroupsWithoutServiceName() throws Exception { + EasyMockSupport easyMockSupport = new EasyMockSupport(); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + + final StackManagerFactory mockStackManagerFactory = easyMockSupport.createNiceMock(StackManagerFactory.class); + final EntityManager mockEntityManager = easyMockSupport.createNiceMock(EntityManager.class); + final Clusters mockClusters = easyMockSupport.createNiceMock(Clusters.class); + final OsFamily mockOSFamily = easyMockSupport.createNiceMock(OsFamily.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(StackManagerFactory.class).toInstance(mockStackManagerFactory); + bind(EntityManager.class).toInstance(mockEntityManager); + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(Clusters.class).toInstance(mockClusters); + bind(OsFamily.class).toInstance(mockOSFamily); + } + }); + + Map<String, Cluster> clusters = new HashMap<>(); + Cluster cluster1 = easyMockSupport.createNiceMock(Cluster.class); + clusters.put("c1", cluster1); + Cluster cluster2 = easyMockSupport.createNiceMock(Cluster.class); + clusters.put("c2", cluster2); + expect(cluster2.getConfigGroups()).andReturn(new HashMap<Long, ConfigGroup>(0)).anyTimes(); + expect(mockClusters.getClusters()).andReturn(clusters).anyTimes(); + expect(mockClusters.getCluster("c1")).andReturn(cluster1).anyTimes(); + expect(mockClusters.getCluster("c2")).andReturn(cluster2).anyTimes(); + + Map<Long, ConfigGroup> configGroupMap = new HashMap<>(); + ConfigGroup cgWithoutServiceName = easyMockSupport.createNiceMock(ConfigGroup.class); + ConfigGroup cgWithServiceName = easyMockSupport.createNiceMock(ConfigGroup.class); + ConfigGroup cgForNonExistentService = easyMockSupport.createNiceMock(ConfigGroup.class); + configGroupMap.put(1L, cgWithoutServiceName); + configGroupMap.put(2L, cgWithServiceName); + configGroupMap.put(3L, cgForNonExistentService); + + expect(cluster1.getConfigGroups()).andReturn(configGroupMap).anyTimes(); + expect(cgWithoutServiceName.getId()).andReturn(1L).anyTimes(); + expect(cgWithoutServiceName.getClusterName()).andReturn("c1").anyTimes(); + expect(cgWithoutServiceName.getServiceName()).andReturn(null).anyTimes(); + expect(cgWithoutServiceName.getTag()).andReturn("YARN").anyTimes(); + cgWithoutServiceName.setServiceName("YARN"); expectLastCall(); + expect(cgWithServiceName.getId()).andReturn(2L).anyTimes(); + expect(cgWithServiceName.getClusterName()).andReturn("c1").anyTimes(); + expect(cgWithServiceName.getServiceName()).andReturn("HDFS").anyTimes(); + expect(cgForNonExistentService.getId()).andReturn(3L).anyTimes(); + expect(cgForNonExistentService.getClusterName()).andReturn("c1").anyTimes(); + expect(cgForNonExistentService.getServiceName()).andReturn(null).anyTimes(); + expect(cgForNonExistentService.getTag()).andReturn("NOT_EXISTS").anyTimes(); + + Service hdfsService = easyMockSupport.createNiceMock(Service.class); + Service yarnService = easyMockSupport.createNiceMock(Service.class); + Map<String, Service> services = new HashMap<>(); + services.put("HDFS", hdfsService); + services.put("YARN", yarnService); + expect(cluster1.getServices()).andReturn(services).anyTimes(); + + DatabaseConsistencyCheckHelper.setInjector(mockInjector); + + easyMockSupport.replayAll(); + + Map<Long, ConfigGroup> configGroups = DatabaseConsistencyCheckHelper.collectConfigGroupsWithoutServiceName(); + DatabaseConsistencyCheckHelper.fixConfigGroupServiceNames(); + + easyMockSupport.verifyAll(); + + Assert.assertFalse(MapUtils.isEmpty(configGroups)); + Assert.assertEquals(2, configGroups.size()); + Assert.assertTrue(configGroups.containsKey(1L)); + Assert.assertFalse(configGroups.containsKey(2L)); + Assert.assertTrue(configGroups.containsKey(3L)); + } + + @Test + public void testCollectConfigGroupsWithoutServiceNameReturnsEmptyMapWhenNoClusters() throws Exception { + EasyMockSupport easyMockSupport = new EasyMockSupport(); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + + final StackManagerFactory mockStackManagerFactory = easyMockSupport.createNiceMock(StackManagerFactory.class); + final EntityManager mockEntityManager = easyMockSupport.createNiceMock(EntityManager.class); + final Clusters mockClusters = easyMockSupport.createNiceMock(Clusters.class); + final OsFamily mockOSFamily = easyMockSupport.createNiceMock(OsFamily.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(StackManagerFactory.class).toInstance(mockStackManagerFactory); + bind(EntityManager.class).toInstance(mockEntityManager); + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(Clusters.class).toInstance(mockClusters); + bind(OsFamily.class).toInstance(mockOSFamily); + } + }); + + Map<String, Cluster> clusters = new HashMap<>(); + expect(mockClusters.getClusters()).andReturn(clusters).anyTimes(); + + DatabaseConsistencyCheckHelper.setInjector(mockInjector); + + easyMockSupport.replayAll(); + + Map<Long, ConfigGroup> configGroups = DatabaseConsistencyCheckHelper.collectConfigGroupsWithoutServiceName(); + + easyMockSupport.verifyAll(); + + Assert.assertTrue(MapUtils.isEmpty(configGroups)); + } + + @Test public void testFixConfigsSelectedMoreThanOnce() throws Exception { EasyMockSupport easyMockSupport = new EasyMockSupport(); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog271Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog271Test.java index d7a1069..8d397f0 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog271Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog271Test.java @@ -55,11 +55,13 @@ public class UpgradeCatalog271Test { Method addNewConfigurationsFromXml = AbstractUpgradeCatalog.class.getDeclaredMethod("addNewConfigurationsFromXml"); Method updateRangerLogDirConfigs = UpgradeCatalog271.class.getDeclaredMethod("updateRangerLogDirConfigs"); Method updateRangerKmsDbUrl = UpgradeCatalog271.class.getDeclaredMethod("updateRangerKmsDbUrl"); + Method renameAmbariInfraInConfigGroups = UpgradeCatalog271.class.getDeclaredMethod("renameAmbariInfraInConfigGroups"); UpgradeCatalog271 upgradeCatalog271 = createMockBuilder(UpgradeCatalog271.class) .addMockedMethod(updateRangerKmsDbUrl) .addMockedMethod(updateRangerLogDirConfigs) .addMockedMethod(addNewConfigurationsFromXml) + .addMockedMethod(renameAmbariInfraInConfigGroups) .createMock(); upgradeCatalog271.addNewConfigurationsFromXml(); @@ -71,6 +73,9 @@ public class UpgradeCatalog271Test { upgradeCatalog271.updateRangerKmsDbUrl(); expectLastCall().once(); + upgradeCatalog271.renameAmbariInfraInConfigGroups(); + expectLastCall().once(); + replay(upgradeCatalog271); upgradeCatalog271.executeDMLUpdates(); verify(upgradeCatalog271);