AMBARI-21832. Reject PATCH VDFs with Services that are not Included in the Cluster (dlysnichenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c091ebe8 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c091ebe8 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c091ebe8 Branch: refs/heads/feature-branch-AMBARI-21307 Commit: c091ebe8afa1d83384d5607fb4ee52eb018772b0 Parents: c51540d Author: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Authored: Mon Sep 4 19:33:11 2017 +0300 Committer: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Committed: Mon Sep 4 19:33:11 2017 +0300 ---------------------------------------------------------------------- .../ClusterStackVersionResourceProvider.java | 45 +++++++++- ...ClusterStackVersionResourceProviderTest.java | 94 +++++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/c091ebe8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java index 19f5895..3e4d4fd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java @@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; @@ -77,6 +78,8 @@ import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.ServiceOsSpecific; import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.StackInfo; +import org.apache.ambari.server.state.repository.AvailableService; import org.apache.ambari.server.state.repository.ClusterVersionSummary; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; @@ -184,6 +187,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou private static Gson gson; @Inject + private static Provider<AmbariMetaInfo> metaInfo; + + @Inject private static Provider<Clusters> clusters; /** @@ -558,6 +564,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou // determine services for the repo Set<String> serviceNames = new HashSet<>(); + + checkPatchVDFAvailableServices(cluster, repoVersionEnt, desiredVersionDefinition); + // !!! limit the serviceNames to those that are detailed for the repository. // TODO packages don't have component granularity if (RepositoryType.STANDARD != repoVersionEnt.getType()) { @@ -596,6 +605,38 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou return req; } + /** + * Reject PATCH VDFs with Services that are not included in the Cluster + * @param cluster cluster instance + * @param repoVersionEnt repo version entity + * @param desiredVersionDefinition VDF + * @throws IllegalArgumentException thrown if VDF includes services that are not installed + * @throws AmbariException thrown if could not load stack for repo repoVersionEnt + */ + protected void checkPatchVDFAvailableServices(Cluster cluster, RepositoryVersionEntity repoVersionEnt, + VersionDefinitionXml desiredVersionDefinition) throws SystemException, AmbariException { + if (repoVersionEnt.getType() == RepositoryType.PATCH) { + + Collection<String> notPresentServices = new ArrayList<>(); + Collection<String> presentServices = new ArrayList<>(); + + presentServices.addAll(cluster.getServices().keySet()); + final StackInfo stack; + stack = metaInfo.get().getStack(repoVersionEnt.getStackName(), repoVersionEnt.getStackVersion()); + + for (AvailableService availableService : desiredVersionDefinition.getAvailableServices(stack)) { + String name = availableService.getName(); + if (!presentServices.contains(name)) { + notPresentServices.add(name); + } + } + if (!notPresentServices.isEmpty()) { + throw new IllegalArgumentException(String.format("%s VDF includes services that are not installed: %s", + RepositoryType.PATCH, StringUtils.join(notPresentServices, ","))); + } + } + } + private ActionExecutionContext getHostVersionInstallCommand(RepositoryVersionEntity repoVersion, Cluster cluster, AmbariManagementController managementController, AmbariMetaInfo ami, final StackId stackId, Set<String> repoServices, Map<String, List<RepositoryEntity>> perOsRepos, Stage stage1, Host host) @@ -685,7 +726,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou RequestStageContainer requestStages = new RequestStageContainer( actionManager.getNextRequestId(), null, requestFactory, actionManager); - requestStages.setRequestContext(String.format(INSTALL_PACKAGES_FULL_NAME)); + requestStages.setRequestContext(INSTALL_PACKAGES_FULL_NAME); return requestStages; } @@ -729,7 +770,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou compare = v2 - v1; - return (compare == 0) ? 0 : (compare < 0) ? -1 : 1; + return Integer.compare(compare, 0); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/c091ebe8/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java index f729de1..0e0e1c6 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java @@ -35,6 +35,7 @@ import java.lang.reflect.Field; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -89,11 +90,14 @@ import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.ServiceOsSpecific; import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.cluster.ClusterImpl; +import org.apache.ambari.server.state.repository.AvailableService; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.server.state.stack.upgrade.Direction; import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; @@ -1522,7 +1526,7 @@ public class ClusterStackVersionResourceProviderTest { " }\n" + "]"; expect(repoVersion.getOperatingSystems()).andReturn(rvh.parseOperatingSystems(os_json)).anyTimes(); - expect(repoVersion.getType()).andReturn(RepositoryType.STANDARD); + expect(repoVersion.getType()).andReturn(RepositoryType.STANDARD).anyTimes(); Map<String, Host> hostsForCluster = new HashMap<>(); int hostCount = 2; @@ -1806,6 +1810,94 @@ public class ClusterStackVersionResourceProviderTest { } + @Test + public void testCheckPatchVDFAvailableServices() throws Exception { + Cluster cluster = createNiceMock(Cluster.class); + RepositoryVersionEntity repoVersionEnt = createNiceMock(RepositoryVersionEntity.class); + VersionDefinitionXml desiredVersionDefinition = createNiceMock(VersionDefinitionXml.class); + + expect(repoVersionEnt.getType()).andReturn(RepositoryType.PATCH).once(); + + Service service1 = createNiceMock(Service.class); + expect(service1.getName()).andReturn("SERVICE1").anyTimes(); + expect(service1.getServiceComponents()).andReturn(new HashMap<String, ServiceComponent>()); + + Service service2 = createNiceMock(Service.class); + expect(service2.getName()).andReturn("SERVICE2").anyTimes(); + expect(service2.getServiceComponents()).andReturn(new HashMap<String, ServiceComponent>()); + + Map<String, Service> clusterServices = new HashMap<>(); + clusterServices.put("SERVICE1",service1); + clusterServices.put("SERVICE2",service2); + + expect(cluster.getServices()).andReturn(clusterServices).once(); + expect(repoVersionEnt.getStackName()).andReturn("HDP").once(); + expect(repoVersionEnt.getStackVersion()).andReturn("2.5.0").once(); + + AvailableService availableService1 = createNiceMock(AvailableService.class); + expect(availableService1.getName()).andReturn("SERVICE1").anyTimes(); + + AvailableService availableService2 = createNiceMock(AvailableService.class); + expect(availableService2.getName()).andReturn("SERVICE2").anyTimes(); + + Collection<AvailableService> availableServices = new ArrayList<>(); + availableServices.add(availableService1); + availableServices.add(availableService2); + + expect(desiredVersionDefinition.getAvailableServices((StackInfo)EasyMock.anyObject())).andReturn(availableServices).once(); + + + replay(cluster, repoVersionEnt, desiredVersionDefinition, service1, service2, availableService1, availableService2); + + ClusterStackVersionResourceProvider provider = new ClusterStackVersionResourceProvider(null); + injector.injectMembers(provider); + provider.checkPatchVDFAvailableServices(cluster, repoVersionEnt, desiredVersionDefinition); + } + + @Test + public void testCheckPatchVDFAvailableServicesFail() throws Exception { + Cluster cluster = createNiceMock(Cluster.class); + RepositoryVersionEntity repoVersionEnt = createNiceMock(RepositoryVersionEntity.class); + VersionDefinitionXml desiredVersionDefinition = createNiceMock(VersionDefinitionXml.class); + + expect(repoVersionEnt.getType()).andReturn(RepositoryType.PATCH).once(); + + Service service1 = createNiceMock(Service.class); + expect(service1.getName()).andReturn("SERVICE1").anyTimes(); + expect(service1.getServiceComponents()).andReturn(new HashMap<String, ServiceComponent>()); + + Map<String, Service> clusterServices = new HashMap<>(); + clusterServices.put("SERVICE1",service1); + + expect(cluster.getServices()).andReturn(clusterServices).once(); + expect(repoVersionEnt.getStackName()).andReturn("HDP").once(); + expect(repoVersionEnt.getStackVersion()).andReturn("2.5.0").once(); + + AvailableService availableService1 = createNiceMock(AvailableService.class); + expect(availableService1.getName()).andReturn("SERVICE1").anyTimes(); + + AvailableService availableService2 = createNiceMock(AvailableService.class); + expect(availableService2.getName()).andReturn("SERVICE2").anyTimes(); + + Collection<AvailableService> availableServices = new ArrayList<>(); + availableServices.add(availableService1); + availableServices.add(availableService2); + + expect(desiredVersionDefinition.getAvailableServices((StackInfo)EasyMock.anyObject())).andReturn(availableServices).once(); + + + replay(cluster, repoVersionEnt, desiredVersionDefinition, service1, availableService1, availableService2); + + ClusterStackVersionResourceProvider provider = new ClusterStackVersionResourceProvider(null); + injector.injectMembers(provider); + try { + provider.checkPatchVDFAvailableServices(cluster, repoVersionEnt, desiredVersionDefinition); + Assert.fail("Expected an exception when PATCH VDF includes services that are not installed"); + } catch (IllegalArgumentException expected) { + // !!! expected + Assert.assertEquals(expected.getMessage(),"PATCH VDF includes services that are not installed: SERVICE2"); + } + } private void testCreateResourcesExistingUpgrade(Authentication authentication) throws Exception { Resource.Type type = Resource.Type.ClusterStackVersion;