You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2018/08/01 23:27:00 UTC
[ambari] branch trunk updated: [AMBARI-24397] - Allow PATCH VDFs to
Specify Services Which Are Not Installed in the Cluster (#1943)
This is an automated email from the ASF dual-hosted git repository.
jonathanhurley pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new d8004b0 [AMBARI-24397] - Allow PATCH VDFs to Specify Services Which Are Not Installed in the Cluster (#1943)
d8004b0 is described below
commit d8004b05060a71623b849df2c4c2ad8351a5e6eb
Author: Jonathan Hurley <jo...@apache.org>
AuthorDate: Wed Aug 1 19:26:57 2018 -0400
[AMBARI-24397] - Allow PATCH VDFs to Specify Services Which Are Not Installed in the Cluster (#1943)
---
.../ClusterStackVersionResourceProvider.java | 37 -----
.../internal/UpgradeResourceProvider.java | 4 +-
.../orm/entities/RepositoryVersionEntity.java | 3 +-
.../upgrades/FinalizeUpgradeAction.java | 62 ++++++++-
.../apache/ambari/server/state/UpgradeContext.java | 7 +-
.../ClusterStackVersionResourceProviderTest.java | 103 +-------------
.../serveraction/upgrades/UpgradeActionTest.java | 155 +++++++++++++++++++++
7 files changed, 220 insertions(+), 151 deletions(-)
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 c9a826f..a78a947 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,7 +20,6 @@ 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;
@@ -79,8 +78,6 @@ 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;
@@ -521,8 +518,6 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
}
}
- checkPatchVDFAvailableServices(cluster, repoVersionEntity, versionDefinitionXml);
-
// the cluster will create/update all of the host versions to the correct state
List<Host> hostsNeedingInstallCommands = cluster.transitionHostsToInstalling(
repoVersionEntity, versionDefinitionXml, forceInstalled);
@@ -650,38 +645,6 @@ 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, ",")));
- }
- }
- }
-
@Transactional
ActionExecutionContext getHostVersionInstallCommand(RepositoryVersionEntity repoVersion,
Cluster cluster, AmbariManagementController managementController, AmbariMetaInfo ami,
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index 287e1a5..31cd926 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -1603,12 +1603,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
// depending on whether this is an upgrade or a downgrade, the history
// will be different
- if (upgradeContext.getDirection() == Direction.UPGRADE || upgradeContext.isPatchRevert()) {
+ if (upgradeContext.getDirection() == Direction.UPGRADE) {
history.setFromRepositoryVersion(component.getDesiredRepositoryVersion());
history.setTargetRepositoryVersion(upgradeContext.getRepositoryVersion());
} else {
// the target version on a downgrade is the original version that the
- // service was on in the failed upgrade
+ // service was on in the upgrade
RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
serviceName);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
index 18ac2c2..86359a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
@@ -54,6 +54,7 @@ import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
import org.apache.commons.lang.StringUtils;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -392,7 +393,7 @@ public class RepositoryVersionEntity {
*/
@Override
public String toString() {
- return Objects.toStringHelper(this).add("id", id).add("stack", stack).add("version",
+ return MoreObjects.toStringHelper(this).add("id", id).add("stack", stack).add("version",
version).add("type", type).add("hidden", isHidden == 1).toString();
}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
index 755f28e..cb6c71e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
@@ -35,7 +35,6 @@ import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.events.StackUpgradeFinishEvent;
import org.apache.ambari.server.events.publishers.VersionEventPublisher;
-import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
import org.apache.ambari.server.orm.dao.HostVersionDAO;
import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
@@ -50,8 +49,11 @@ 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.StackId;
+import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.UpgradeContext;
import org.apache.ambari.server.state.UpgradeState;
+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.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
@@ -95,9 +97,6 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
}
}
- @Inject
- private RoleCommandOrderProvider roleCommandOrderProvider;
-
/**
* Execution path for upgrade.
* @return the command report
@@ -200,7 +199,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
// move host versions from CURRENT to INSTALLED if their repos are no
// longer used
- finalizeHostVersionsNotDesired(cluster);
+ finalizeHostVersionsNotDesired(cluster, upgradeContext);
if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) {
outSB.append(String.format("Finalizing the version for cluster %s.\n", cluster.getClusterName()));
@@ -280,7 +279,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
throw new AmbariException(messageBuff.toString());
}
- finalizeHostVersionsNotDesired(cluster);
+ finalizeHostVersionsNotDesired(cluster, upgradeContext);
// for every repository being downgraded to, ensure the host versions are correct
Map<String, RepositoryVersionEntity> targetVersionsByService = upgradeContext.getTargetVersions();
@@ -400,11 +399,19 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
* {@link RepositoryVersionState#INSTALLED} or
* {@link RepositoryVersionState#NOT_REQUIRED} if their assocaited
* repositories are no longer in use.
+ * <p/>
+ * If this is a patch reversion, then this method will also attempt to
+ * determine if the downgrade-from repository needs to be set to
+ * {@link RepositoryVersionState#OUT_OF_SYNC}. If a patch upgrade was
+ * completed and then a service added after that happens to be specified in
+ * the VDF, then we must mark the repository as OUT_OF_SYNC since those
+ * service's packages were never distributed.
*
* @param cluster
* @throws AmbariException
*/
- private void finalizeHostVersionsNotDesired(Cluster cluster) throws AmbariException {
+ private void finalizeHostVersionsNotDesired(Cluster cluster, UpgradeContext upgradeContext)
+ throws AmbariException {
// create a set of all of the repos that the services are on
Set<RepositoryVersionEntity> desiredRepoVersions = new HashSet<>();
Set<String> serviceNames = cluster.getServices().keySet();
@@ -425,6 +432,47 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
hostVersion = hostVersionDAO.merge(hostVersion);
}
}
+
+ // reverting a patch requires us to check the repository state and
+ // possibly set it to OUT_OF_SYNC if services were added after this patch
+ // was originally distributed
+ if (upgradeContext.isPatchRevert()) {
+ RepositoryVersionEntity repositoryVersionEntity = upgradeContext.getRepositoryVersion();
+
+ final VersionDefinitionXml vdfXml;
+ try {
+ vdfXml = repositoryVersionEntity.getRepositoryXml();
+ } catch (Exception exception) {
+ throw new AmbariException("The VDF's XML could not be deserialized", exception);
+ }
+
+ StackInfo stack = ambariMetaInfo.getStack(repositoryVersionEntity.getStackId());
+
+ // grab the services in the VDF, the services which were part of the
+ // revert, and the services in the cluster to determine if a service was
+ // added to the cluster after the patch was originally applied
+ Collection<AvailableService> availableServices = vdfXml.getAvailableServices(stack);
+ Set<String> participatingServices = upgradeContext.getSupportedServices();
+ Set<String> clusterServices = cluster.getServices().keySet();
+
+ boolean resetRepoStateToOutOfSync = false;
+ for (AvailableService availableService : availableServices) {
+ if (clusterServices.contains(availableService.getName())
+ && !participatingServices.contains(availableService.getName())) {
+ resetRepoStateToOutOfSync = true;
+ break;
+ }
+ }
+
+ if (resetRepoStateToOutOfSync) {
+ List<HostVersionEntity> hostVersions = hostVersionDAO.findHostVersionByClusterAndRepository(
+ cluster.getClusterId(), repositoryVersionEntity);
+ for (HostVersionEntity hostVersion : hostVersions) {
+ hostVersion.setState(RepositoryVersionState.OUT_OF_SYNC);
+ hostVersion = hostVersionDAO.merge(hostVersion);
+ }
+ }
+ }
}
protected static class InfoTuple implements Comparable<InfoTuple> {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
index 8ef648c..0ccc15e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
@@ -387,7 +387,8 @@ public class UpgradeContext {
throw new AmbariException(message);
}
- m_repositoryVersion = priors.iterator().next();
+ // the "associated" repository of the revert is the target of what's being reverted
+ m_repositoryVersion = revertUpgrade.getRepositoryVersion();
// !!! the version is used later in validators
upgradeRequestMap.put(UPGRADE_REPO_VERSION_ID, m_repositoryVersion.getId().toString());
@@ -1061,11 +1062,11 @@ public class UpgradeContext {
/**
* Gets the set of services which will participate in the upgrade. The
- * services available in the repository are comapred against those installed
+ * services available in the repository are compared against those installed
* in the cluster to arrive at the final subset.
* <p/>
* In some cases, such as with a {@link RepositoryType#MAINT} repository, the
- * subset can be further trimmed by determing that an installed services is
+ * subset can be further trimmed by determing that an installed service is
* already at a high enough version and doesn't need to be upgraded.
* <p/>
* This method will also populate the source ({@link #m_sourceRepositoryMap})
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 ecf629f..f26db2a 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
@@ -34,7 +34,6 @@ import java.io.FileInputStream;
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;
@@ -78,8 +77,8 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.HostVersionEntity;
- import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
- import org.apache.ambari.server.orm.entities.RepoOsEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.orm.entities.StackEntity;
import org.apache.ambari.server.orm.entities.UpgradeEntity;
@@ -98,9 +97,7 @@ 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.ClusterVersionSummary;
import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.stack.upgrade.Direction;
@@ -127,8 +124,6 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.util.Modules;
-import junit.framework.AssertionFailedError;
-
/**
* ClusterStackVersionResourceProvider tests.
@@ -1747,100 +1742,6 @@ 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();
-
- expect(cluster.transitionHostsToInstalling(
- anyObject(RepositoryVersionEntity.class), anyObject(VersionDefinitionXml.class),
- EasyMock.anyBoolean())).andReturn(Collections.<Host>emptyList()).atLeastOnce();
-
- 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();
- expect(cluster.transitionHostsToInstalling(
- anyObject(RepositoryVersionEntity.class), anyObject(VersionDefinitionXml.class),
- EasyMock.anyBoolean())).andThrow(new AssertionFailedError()).anyTimes();
-
- 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 {
Cluster cluster = createNiceMock(Cluster.class);
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
index 86507b9..8ba5250 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
@@ -21,7 +21,10 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileInputStream;
import java.lang.reflect.Field;
+import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -66,6 +69,7 @@ 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.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;
@@ -77,8 +81,10 @@ import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.UpgradeState;
import org.apache.ambari.server.state.stack.UpgradePack;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
import org.apache.ambari.server.utils.EventBusSynchronizer;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Assert;
@@ -141,6 +147,9 @@ public class UpgradeActionTest {
private ConfigFactory configFactory;
@Inject
+ private RepositoryVersionDAO repositoryVersionDAO;
+
+ @Inject
private HostComponentStateDAO hostComponentStateDAO;
private RepositoryVersionEntity repositoryVersion2110;
@@ -583,6 +592,110 @@ public class UpgradeActionTest {
}
}
+ /**
+ * Tests the case where a revert happens on a patch upgrade and a new service
+ * has been added which causes the repository to go OUT_OF_SYNC.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testHostVersionsOutOfSyncAfterRevert() throws Exception {
+ String hostName = "h1";
+ Cluster cluster = createUpgradeCluster(repositoryVersion2110, hostName);
+ createHostVersions(repositoryVersion2111, hostName);
+
+ // Install ZK with some components (HBase is installed later to test the
+ // logic of revert)
+ Service zk = installService(cluster, "ZOOKEEPER", repositoryVersion2110);
+ addServiceComponent(cluster, zk, "ZOOKEEPER_SERVER");
+ addServiceComponent(cluster, zk, "ZOOKEEPER_CLIENT");
+ createNewServiceComponentHost(cluster, "ZOOKEEPER", "ZOOKEEPER_SERVER", hostName);
+ createNewServiceComponentHost(cluster, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostName);
+
+ List<HostVersionEntity> hostVersions = hostVersionDAO.findAll();
+ assertEquals(2, hostVersions.size());
+
+ // repo 2110 - CURRENT
+ // repo 2111 - CURRENT (PATCH)
+ for (HostVersionEntity hostVersion : hostVersions) {
+ RepositoryVersionEntity hostRepoVersion = hostVersion.getRepositoryVersion();
+ if (repositoryVersion2110.equals(hostRepoVersion)) {
+ hostVersion.setState(RepositoryVersionState.CURRENT);
+ } else {
+ hostVersion.setState(RepositoryVersionState.CURRENT);
+ }
+
+ hostVersionDAO.merge(hostVersion);
+ }
+
+ // convert the repository into a PATCH repo (which should have ZK and HBase
+ // as available services)
+ repositoryVersion2111.setParent(repositoryVersion2110);
+ repositoryVersion2111.setType(RepositoryType.PATCH);
+ repositoryVersion2111.setVersionXml(hostName);
+ repositoryVersion2111.setVersionXsd("version_definition.xsd");
+
+ File patchVdfFile = new File("src/test/resources/hbase_version_test.xml");
+ repositoryVersion2111.setVersionXml(
+ IOUtils.toString(new FileInputStream(patchVdfFile), Charset.defaultCharset()));
+
+ repositoryVersion2111 = repositoryVersionDAO.merge(repositoryVersion2111);
+
+ // pretend like we patched
+ UpgradeEntity upgrade = createUpgrade(cluster, repositoryVersion2111);
+ upgrade.setOrchestration(RepositoryType.PATCH);
+ upgrade.setRevertAllowed(true);
+ upgrade = upgradeDAO.merge(upgrade);
+
+ // add a service on the parent repo to cause the OUT_OF_SYNC on revert
+ Service hbase = installService(cluster, "HBASE", repositoryVersion2110);
+ addServiceComponent(cluster, hbase, "HBASE_MASTER");
+ createNewServiceComponentHost(cluster, "HBASE", "HBASE_MASTER", hostName);
+
+ // revert the patch
+ UpgradeEntity revert = createRevert(cluster, upgrade);
+ assertEquals(RepositoryType.PATCH, revert.getOrchestration());
+
+ // push all services to the revert repo version for finalize
+ Map<String, Service> services = cluster.getServices();
+ assertTrue(services.size() > 0);
+ for (Service service : services.values()) {
+ service.setDesiredRepositoryVersion(repositoryVersion2110);
+ }
+
+ // push all components to the revert version
+ List<HostComponentStateEntity> hostComponentStates = hostComponentStateDAO.findByHost(hostName);
+ for (HostComponentStateEntity hostComponentState : hostComponentStates) {
+ hostComponentState.setVersion(repositoryVersion2110.getVersion());
+ hostComponentStateDAO.merge(hostComponentState);
+ }
+
+ Map<String, String> commandParams = new HashMap<>();
+ ExecutionCommand executionCommand = new ExecutionCommand();
+ executionCommand.setCommandParams(commandParams);
+ executionCommand.setClusterName(clusterName);
+
+ HostRoleCommand hostRoleCommand = hostRoleCommandFactory.create(null, null, null, null);
+ hostRoleCommand.setExecutionCommandWrapper(new ExecutionCommandWrapper(executionCommand));
+
+ finalizeUpgradeAction.setExecutionCommand(executionCommand);
+ finalizeUpgradeAction.setHostRoleCommand(hostRoleCommand);
+
+ // finalize
+ CommandReport report = finalizeUpgradeAction.execute(null);
+ assertNotNull(report);
+ assertEquals(HostRoleStatus.COMPLETED.name(), report.getStatus());
+
+ for (HostVersionEntity hostVersion : hostVersions) {
+ RepositoryVersionEntity hostRepoVersion = hostVersion.getRepositoryVersion();
+ if (repositoryVersion2110.equals(hostRepoVersion)) {
+ assertEquals(RepositoryVersionState.CURRENT, hostVersion.getState());
+ } else {
+ assertEquals(RepositoryVersionState.OUT_OF_SYNC, hostVersion.getState());
+ }
+ }
+ }
+
private ServiceComponentHost createNewServiceComponentHost(Cluster cluster, String svc,
String svcComponent, String hostName) throws AmbariException {
Assert.assertNotNull(cluster.getConfigGroups());
@@ -692,4 +805,46 @@ public class UpgradeActionTest {
cluster.setUpgradeEntity(upgradeEntity);
return upgradeEntity;
}
+
+ /**
+ * Creates a revert based on an existing upgrade.
+ */
+ private UpgradeEntity createRevert(Cluster cluster, UpgradeEntity upgradeToRevert)
+ throws Exception {
+
+ // create some entities for the finalize action to work with for patch
+ // history
+ RequestEntity requestEntity = new RequestEntity();
+ requestEntity.setClusterId(cluster.getClusterId());
+ requestEntity.setRequestId(2L);
+ requestEntity.setStartTime(System.currentTimeMillis());
+ requestEntity.setCreateTime(System.currentTimeMillis());
+ requestDAO.create(requestEntity);
+
+ UpgradeEntity revert = new UpgradeEntity();
+ revert.setId(2L);
+ revert.setDirection(Direction.DOWNGRADE);
+ revert.setClusterId(cluster.getClusterId());
+ revert.setRequestEntity(requestEntity);
+ revert.setUpgradePackage("");
+ revert.setRepositoryVersion(upgradeToRevert.getRepositoryVersion());
+ revert.setUpgradeType(upgradeToRevert.getUpgradeType());
+ revert.setOrchestration(upgradeToRevert.getOrchestration());
+
+
+ for (UpgradeHistoryEntity historyToRevert : upgradeToRevert.getHistory()) {
+ UpgradeHistoryEntity history = new UpgradeHistoryEntity();
+ history.setUpgrade(revert);
+ history.setServiceName(historyToRevert.getServiceName());
+ history.setComponentName(historyToRevert.getComponentName());
+ history.setFromRepositoryVersion(upgradeToRevert.getRepositoryVersion());
+ history.setTargetRepositoryVersion(historyToRevert.getFromReposistoryVersion());
+ revert.addHistory(history);
+
+ }
+ upgradeDAO.create(revert);
+ cluster.setUpgradeEntity(revert);
+ return revert;
+ }
+
}