Repository: ambari Updated Branches: refs/heads/branch-feature-AMBARI-12556 382da9799 -> e2b8764cd
AMBARI-21241. Support revert for patch upgrades (ncole) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e2b8764c Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e2b8764c Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e2b8764c Branch: refs/heads/branch-feature-AMBARI-12556 Commit: e2b8764cda8e51e06654e51debe46e47354a61aa Parents: 382da97 Author: Nate Cole <nc...@hortonworks.com> Authored: Tue Jun 13 14:09:54 2017 -0400 Committer: Nate Cole <nc...@hortonworks.com> Committed: Wed Jun 14 12:33:49 2017 -0400 ---------------------------------------------------------------------- .../checks/HostsRepositoryVersionCheck.java | 13 +- .../server/controller/PrereqCheckRequest.java | 27 ++- .../PreUpgradeCheckResourceProvider.java | 11 +- .../internal/UpgradeResourceProvider.java | 12 +- .../server/orm/entities/UpgradeEntity.java | 22 ++ .../upgrades/FinalizeUpgradeAction.java | 59 ++--- .../upgrades/UpdateDesiredStackAction.java | 2 +- .../ambari/server/state/UpgradeContext.java | 230 +++++++++++++------ .../main/resources/Ambari-DDL-Derby-CREATE.sql | 1 + .../main/resources/Ambari-DDL-MySQL-CREATE.sql | 1 + .../main/resources/Ambari-DDL-Oracle-CREATE.sql | 1 + .../resources/Ambari-DDL-Postgres-CREATE.sql | 1 + .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 1 + .../resources/Ambari-DDL-SQLServer-CREATE.sql | 1 + .../StackUpgradeConfigurationMergeTest.java | 2 +- .../internal/UpgradeResourceProviderTest.java | 99 +++++++- .../ambari/server/state/UpgradeHelperTest.java | 4 +- .../src/test/resources/hbase_version_test.xml | 2 + 18 files changed, 374 insertions(+), 115 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java index a66db3c..79f3598 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java @@ -17,7 +17,9 @@ */ package org.apache.ambari.server.checks; +import java.util.EnumSet; import java.util.Map; +import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.PrereqCheckRequest; @@ -69,8 +71,6 @@ public class HostsRepositoryVersionCheck extends AbstractCheckDescriptor { final Map<String, Host> clusterHosts = clustersProvider.get().getHostsForCluster(clusterName); final StackId stackId = request.getSourceStackId(); - - for (Host host : clusterHosts.values()) { // hosts in MM will produce a warning if they do not have the repo version MaintenanceState maintenanceState = host.getMaintenanceState(cluster.getClusterId()); @@ -80,10 +80,17 @@ public class HostsRepositoryVersionCheck extends AbstractCheckDescriptor { if (null != request.getRepositoryVersion()) { boolean found = false; + + Set<RepositoryVersionState> allowed = EnumSet.of(RepositoryVersionState.INSTALLED, + RepositoryVersionState.NOT_REQUIRED); + if (request.isRevert()) { + allowed.add(RepositoryVersionState.CURRENT); + } + for (HostVersionEntity hve : hostVersionDaoProvider.get().findByHost(host.getHostName())) { if (hve.getRepositoryVersion().getVersion().equals(request.getRepositoryVersion()) - && (hve.getState() == RepositoryVersionState.INSTALLED || hve.getState() == RepositoryVersionState.NOT_REQUIRED)) { + && allowed.contains(hve.getState())) { found = true; break; } http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java index c8c9f9e..f80c16a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java @@ -38,8 +38,8 @@ public class PrereqCheckRequest { private UpgradeType m_upgradeType; - private Map<CheckDescription, PrereqCheckStatus> m_results = - new HashMap<>(); + private Map<CheckDescription, PrereqCheckStatus> m_results = new HashMap<>(); + private boolean m_revert = false; public PrereqCheckRequest(String clusterName, UpgradeType upgradeType) { @@ -132,11 +132,30 @@ public class PrereqCheckRequest { * Gets the prerequisite check config * @return the prereqCheckConfig */ - public PrerequisiteCheckConfig getPrerequisiteCheckConfig() { return m_prereqCheckConfig; } + public PrerequisiteCheckConfig getPrerequisiteCheckConfig() { + return m_prereqCheckConfig; + } /** * Sets the prerequisite check config obtained from the upgrade pack * @param prereqCheckConfig The prereqCheckConfig */ - public void setPrerequisiteCheckConfig(PrerequisiteCheckConfig prereqCheckConfig) { m_prereqCheckConfig = prereqCheckConfig;} + public void setPrerequisiteCheckConfig(PrerequisiteCheckConfig prereqCheckConfig) { + m_prereqCheckConfig = prereqCheckConfig; + } + + /** + * @param revert + * {@code true} if the check is for a patch reversion + */ + public void setRevert(boolean revert) { + m_revert = revert; + } + + /** + * @return if the check is for a patch reversion + */ + public boolean isRevert() { + return m_revert; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java index ea8fb37..7b03912 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java @@ -52,6 +52,7 @@ import org.apache.ambari.server.state.stack.PrerequisiteCheck; 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.commons.lang.BooleanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,6 +83,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider { */ public static final String UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "upgrade_pack"); public static final String UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "repository_version"); + public static final String UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "for_revert"); @Inject private static Provider<Clusters> clustersProvider; @@ -114,7 +116,8 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider { UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID, UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID, UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID, - UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID); + UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID, + UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID); @SuppressWarnings("serial") @@ -134,6 +137,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider { super(propertyIds, keyPropertyIds, managementController); } + @Override public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { @@ -175,6 +179,11 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider { upgradeCheckRequest.setTargetStackId(repositoryVersionEntity.getStackId()); } + if (propertyMap.containsKey(UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID)) { + Boolean forRevert = BooleanUtils.toBooleanObject(propertyMap.get(UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID).toString()); + upgradeCheckRequest.setRevert(forRevert); + } + //ambariMetaInfo.getStack(stackName, cluster.getCurrentStackVersion().getStackVersion()).getUpgradePacks() // TODO AMBARI-12698, filter the upgrade checks to run based on the stack and upgrade type, or the upgrade pack. UpgradePack upgradePack = null; http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java ---------------------------------------------------------------------- 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 60665f7..269bc19 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 @@ -127,6 +127,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider public static final String UPGRADE_REPO_VERSION_ID = "Upgrade/repository_version_id"; public static final String UPGRADE_TYPE = "Upgrade/upgrade_type"; public static final String UPGRADE_PACK = "Upgrade/pack"; + public static final String UPGRADE_ID = "Upgrade/upgrade_id"; public static final String UPGRADE_REQUEST_ID = "Upgrade/request_id"; public static final String UPGRADE_ASSOCIATED_VERSION = "Upgrade/associated_version"; public static final String UPGRADE_VERSIONS = "Upgrade/versions"; @@ -175,6 +176,11 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider public static final String UPGRADE_HOST_ORDERED_HOSTS = "Upgrade/host_order"; /** + * Allows reversion of a successful upgrade of a patch. + */ + public static final String UPGRADE_REVERT_UPGRADE_ID = "Upgrade/revert_upgrade_id"; + + /** * The role that will be used when creating HRC's for the type * {@link StageWrapper.Type#RU_TASKS}. */ @@ -251,6 +257,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider PROPERTY_IDS.add(UPGRADE_REPO_VERSION_ID); PROPERTY_IDS.add(UPGRADE_TYPE); PROPERTY_IDS.add(UPGRADE_PACK); + PROPERTY_IDS.add(UPGRADE_ID); PROPERTY_IDS.add(UPGRADE_REQUEST_ID); PROPERTY_IDS.add(UPGRADE_ASSOCIATED_VERSION); PROPERTY_IDS.add(UPGRADE_VERSIONS); @@ -263,6 +270,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider PROPERTY_IDS.add(UPGRADE_SKIP_PREREQUISITE_CHECKS); PROPERTY_IDS.add(UPGRADE_FAIL_ON_CHECK_WARNINGS); PROPERTY_IDS.add(UPGRADE_HOST_ORDERED_HOSTS); + PROPERTY_IDS.add(UPGRADE_REVERT_UPGRADE_ID); PROPERTY_IDS.add(REQUEST_CONTEXT_ID); PROPERTY_IDS.add(REQUEST_CREATE_TIME_ID); @@ -538,6 +546,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider private Resource toResource(UpgradeEntity entity, String clusterName, Set<String> requestedIds) { ResourceImpl resource = new ResourceImpl(Resource.Type.Upgrade); + setResourceProperty(resource, UPGRADE_ID, entity.getId(), requestedIds); setResourceProperty(resource, UPGRADE_CLUSTER_NAME, clusterName, requestedIds); setResourceProperty(resource, UPGRADE_TYPE, entity.getUpgradeType(), requestedIds); setResourceProperty(resource, UPGRADE_PACK, entity.getUpgradePackage(), requestedIds); @@ -667,6 +676,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider upgrade.setAutoSkipComponentFailures(upgradeContext.isComponentFailureAutoSkipped()); upgrade.setAutoSkipServiceCheckFailures(upgradeContext.isServiceCheckFailureAutoSkipped()); upgrade.setDowngradeAllowed(upgradeContext.isDowngradeAllowed()); + upgrade.setOrchestration(upgradeContext.getOrchestrationType()); // create to/from history for this upgrade - this should be done before any // possible changes to the desired version for components @@ -1355,7 +1365,7 @@ 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) { + if (upgradeContext.getDirection() == Direction.UPGRADE || upgradeContext.isPatchRevert()) { history.setFromRepositoryVersion(component.getDesiredRepositoryVersion()); history.setTargetRepositoryVersion(upgradeContext.getRepositoryVersion()); } else { http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java index 43b2e08..7f4824f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java @@ -38,6 +38,7 @@ import javax.persistence.Table; import javax.persistence.TableGenerator; import org.apache.ambari.server.actionmanager.HostRoleStatus; +import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.stack.upgrade.Direction; import org.apache.ambari.server.state.stack.upgrade.UpgradeType; import org.apache.commons.lang.builder.EqualsBuilder; @@ -118,6 +119,10 @@ public class UpgradeEntity { @Column(name="downgrade_allowed", nullable = false) private Short downgrade_allowed = 1; + @Column(name="orchestration", nullable = false) + @Enumerated(value = EnumType.STRING) + private RepositoryType orchestration = RepositoryType.STANDARD; + /** * {@code true} if the upgrade has been marked as suspended. */ @@ -372,6 +377,23 @@ public class UpgradeEntity { } /** + * Sets the orchestration for the upgrade. Only different when an upgrade is a revert of a patch. + * In that case, the orchestration is set to PATCH even if the target repository is type STANDARD. + * + * @param type the orchestration + */ + public void setOrchestration(RepositoryType type) { + orchestration = type; + } + + /** + * @return the orchestration type + */ + public RepositoryType getOrchestration() { + return orchestration; + } + + /** * {@inheritDoc} */ @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java ---------------------------------------------------------------------- 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 e70f1ce..9d70546 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 @@ -109,7 +109,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { String version = repositoryVersion.getVersion(); String message; - if (upgradeContext.getRepositoryType() == RepositoryType.STANDARD) { + if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) { message = MessageFormat.format("Finalizing the upgrade to {0} for all cluster services.", version); } else { Set<String> servicesInUpgrade = upgradeContext.getSupportedServices(); @@ -150,7 +150,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { // transition correctly for (HostVersionEntity hostVersion : hostVersions) { RepositoryVersionState hostVersionState = hostVersion.getState(); - switch( hostVersionState ){ + switch (hostVersionState) { case CURRENT: case NOT_REQUIRED: { hostVersionsAllowed.add(hostVersion); @@ -230,7 +230,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { String message; - if (downgradeFromRepositoryVersion.getType() == RepositoryType.STANDARD) { + if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) { message = MessageFormat.format( "Finalizing the downgrade from {0} for all cluster services.", downgradeFromVersion); @@ -260,39 +260,44 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { throw new AmbariException(messageBuff.toString()); } - // for every repository being downgraded to, ensure the host versions are correct - Map<String, RepositoryVersionEntity> targetVersionsByService = upgradeContext.getTargetVersions(); - Set<RepositoryVersionEntity> targetRepositoryVersions = new HashSet<>(); - for (String service : targetVersionsByService.keySet()) { - targetRepositoryVersions.add(targetVersionsByService.get(service)); - } - for (RepositoryVersionEntity targetRepositoryVersion : targetRepositoryVersions) { - // find host versions - List<HostVersionEntity> hostVersions = hostVersionDAO.findHostVersionByClusterAndRepository( - cluster.getClusterId(), targetRepositoryVersion); + if (upgradeContext.isPatchRevert()) { + finalizeHostRepositoryVersions(cluster); + } else { + // for every repository being downgraded to, ensure the host versions are correct + Map<String, RepositoryVersionEntity> targetVersionsByService = upgradeContext.getTargetVersions(); + Set<RepositoryVersionEntity> targetRepositoryVersions = new HashSet<>(); + for (String service : targetVersionsByService.keySet()) { + targetRepositoryVersions.add(targetVersionsByService.get(service)); + } - outSB.append(String.format("Finalizing %d host(s) back to %s", hostVersions.size(), - targetRepositoryVersion.getVersion())).append(System.lineSeparator()); + for (RepositoryVersionEntity targetRepositoryVersion : targetRepositoryVersions) { + // find host versions + List<HostVersionEntity> hostVersions = hostVersionDAO.findHostVersionByClusterAndRepository( + cluster.getClusterId(), targetRepositoryVersion); - for (HostVersionEntity hostVersion : hostVersions) { - if (hostVersion.getState() != RepositoryVersionState.CURRENT) { - hostVersion.setState(RepositoryVersionState.CURRENT); - hostVersionDAO.merge(hostVersion); - } + outSB.append(String.format("Finalizing %d host(s) back to %s", hostVersions.size(), + targetRepositoryVersion.getVersion())).append(System.lineSeparator()); + + for (HostVersionEntity hostVersion : hostVersions) { + if (hostVersion.getState() != RepositoryVersionState.CURRENT) { + hostVersion.setState(RepositoryVersionState.CURRENT); + hostVersionDAO.merge(hostVersion); + } - List<HostComponentStateEntity> hostComponentStates = hostComponentStateDAO.findByHost( - hostVersion.getHostName()); + List<HostComponentStateEntity> hostComponentStates = hostComponentStateDAO.findByHost( + hostVersion.getHostName()); - for (HostComponentStateEntity hostComponentState : hostComponentStates) { - hostComponentState.setUpgradeState(UpgradeState.NONE); - hostComponentStateDAO.merge(hostComponentState); + for (HostComponentStateEntity hostComponentState : hostComponentStates) { + hostComponentState.setUpgradeState(UpgradeState.NONE); + hostComponentStateDAO.merge(hostComponentState); + } } } } // remove any configurations for services which crossed a stack boundary - for( String serviceName : servicesInUpgrade ){ + for (String serviceName : servicesInUpgrade) { RepositoryVersionEntity sourceRepositoryVersion = upgradeContext.getSourceRepositoryVersion(serviceName); RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(serviceName); StackId sourceStackId = sourceRepositoryVersion.getStackId(); @@ -346,7 +351,7 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { StackId targetStackId = repositoryVersionEntity.getStackId(); Set<String> servicesParticipating = upgradeContext.getSupportedServices(); - for( String serviceName : servicesParticipating ){ + for (String serviceName : servicesParticipating) { Service service = cluster.getService(serviceName); String targetVersion = upgradeContext.getTargetVersion(serviceName); http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java index 8a4820d..ff0becc 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java @@ -130,7 +130,7 @@ public class UpdateDesiredStackAction extends AbstractUpgradeServerAction { final String message; RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getRepositoryVersion(); - if (upgradeContext.getRepositoryType() == RepositoryType.STANDARD) { + if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) { message = MessageFormat.format( "Updating the desired repository version to {0} for all cluster services.", targetRepositoryVersion.getVersion()); http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java ---------------------------------------------------------------------- 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 3ecf64d..bca85ca 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 @@ -22,6 +22,7 @@ import static org.apache.ambari.server.controller.internal.UpgradeResourceProvid import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_HOST_ORDERED_HOSTS; import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_PACK; import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID; +import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_REVERT_UPGRADE_ID; import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_FAILURES; import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_MANUAL_VERIFICATION; import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS; @@ -42,6 +43,7 @@ import java.util.Set; import org.apache.ambari.annotations.Experimental; import org.apache.ambari.annotations.ExperimentalFeature; import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.ServiceNotFoundException; import org.apache.ambari.server.actionmanager.HostRoleCommandFactory; import org.apache.ambari.server.agent.ExecutionCommand.KeyNames; import org.apache.ambari.server.api.services.AmbariMetaInfo; @@ -75,6 +77,8 @@ import org.apache.ambari.server.state.stack.upgrade.UpgradeScope; import org.apache.ambari.server.state.stack.upgrade.UpgradeType; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Objects; import com.google.gson.Gson; @@ -90,6 +94,8 @@ import com.google.inject.assistedinject.AssistedInject; */ public class UpgradeContext { + private static final Logger LOG = LoggerFactory.getLogger(UpgradeContext.class); + public static final String COMMAND_PARAM_CLUSTER_NAME = "clusterName"; public static final String COMMAND_PARAM_DIRECTION = "upgrade_direction"; public static final String COMMAND_PARAM_UPGRADE_PACK = "upgrade_pack"; @@ -237,6 +243,16 @@ public class UpgradeContext { @Inject private UpgradeDAO m_upgradeDAO; + /** + * Used as a quick way to tell if the upgrade is to revert a patch. + */ + private boolean m_isRevert = false; + + /** + * Defines orchestration type. This is not the repository type when reverting a patch. + */ + private RepositoryType m_orchestration = RepositoryType.STANDARD; + @AssistedInject public UpgradeContext(@Assisted Cluster cluster, @Assisted Map<String, Object> upgradeRequestMap, Gson gson, UpgradeHelper upgradeHelper, @@ -250,14 +266,6 @@ public class UpgradeContext { m_cluster = cluster; - // determine direction - String directionProperty = (String) upgradeRequestMap.get(UPGRADE_DIRECTION); - if (StringUtils.isEmpty(directionProperty)) { - throw new AmbariException(String.format("%s is required", UPGRADE_DIRECTION)); - } - - m_direction = Direction.valueOf(directionProperty); - // determine upgrade type (default is ROLLING) String upgradeTypeProperty = (String) upgradeRequestMap.get(UPGRADE_TYPE); if (StringUtils.isNotBlank(upgradeTypeProperty)) { @@ -272,71 +280,134 @@ public class UpgradeContext { m_type= UpgradeType.ROLLING; } - // depending on the direction, we must either have a target repository or an upgrade we are downgrading from - switch(m_direction){ - case UPGRADE:{ - String repositoryVersionId = (String) upgradeRequestMap.get(UPGRADE_REPO_VERSION_ID); - if (null == repositoryVersionId) { - throw new AmbariException( - String.format("The property %s is required when the upgrade direction is %s", - UPGRADE_REPO_VERSION_ID, m_direction)); - } + m_isRevert = upgradeRequestMap.containsKey(UPGRADE_REVERT_UPGRADE_ID); - // depending on the repository, add services - m_repositoryVersion = m_repoVersionDAO.findByPK(Long.valueOf(repositoryVersionId)); - if (m_repositoryVersion.getType() == RepositoryType.STANDARD) { - m_services.addAll(cluster.getServices().keySet()); - } else { - try { - VersionDefinitionXml vdf = m_repositoryVersion.getRepositoryXml(); - m_services.addAll(vdf.getAvailableServiceNames()); - - // if this is every true, then just stop the upgrade attempt and - // throw an exception - if (m_services.isEmpty()) { - String message = String.format( - "When using a VDF of type %s, the available services must be defined in the VDF", - m_repositoryVersion.getType()); - - throw new AmbariException(message); - } + if (m_isRevert) { + Long revertUpgradeId = Long.valueOf(upgradeRequestMap.get(UPGRADE_REVERT_UPGRADE_ID).toString()); + UpgradeEntity revertUpgrade = m_upgradeDAO.findUpgrade(revertUpgradeId); - } catch (Exception e) { - String msg = String.format( - "Could not parse version definition for %s. Upgrade will not proceed.", - m_repositoryVersion.getVersion()); + if (revertUpgrade.getOrchestration() != RepositoryType.PATCH) { + throw new AmbariException("Can only revert upgrades that have been done as a patch."); + } - throw new AmbariException(msg); - } - } + if (revertUpgrade.getDirection() != Direction.UPGRADE) { + throw new AmbariException("Can only revert successful upgrades, not downgrades."); + } - // populate the target repository map for all services in the upgrade - for (String serviceName : m_services) { - Service service = cluster.getService(serviceName); - m_sourceRepositoryMap.put(serviceName, service.getDesiredRepositoryVersion()); - m_targetRepositoryMap.put(serviceName, m_repositoryVersion); - } + Set<RepositoryVersionEntity> priors = new HashSet<>(); + for (UpgradeHistoryEntity history : revertUpgrade.getHistory()) { + priors.add(history.getFromReposistoryVersion()); - break; + // !!! build all service-specific + m_services.add(history.getServiceName()); + m_sourceRepositoryMap.put(history.getServiceName(), history.getTargetRepositoryVersion()); + m_targetRepositoryMap.put(history.getServiceName(), history.getFromReposistoryVersion()); } - case DOWNGRADE:{ - UpgradeEntity upgrade = m_upgradeDAO.findLastUpgradeForCluster( - cluster.getClusterId(), Direction.UPGRADE); - m_repositoryVersion = upgrade.getRepositoryVersion(); + if (priors.size() != 1) { + String message = String.format("Upgrade from %s could not be reverted as there is no single " + + " repository across services.", revertUpgrade.getRepositoryVersion().getVersion()); - // populate the repository maps for all services in the upgrade - for (UpgradeHistoryEntity history : upgrade.getHistory()) { - m_services.add(history.getServiceName()); - m_sourceRepositoryMap.put(history.getServiceName(), m_repositoryVersion); - m_targetRepositoryMap.put(history.getServiceName(), history.getFromReposistoryVersion()); + throw new AmbariException(message); + } + + m_repositoryVersion = priors.iterator().next(); + + // !!! the version is used later in validators + upgradeRequestMap.put(UPGRADE_REPO_VERSION_ID, m_repositoryVersion.getId().toString()); + // !!! use the same upgrade pack that was used in the upgrade being reverted + upgradeRequestMap.put(UPGRADE_PACK, revertUpgrade.getUpgradePackage()); + + // !!! direction can ONLY be an downgrade on revert + m_direction = Direction.DOWNGRADE; + m_orchestration = RepositoryType.PATCH; + } else { + + // determine direction + String directionProperty = (String) upgradeRequestMap.get(UPGRADE_DIRECTION); + if (StringUtils.isEmpty(directionProperty)) { + throw new AmbariException(String.format("%s is required", UPGRADE_DIRECTION)); + } + + m_direction = Direction.valueOf(directionProperty); + + // depending on the direction, we must either have a target repository or an upgrade we are downgrading from + switch(m_direction){ + case UPGRADE:{ + String repositoryVersionId = (String) upgradeRequestMap.get(UPGRADE_REPO_VERSION_ID); + if (null == repositoryVersionId) { + throw new AmbariException( + String.format("The property %s is required when the upgrade direction is %s", + UPGRADE_REPO_VERSION_ID, m_direction)); + } + + // depending on the repository, add services + m_repositoryVersion = m_repoVersionDAO.findByPK(Long.valueOf(repositoryVersionId)); + m_orchestration = m_repositoryVersion.getType(); + + if (m_orchestration == RepositoryType.STANDARD) { + m_services.addAll(cluster.getServices().keySet()); + } else { + try { + VersionDefinitionXml vdf = m_repositoryVersion.getRepositoryXml(); + m_services.addAll(vdf.getAvailableServiceNames()); + + // if this is every true, then just stop the upgrade attempt and + // throw an exception + if (m_services.isEmpty()) { + String message = String.format( + "When using a VDF of type %s, the available services must be defined in the VDF", + m_repositoryVersion.getType()); + + throw new AmbariException(message); + } + + } catch (Exception e) { + String msg = String.format( + "Could not parse version definition for %s. Upgrade will not proceed.", + m_repositoryVersion.getVersion()); + + throw new AmbariException(msg); + } + } + + Set<String> installedServices = new HashSet<>(); + // populate the target repository map for all services in the upgrade + for (String serviceName : m_services) { + try { + Service service = cluster.getService(serviceName); + m_sourceRepositoryMap.put(serviceName, service.getDesiredRepositoryVersion()); + m_targetRepositoryMap.put(serviceName, m_repositoryVersion); + installedServices.add(serviceName); + } catch (ServiceNotFoundException e) { + LOG.warn("Skipping orchestraction for service {}, as it was defined to upgrade, but is not installed in cluster {}", + serviceName, cluster.getClusterName()); + } + } + + m_services = installedServices; + + break; } + case DOWNGRADE:{ + UpgradeEntity upgrade = m_upgradeDAO.findLastUpgradeForCluster( + cluster.getClusterId(), Direction.UPGRADE); - break; + m_repositoryVersion = upgrade.getRepositoryVersion(); + + // populate the repository maps for all services in the upgrade + for (UpgradeHistoryEntity history : upgrade.getHistory()) { + m_services.add(history.getServiceName()); + m_sourceRepositoryMap.put(history.getServiceName(), m_repositoryVersion); + m_targetRepositoryMap.put(history.getServiceName(), history.getFromReposistoryVersion()); + } + + break; + } + default: + m_repositoryVersion = null; + break; } - default: - m_repositoryVersion = null; - break; } @@ -428,6 +499,10 @@ public class UpgradeContext { m_upgradePack = packs.get(upgradePackage); m_resolver = new MasterHostResolver(m_cluster, configHelper, this); + m_orchestration = upgradeEntity.getOrchestration(); + + m_isRevert = upgradeEntity.getOrchestration() == RepositoryType.PATCH && + upgradeEntity.getDirection() == Direction.DOWNGRADE; } /** @@ -522,7 +597,7 @@ public class UpgradeContext { * service. This is the version that the service will be on if the upgrade or * downgrade succeeds. * <p/> - * With a {@link Direction#UPGRADE}, all services should be targetting the + * With a {@link Direction#UPGRADE}, all services should be targeting the * same repository version. However, {@link Direction#DOWNGRADE} will target * the original repository that the service was on. * @@ -699,7 +774,7 @@ public class UpgradeContext { return true; } - switch (m_repositoryVersion.getType()) { + switch (m_orchestration) { case PATCH: case SERVICE: return scope == UpgradeScope.PARTIAL; @@ -730,12 +805,14 @@ public class UpgradeContext { /** * Gets the repository type to determine if this upgrade is a complete upgrade - * or a service/patch. + * or a service/patch. This value is not always the same as the repository version. In + * the case of a revert of a patch, the target repository may be of type STANDARD, but orchestration + * must be "like a patch". * - * @return the repository type. + * @return the orchestration type. */ - public RepositoryType getRepositoryType() { - return m_repositoryVersion.getType(); + public RepositoryType getOrchestrationType() { + return m_orchestration; } /** @@ -802,6 +879,13 @@ public class UpgradeContext { } /** + * @return + */ + public boolean isPatchRevert() { + return m_isRevert; + } + + /** * Builds a chain of {@link UpgradeRequestValidator}s to ensure that the * incoming request to create a new upgrade is valid. * @@ -816,7 +900,7 @@ public class UpgradeContext { validator.setNextValidator(preReqValidator); final UpgradeRequestValidator upgradeTypeValidator; - switch( upgradeType ){ + switch (upgradeType) { case HOST_ORDERED: upgradeTypeValidator = new HostOrderedUpgradeValidator(); break; @@ -869,7 +953,7 @@ public class UpgradeContext { check(cluster, direction, type, upgradePack, requestMap); // pass along to the next - if( null != m_nextValidator ) { + if (null != m_nextValidator) { m_nextValidator.validate(cluster, direction, type, upgradePack, requestMap); } } @@ -931,7 +1015,7 @@ public class UpgradeContext { // verify that there is not an upgrade or downgrade that is in progress or suspended UpgradeEntity existingUpgrade = cluster.getUpgradeInProgress(); - if( null != existingUpgrade ){ + if (null != existingUpgrade) { throw new AmbariException( String.format("Unable to perform %s as another %s (request ID %s) is in progress.", direction.getText(false), existingUpgrade.getDirection().getText(false), @@ -939,7 +1023,7 @@ public class UpgradeContext { } // skip this check if it's a downgrade or we are instructed to skip it - if( direction.isDowngrade() || skipPrereqChecks ){ + if (direction.isDowngrade() || skipPrereqChecks) { return; } @@ -953,6 +1037,7 @@ public class UpgradeContext { Predicate preUpgradeCheckPredicate = new PredicateBuilder().property( PreUpgradeCheckResourceProvider.UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).equals(cluster.getClusterName()).and().property( PreUpgradeCheckResourceProvider.UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).equals(repositoryVersion.getVersion()).and().property( + PreUpgradeCheckResourceProvider.UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID).equals(m_isRevert).and().property( PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID).equals(type).and().property( PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID).equals(preferredUpgradePack).toPredicate(); @@ -1110,4 +1195,5 @@ public class UpgradeContext { return hostOrderItems; } } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql index e341405..bbb4af0 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql @@ -813,6 +813,7 @@ CREATE TABLE upgrade ( cluster_id BIGINT NOT NULL, request_id BIGINT NOT NULL, direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL, upgrade_package VARCHAR(255) NOT NULL, upgrade_type VARCHAR(32) NOT NULL, repo_version_id BIGINT NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql index ce8736e..5cdbd26 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql @@ -831,6 +831,7 @@ CREATE TABLE upgrade ( cluster_id BIGINT NOT NULL, request_id BIGINT NOT NULL, direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL, upgrade_package VARCHAR(255) NOT NULL, upgrade_type VARCHAR(32) NOT NULL, repo_version_id BIGINT NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql index ace3738..732e2c4 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql @@ -810,6 +810,7 @@ CREATE TABLE upgrade ( cluster_id NUMBER(19) NOT NULL, request_id NUMBER(19) NOT NULL, direction VARCHAR2(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR2(255) DEFAULT 'STANDARD' NOT NULL, upgrade_package VARCHAR2(255) NOT NULL, upgrade_type VARCHAR2(32) NOT NULL, repo_version_id NUMBER(19) NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql index 5899179..62a3f00 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql @@ -812,6 +812,7 @@ CREATE TABLE upgrade ( cluster_id BIGINT NOT NULL, request_id BIGINT NOT NULL, direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL, upgrade_package VARCHAR(255) NOT NULL, upgrade_type VARCHAR(32) NOT NULL, repo_version_id BIGINT NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql index 6164b2d..da46ec4 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql @@ -808,6 +808,7 @@ CREATE TABLE upgrade ( cluster_id NUMERIC(19) NOT NULL, request_id NUMERIC(19) NOT NULL, direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL, upgrade_type VARCHAR(32) NOT NULL, repo_version_id NUMERIC(19) NOT NULL, upgrade_package VARCHAR(255) NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql index 52d2b87..c64355e 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql @@ -830,6 +830,7 @@ CREATE TABLE upgrade ( cluster_id BIGINT NOT NULL, request_id BIGINT NOT NULL, direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL, + orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL, upgrade_package VARCHAR(255) NOT NULL, upgrade_type VARCHAR(32) NOT NULL, repo_version_id BIGINT NOT NULL, http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackUpgradeConfigurationMergeTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackUpgradeConfigurationMergeTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackUpgradeConfigurationMergeTest.java index a37e4f5..9f3f01f 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackUpgradeConfigurationMergeTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackUpgradeConfigurationMergeTest.java @@ -264,7 +264,7 @@ public class StackUpgradeConfigurationMergeTest extends EasyMockSupport { expect(context.getSupportedServices()).andReturn(Sets.newHashSet("ZOOKEEPER")).atLeastOnce(); expect(context.getSourceRepositoryVersion(EasyMock.anyString())).andReturn(repoVersion211).atLeastOnce(); expect(context.getTargetRepositoryVersion(EasyMock.anyString())).andReturn(repoVersion220).atLeastOnce(); - expect(context.getRepositoryType()).andReturn(RepositoryType.STANDARD).anyTimes(); + expect(context.getOrchestrationType()).andReturn(RepositoryType.STANDARD).anyTimes(); expect(context.getHostRoleCommandFactory()).andStubReturn(m_injector.getInstance(HostRoleCommandFactory.class)); expect(context.getRoleGraphFactory()).andStubReturn(m_injector.getInstance(RoleGraphFactory.class)); http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java index 014ab42..48d78f8 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java @@ -25,9 +25,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.FileInputStream; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -88,6 +91,7 @@ import org.apache.ambari.server.state.ConfigFactory; import org.apache.ambari.server.state.ConfigHelper; import org.apache.ambari.server.state.Host; import org.apache.ambari.server.state.HostState; +import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; @@ -100,6 +104,8 @@ import org.apache.ambari.server.state.stack.upgrade.UpgradeType; import org.apache.ambari.server.topology.TopologyManager; import org.apache.ambari.server.utils.StageUtils; import org.apache.ambari.server.view.ViewRegistry; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.easymock.EasyMock; import org.easymock.EasyMockSupport; @@ -109,6 +115,8 @@ import org.junit.Before; import org.junit.Test; import org.springframework.security.core.context.SecurityContextHolder; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -139,6 +147,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { RepositoryVersionEntity repoVersionEntity2110; RepositoryVersionEntity repoVersionEntity2111; + RepositoryVersionEntity repoVersionEntity2112; RepositoryVersionEntity repoVersionEntity2200; /** @@ -208,14 +217,23 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { repoVersionDao.create(repoVersionEntity2110); repoVersionEntity2111 = new RepositoryVersionEntity(); - repoVersionEntity2111.setDisplayName("My New Version 2 for patch upgrade"); + repoVersionEntity2111.setDisplayName("My New Version 2 for minor upgrade"); repoVersionEntity2111.setOperatingSystems(""); repoVersionEntity2111.setStack(stackEntity211); repoVersionEntity2111.setVersion("2.1.1.1"); repoVersionDao.create(repoVersionEntity2111); + repoVersionEntity2112 = new RepositoryVersionEntity(); + repoVersionEntity2112.setDisplayName("My New Version 3 for patch upgrade"); + repoVersionEntity2112.setOperatingSystems(""); + repoVersionEntity2112.setStack(stackEntity211); + repoVersionEntity2112.setVersion("2.1.1.2"); + repoVersionEntity2112.setType(RepositoryType.PATCH); + repoVersionEntity2112.setVersionXml(""); + repoVersionDao.create(repoVersionEntity2112); + repoVersionEntity2200 = new RepositoryVersionEntity(); - repoVersionEntity2200.setDisplayName("My New Version 3 for major upgrade"); + repoVersionEntity2200.setDisplayName("My New Version 4 for major upgrade"); repoVersionEntity2200.setOperatingSystems(""); repoVersionEntity2200.setStack(stackEntity220); repoVersionEntity2200.setVersion("2.2.0.0"); @@ -1572,6 +1590,81 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { } } + + /** + * Tests that from/to repository version history is created correctly on the + * upgrade. + * + * @throws Exception + */ + @Test + public void testCreatePatchRevertUpgrade() throws Exception { + Cluster cluster = clusters.getCluster("c1"); + + File f = new File("src/test/resources/hbase_version_test.xml"); + repoVersionEntity2112.setVersionXml(IOUtils.toString(new FileInputStream(f))); + repoVersionEntity2112.setVersionXsd("version_definition.xsd"); + repoVersionDao.merge(repoVersionEntity2112); + + List<UpgradeEntity> upgrades = upgradeDao.findUpgrades(cluster.getClusterId()); + assertEquals(0, upgrades.size()); + + Map<String, Object> requestProps = new HashMap<>(); + requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1"); + requestProps.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID, String.valueOf(repoVersionEntity2112.getId())); + requestProps.put(UpgradeResourceProvider.UPGRADE_PACK, "upgrade_test"); + requestProps.put(UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS, "true"); + requestProps.put(UpgradeResourceProvider.UPGRADE_DIRECTION, Direction.UPGRADE.name()); + + ResourceProvider upgradeResourceProvider = createProvider(amc); + + Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null); + upgradeResourceProvider.createResources(request); + + upgrades = upgradeDao.findUpgrades(cluster.getClusterId()); + assertEquals(1, upgrades.size()); + UpgradeEntity upgradeEntity = upgrades.get(0); + assertEquals(RepositoryType.PATCH, upgradeEntity.getOrchestration()); + + // !!! make it look like the cluster is done + cluster.setUpgradeEntity(null); + + requestProps = new HashMap<>(); + requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1"); + requestProps.put(UpgradeResourceProvider.UPGRADE_REVERT_UPGRADE_ID, upgradeEntity.getId()); + requestProps.put(UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS, Boolean.TRUE.toString()); + + request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null); + upgradeResourceProvider.createResources(request); + + upgrades = upgradeDao.findUpgrades(cluster.getClusterId()); + assertEquals(2, upgrades.size()); + + boolean found = false; + + Function<UpgradeHistoryEntity, String> function = new Function<UpgradeHistoryEntity, String>() { + @Override + public String apply(UpgradeHistoryEntity input) { + return input.getServiceName() + "/" + input.getComponentName(); + }; + }; + + for (UpgradeEntity upgrade : upgrades) { + if (upgrade.getId() != upgradeEntity.getId()) { + found = true; + assertEquals(upgradeEntity.getOrchestration(), upgrade.getOrchestration()); + + Collection<String> upgradeEntityStrings = Collections2.transform(upgradeEntity.getHistory(), function); + Collection<String> upgradeStrings = Collections2.transform(upgrade.getHistory(), function); + + Collection<?> diff = CollectionUtils.disjunction(upgradeEntityStrings, upgradeStrings); + assertEquals("Verify the same set of components was orchestrated", 0, diff.size()); + } + } + + assertTrue(found); + } + private String parseSingleMessage(String msgStr){ JsonParser parser = new JsonParser(); JsonArray msgArray = (JsonArray) parser.parse(msgStr); @@ -1664,7 +1757,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { * Without this, commands of this type would not be able to determine which * service/component repository they should use when the command is scheduled * to run. - * + * * @throws Exception */ @Test http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java index 921322b..8cf7373 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java @@ -2393,7 +2393,7 @@ public class UpgradeHelperTest extends EasyMockSupport { expect(context.getSupportedServices()).andReturn(Sets.newHashSet("ZOOKEEPER")).atLeastOnce(); expect(context.getSourceRepositoryVersion(EasyMock.anyString())).andReturn(repoVersion211).atLeastOnce(); expect(context.getTargetRepositoryVersion(EasyMock.anyString())).andReturn(repoVersion220).atLeastOnce(); - expect(context.getRepositoryType()).andReturn(RepositoryType.STANDARD).anyTimes(); + expect(context.getOrchestrationType()).andReturn(RepositoryType.STANDARD).anyTimes(); expect(context.getAmbariMetaInfo()).andReturn(ambariMetaInfo).anyTimes(); expect(context.getHostRoleCommandFactory()).andStubReturn(injector.getInstance(HostRoleCommandFactory.class)); expect(context.getRoleGraphFactory()).andStubReturn(injector.getInstance(RoleGraphFactory.class)); @@ -2492,7 +2492,7 @@ public class UpgradeHelperTest extends EasyMockSupport { expect(context.getDirection()).andReturn(direction).anyTimes(); expect(context.getRepositoryVersion()).andReturn(repositoryVersion).anyTimes(); expect(context.getSupportedServices()).andReturn(services).anyTimes(); - expect(context.getRepositoryType()).andReturn(repositoryType).anyTimes(); + expect(context.getOrchestrationType()).andReturn(repositoryType).anyTimes(); expect(context.getAmbariMetaInfo()).andReturn(ambariMetaInfo).anyTimes(); expect(context.getHostRoleCommandFactory()).andStubReturn( injector.getInstance(HostRoleCommandFactory.class)); http://git-wip-us.apache.org/repos/asf/ambari/blob/e2b8764c/ambari-server/src/test/resources/hbase_version_test.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/resources/hbase_version_test.xml b/ambari-server/src/test/resources/hbase_version_test.xml index 58c8701..ea90f40 100644 --- a/ambari-server/src/test/resources/hbase_version_test.xml +++ b/ambari-server/src/test/resources/hbase_version_test.xml @@ -30,10 +30,12 @@ <manifest> <service id="HBASE-112" name="HBASE" version="1.1.2" version-id="2_3_4_0-3396" /> + <service id="ZOOKEEPER-346" name="ZOOKEEPER" version="3.4.6" version-id="2_3_4_0-3396" /> </manifest> <available-services> <service idref="HBASE-112" /> + <service idref="ZOOKEEPER-346" /> </available-services> <repository-info>