Repository: ambari Updated Branches: refs/heads/branch-2.6 854d7000f -> 313e3bf0f
AMBARI-21894 - PATCH and MAINT Repositories Should Indicate that they can be Reverted (jonathanhurley) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/313e3bf0 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/313e3bf0 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/313e3bf0 Branch: refs/heads/branch-2.6 Commit: 313e3bf0f812a285506ff5e58cf1ef23544764d1 Parents: 854d700 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Wed Sep 6 14:32:29 2017 -0400 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Thu Sep 7 00:00:47 2017 -0400 ---------------------------------------------------------------------- .../ClusterStackVersionResourceProvider.java | 34 +++++- .../internal/UpgradeResourceProvider.java | 16 ++- .../ambari/server/orm/dao/UpgradeDAO.java | 46 +++++++- .../server/orm/entities/UpgradeEntity.java | 109 +++++++++++++++---- .../upgrades/AbstractUpgradeServerAction.java | 7 ++ .../upgrades/FinalizeUpgradeAction.java | 12 +- .../ambari/server/state/RepositoryType.java | 7 ++ .../ambari/server/state/UpgradeContext.java | 33 +++++- .../server/upgrade/UpgradeCatalog260.java | 9 +- .../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 + .../internal/UpgradeResourceProviderTest.java | 62 +++++++++++ .../ambari/server/orm/dao/UpgradeDAOTest.java | 102 +++++++++++++++++ .../ambari/server/state/UpgradeContextTest.java | 50 +++++++++ .../server/upgrade/UpgradeCatalog260Test.java | 30 ++++- 19 files changed, 488 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 940bc2b..c2084b6 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 @@ -61,6 +61,7 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; +import org.apache.ambari.server.orm.dao.UpgradeDAO; import org.apache.ambari.server.orm.entities.HostVersionEntity; import org.apache.ambari.server.orm.entities.OperatingSystemEntity; import org.apache.ambari.server.orm.entities.RepositoryEntity; @@ -110,6 +111,8 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou protected static final String CLUSTER_STACK_VERSION_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "state"); protected static final String CLUSTER_STACK_VERSION_HOST_STATES_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "host_states"); protected static final String CLUSTER_STACK_VERSION_REPO_SUMMARY_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "repository_summary"); + protected static final String CLUSTER_STACK_VERSION_REPO_SUPPORTS_REVERT= PropertyHelper.getPropertyId("ClusterStackVersions", "supports_revert"); + protected static final String CLUSTER_STACK_VERSION_REPO_REVERT_UPGRADE_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "revert_upgrade_id"); protected static final String CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "repository_version"); protected static final String CLUSTER_STACK_VERSION_STAGE_SUCCESS_FACTOR = PropertyHelper.getPropertyId("ClusterStackVersions", "success_factor"); @@ -152,7 +155,8 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou CLUSTER_STACK_VERSION_VERSION_PROPERTY_ID, CLUSTER_STACK_VERSION_HOST_STATES_PROPERTY_ID, CLUSTER_STACK_VERSION_STATE_PROPERTY_ID, CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID, CLUSTER_STACK_VERSION_STAGE_SUCCESS_FACTOR, CLUSTER_STACK_VERSION_IGNORE_PACKAGE_DEPENDENCIES, - CLUSTER_STACK_VERSION_FORCE, CLUSTER_STACK_VERSION_REPO_SUMMARY_PROPERTY_ID); + CLUSTER_STACK_VERSION_FORCE, CLUSTER_STACK_VERSION_REPO_SUMMARY_PROPERTY_ID, + CLUSTER_STACK_VERSION_REPO_SUPPORTS_REVERT, CLUSTER_STACK_VERSION_REPO_REVERT_UPGRADE_ID); private static Map<Type, String> keyPropertyIds = ImmutableMap.<Type, String> builder() .put(Type.Cluster, CLUSTER_STACK_VERSION_CLUSTER_NAME_PROPERTY_ID) @@ -165,6 +169,12 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou @Inject private static HostVersionDAO hostVersionDAO; + /** + * Used for looking up revertable upgrades. + */ + @Inject + private static UpgradeDAO upgradeDAO; + @Inject private static RepositoryVersionDAO repositoryVersionDAO; @@ -251,6 +261,12 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou throw new SystemException("Could not find any repositories to show"); } + // find the 1 repository version which is revertable, if any + UpgradeEntity revertableUpgrade = null; + if (null == cluster.getUpgradeInProgress()) { + revertableUpgrade = upgradeDAO.findRevertable(cluster.getClusterId()); + } + for (Long repositoryVersionId : requestedEntities) { final Resource resource = new ResourceImpl(Resource.Type.ClusterStackVersion); @@ -289,7 +305,6 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou setResourceProperty(resource, CLUSTER_STACK_VERSION_HOST_STATES_PROPERTY_ID, hostStates, requestedIds); setResourceProperty(resource, CLUSTER_STACK_VERSION_REPO_SUMMARY_PROPERTY_ID, versionSummary, requestedIds); - setResourceProperty(resource, CLUSTER_STACK_VERSION_ID_PROPERTY_ID, repositoryVersion.getId(), requestedIds); setResourceProperty(resource, CLUSTER_STACK_VERSION_STACK_PROPERTY_ID, repoVersionStackId.getStackName(), requestedIds); setResourceProperty(resource, CLUSTER_STACK_VERSION_VERSION_PROPERTY_ID, repoVersionStackId.getStackVersion(), requestedIds); @@ -300,6 +315,21 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou RepositoryVersionState aggregateState = RepositoryVersionState.getAggregateState(allStates); setResourceProperty(resource, CLUSTER_STACK_VERSION_STATE_PROPERTY_ID, aggregateState, requestedIds); + // mark whether this repo is revertable for this cluster + boolean revertable = false; + if (null != revertableUpgrade) { + RepositoryVersionEntity revertableRepositoryVersion = revertableUpgrade.getRepositoryVersion(); + revertable = revertableRepositoryVersion.getId() == repositoryVersionId; + } + + setResourceProperty(resource, CLUSTER_STACK_VERSION_REPO_SUPPORTS_REVERT, revertable, requestedIds); + + // if the repo is revertable, indicate which upgrade to revert if necessary + if (revertable) { + setResourceProperty(resource, CLUSTER_STACK_VERSION_REPO_REVERT_UPGRADE_ID, + revertableUpgrade.getId(), requestedIds); + } + if (predicate == null || predicate.evaluate(resource)) { resources.add(resource); } http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 722ec0f..3d72a6e 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 @@ -761,7 +761,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider upgrade.setUpgradeGroups(groupEntities); req.getRequestStatusResponse(); - return createUpgradeInsideTransaction(cluster, req, upgrade); + return createUpgradeInsideTransaction(cluster, req, upgrade, upgradeContext); } /** @@ -778,6 +778,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider * @param upgradeEntity * the upgrade to create and associate with the newly created request * (not {@code null}). + * @param upgradeContext + * the upgrade context associated with the upgrade being created. * @return the persisted {@link UpgradeEntity} encapsulating all * {@link UpgradeGroupEntity} and {@link UpgradeItemEntity}. * @throws AmbariException @@ -785,7 +787,17 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider @Transactional UpgradeEntity createUpgradeInsideTransaction(Cluster cluster, RequestStageContainer request, - UpgradeEntity upgradeEntity) throws AmbariException { + UpgradeEntity upgradeEntity, UpgradeContext upgradeContext) throws AmbariException { + + // if this is a patch reversion, then we must unset the revertable flag of + // the upgrade being reverted + if (upgradeContext.isPatchRevert()) { + UpgradeEntity upgradeBeingReverted = s_upgradeDAO.findUpgrade( + upgradeContext.getPatchRevertUpgradeId()); + + upgradeBeingReverted.setRevertAllowed(false); + upgradeBeingReverted = s_upgradeDAO.merge(upgradeBeingReverted); + } request.persist(); RequestEntity requestEntity = s_requestDAO.findByPK(request.getId()); http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java index 716f5b5..5990c09 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java @@ -26,6 +26,7 @@ import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.UpgradeEntity; import org.apache.ambari.server.orm.entities.UpgradeGroupEntity; import org.apache.ambari.server.orm.entities.UpgradeItemEntity; +import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.stack.upgrade.Direction; import com.google.inject.Inject; @@ -168,7 +169,8 @@ public class UpgradeDAO { } /** - * @param clusterId the cluster id + * @param clusterId + * the cluster id * @return the upgrade entity, or {@code null} if not found */ @RequiresSession @@ -181,6 +183,48 @@ public class UpgradeDAO { return daoUtils.selectSingle(query); } + /** + * Gets the only revertable upgrade if one exists. By definition, only the + * most recent {@code RepositoryType#PATCH} or {@code RepositoryType#MAINT} + * upgrade which doesn't have a downgrade already is revertable. + * + * @param clusterId + * the cluster id + * @return the upgrade which can be reverted, or {@code null} if not found + */ + @RequiresSession + public UpgradeEntity findRevertable(long clusterId) { + TypedQuery<UpgradeEntity> query = entityManagerProvider.get().createNamedQuery( + "UpgradeEntity.findRevertable", UpgradeEntity.class); + query.setMaxResults(1); + query.setParameter("clusterId", clusterId); + + return daoUtils.selectSingle(query); + } + + /** + * Gets the only revertable upgrade if one exists. By definition, only the + * most recent {@code RepositoryType#PATCH} or {@code RepositoryType#MAINT} + * upgrade which doesn't have a downgrade already is revertable. + * <p> + * This method tries to use some fancy SQL to do the work instead of relying + * on columns to be set correctly. + * + * @param clusterId + * the cluster id + * @return the upgrade which can be reverted, or {@code null} if not found + */ + @RequiresSession + public UpgradeEntity findRevertableUsingJPQL(long clusterId) { + TypedQuery<UpgradeEntity> query = entityManagerProvider.get().createNamedQuery( + "UpgradeEntity.findRevertableUsingJPQL", UpgradeEntity.class); + query.setMaxResults(1); + query.setParameter("clusterId", clusterId); + query.setParameter("revertableTypes", RepositoryType.REVERTABLE); + + return daoUtils.selectSingle(query); + } + @Transactional public UpgradeEntity merge(UpgradeEntity upgradeEntity) { return entityManagerProvider.get().merge(upgradeEntity); http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 7f4824f..1361c94 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 @@ -34,6 +34,7 @@ import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.OneToOne; +import javax.persistence.QueryHint; import javax.persistence.Table; import javax.persistence.TableGenerator; @@ -58,21 +59,42 @@ import com.google.common.base.Objects; pkColumnValue = "upgrade_id_seq", initialValue = 0) @NamedQueries({ - @NamedQuery(name = "UpgradeEntity.findAll", - query = "SELECT u FROM UpgradeEntity u"), - @NamedQuery(name = "UpgradeEntity.findAllForCluster", - query = "SELECT u FROM UpgradeEntity u WHERE u.clusterId = :clusterId"), - @NamedQuery(name = "UpgradeEntity.findUpgrade", - query = "SELECT u FROM UpgradeEntity u WHERE u.upgradeId = :upgradeId"), - @NamedQuery(name = "UpgradeEntity.findUpgradeByRequestId", - query = "SELECT u FROM UpgradeEntity u WHERE u.requestId = :requestId"), - @NamedQuery(name = "UpgradeEntity.findLatestForClusterInDirection", - query = "SELECT u FROM UpgradeEntity u JOIN RequestEntity r ON u.requestId = r.requestId WHERE u.clusterId = :clusterId AND u.direction = :direction ORDER BY r.startTime DESC, u.upgradeId DESC"), - @NamedQuery(name = "UpgradeEntity.findLatestForCluster", - query = "SELECT u FROM UpgradeEntity u JOIN RequestEntity r ON u.requestId = r.requestId WHERE u.clusterId = :clusterId ORDER BY r.startTime DESC"), - @NamedQuery(name = "UpgradeEntity.findAllRequestIds", - query = "SELECT upgrade.requestId FROM UpgradeEntity upgrade") -}) + @NamedQuery(name = "UpgradeEntity.findAll", query = "SELECT u FROM UpgradeEntity u"), + @NamedQuery( + name = "UpgradeEntity.findAllForCluster", + query = "SELECT u FROM UpgradeEntity u WHERE u.clusterId = :clusterId"), + @NamedQuery( + name = "UpgradeEntity.findUpgrade", + query = "SELECT u FROM UpgradeEntity u WHERE u.upgradeId = :upgradeId"), + @NamedQuery( + name = "UpgradeEntity.findUpgradeByRequestId", + query = "SELECT u FROM UpgradeEntity u WHERE u.requestId = :requestId"), + @NamedQuery( + name = "UpgradeEntity.findLatestForClusterInDirection", + query = "SELECT u FROM UpgradeEntity u JOIN RequestEntity r ON u.requestId = r.requestId WHERE u.clusterId = :clusterId AND u.direction = :direction ORDER BY r.startTime DESC, u.upgradeId DESC"), + @NamedQuery( + name = "UpgradeEntity.findLatestForCluster", + query = "SELECT u FROM UpgradeEntity u JOIN RequestEntity r ON u.requestId = r.requestId WHERE u.clusterId = :clusterId ORDER BY r.startTime DESC"), + @NamedQuery( + name = "UpgradeEntity.findAllRequestIds", + query = "SELECT upgrade.requestId FROM UpgradeEntity upgrade"), + @NamedQuery( + name = "UpgradeEntity.findRevertable", + query = "SELECT upgrade FROM UpgradeEntity upgrade WHERE upgrade.revertAllowed = 1 AND upgrade.clusterId = :clusterId ORDER BY upgrade.upgradeId DESC", + hints = { + @QueryHint(name = "eclipselink.query-results-cache", value = "true"), + @QueryHint(name = "eclipselink.query-results-cache.ignore-null", value = "false"), + @QueryHint(name = "eclipselink.query-results-cache.size", value = "1") + }), + @NamedQuery( + name = "UpgradeEntity.findRevertableUsingJPQL", + query = "SELECT upgrade FROM UpgradeEntity upgrade WHERE upgrade.repoVersionId IN (SELECT upgrade.repoVersionId FROM UpgradeEntity upgrade WHERE upgrade.clusterId = :clusterId AND upgrade.orchestration IN :revertableTypes GROUP BY upgrade.repoVersionId HAVING MOD(COUNT(upgrade.repoVersionId), 2) != 0) ORDER BY upgrade.upgradeId DESC", + hints = { + @QueryHint(name = "eclipselink.query-results-cache", value = "true"), + @QueryHint(name = "eclipselink.query-results-cache.ignore-null", value = "false"), + @QueryHint(name = "eclipselink.query-results-cache.size", value = "1") + }) + }) public class UpgradeEntity { @Id @@ -107,6 +129,9 @@ public class UpgradeEntity { @Enumerated(value = EnumType.STRING) private UpgradeType upgradeType; + @Column(name = "repo_version_id", insertable = false, updatable = false) + private Long repoVersionId; + @JoinColumn(name = "repo_version_id", referencedColumnName = "repo_version_id", nullable = false) private RepositoryVersionEntity repositoryVersion; @@ -117,7 +142,26 @@ public class UpgradeEntity { private Integer skipServiceCheckFailures = 0; @Column(name="downgrade_allowed", nullable = false) - private Short downgrade_allowed = 1; + private Short downgradeAllowed = 1; + + /** + * Whether this upgrade is a candidate to be reverted. The current restriction + * on this behavior is that only the most recent + * {@link RepositoryType#PATCH}/{@link RepositoryType#MAINT} for a given + * cluster can be reverted at a time. + * <p/> + * All upgrades are created with this value defaulted to {@code false}. Upon + * successful finalization of the upgrade, if the upgrade was the correct type + * and direction, then it becomes a candidate for reversion and this value is + * set to {@code true}. If an upgrade is reverted after being finalized, then + * this value to should set to {@code false} explicitely. + * <p/> + * There can exist <i>n</i> number of upgrades with this value set to + * {@code true}. The idea is that only the most recent upgrade with this value + * set to {@code true} will be able to be reverted. + */ + @Column(name = "revert_allowed", nullable = false) + private Short revertAllowed = 0; @Column(name="orchestration", nullable = false) @Enumerated(value = EnumType.STRING) @@ -222,18 +266,45 @@ public class UpgradeEntity { * @return possibility to process downgrade */ public Boolean isDowngradeAllowed() { - return downgrade_allowed != null ? (downgrade_allowed != 0) : null; + return downgradeAllowed != null ? (downgradeAllowed != 0) : null; } /** * @param canDowngrade {@code true} to allow downgrade, {@code false} to disallow downgrade */ public void setDowngradeAllowed(boolean canDowngrade) { - downgrade_allowed = (!canDowngrade ? (short)0 : (short)1); + downgradeAllowed = (!canDowngrade ? (short) 0 : (short) 1); + } + + /** + * Gets whether this upgrade supports being reverted. Upgrades can be reverted + * (downgraded after finalization) if they are either + * {@link RepositoryType#MAINT} or {@link RepositoryType#PATCH} and have never + * been previously downgraded. + * + * @return {@code true} if this upgrade can potentially be revereted. + */ + public Boolean isRevertAllowed() { + return revertAllowed != null ? (revertAllowed != 0) : null; + } + + /** + * Sets whether this upgrade supports being reverted. This should only ever be + * called from the finalization of an upgrade. {@link RepositoryType#MAINT} or + * {@link RepositoryType#PATCH} upgrades can be revereted only if they have + * not previously been downgraded. + * + * @param revertable + * {@code true} to mark this as being revertable, {@code false} + * otherwise. + */ + public void setRevertAllowed(boolean revertable) { + revertAllowed = (!revertable ? (short) 0 : (short) 1); } /** - * @param upgradeType the upgrade type to set + * @param upgradeType + * the upgrade type to set */ public void setUpgradeType(UpgradeType upgradeType) { this.upgradeType = upgradeType; http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java index e012dac..8ebb186 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java @@ -17,6 +17,7 @@ */ package org.apache.ambari.server.serveraction.upgrades; +import org.apache.ambari.server.orm.dao.UpgradeDAO; import org.apache.ambari.server.orm.entities.UpgradeEntity; import org.apache.ambari.server.serveraction.AbstractServerAction; import org.apache.ambari.server.state.Cluster; @@ -42,6 +43,12 @@ public abstract class AbstractUpgradeServerAction extends AbstractServerAction { protected UpgradeHelper m_upgradeHelper; /** + * Used to lookup or update {@link UpgradeEntity} instances. + */ + @Inject + protected UpgradeDAO m_upgradeDAO; + + /** * Used to create instances of {@link UpgradeContext} with injected * dependencies. */ http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 662dfef..bbff9fd 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 @@ -32,7 +32,6 @@ import java.util.concurrent.ConcurrentMap; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; -import org.apache.ambari.server.agent.ExecutionCommand.KeyNames; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.events.StackUpgradeFinishEvent; import org.apache.ambari.server.events.publishers.VersionEventPublisher; @@ -41,6 +40,7 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.entities.HostComponentStateEntity; import org.apache.ambari.server.orm.entities.HostVersionEntity; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; +import org.apache.ambari.server.orm.entities.UpgradeEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.ComponentInfo; import org.apache.ambari.server.state.RepositoryType; @@ -101,6 +101,9 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { private CommandReport finalizeUpgrade(UpgradeContext upgradeContext) throws AmbariException, InterruptedException { + Direction direction = upgradeContext.getDirection(); + RepositoryType repositoryType = upgradeContext.getOrchestrationType(); + StringBuilder outSB = new StringBuilder(); StringBuilder errSB = new StringBuilder(); @@ -195,6 +198,13 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction { // longer used finalizeHostRepositoryVersions(cluster); + // mark revertable + if (repositoryType.isRevertable() && direction == Direction.UPGRADE) { + UpgradeEntity upgrade = cluster.getUpgradeInProgress(); + upgrade.setRevertAllowed(true); + upgrade = m_upgradeDAO.merge(upgrade); + } + // Reset upgrade state cluster.setUpgradeEntity(null); http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java index 2e95c59..954f705 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java @@ -17,6 +17,8 @@ */ package org.apache.ambari.server.state; +import java.util.EnumSet; + /** * Identifies the type of repository */ @@ -45,6 +47,11 @@ public enum RepositoryType { */ SERVICE; + /** + * The types of repositories which are revertable. + */ + public static final EnumSet<RepositoryType> REVERTABLE = EnumSet.of(RepositoryType.MAINT, + RepositoryType.PATCH); /** * Gets whether applications of this repository are revertable after they have http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 60f44bb..9f31ab8 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 @@ -252,6 +252,11 @@ public class UpgradeContext { private final boolean m_isRevert; /** + * The ID of the upgrade being reverted if this is a reversion. + */ + private long m_revertUpgradeId; + + /** * Defines orchestration type. This is not the repository type when reverting a patch. */ private RepositoryType m_orchestration = RepositoryType.STANDARD; @@ -286,11 +291,19 @@ public class UpgradeContext { m_isRevert = upgradeRequestMap.containsKey(UPGRADE_REVERT_UPGRADE_ID); if (m_isRevert) { - Long revertUpgradeId = Long.valueOf(upgradeRequestMap.get(UPGRADE_REVERT_UPGRADE_ID).toString()); - UpgradeEntity revertUpgrade = m_upgradeDAO.findUpgrade(revertUpgradeId); + m_revertUpgradeId = Long.valueOf(upgradeRequestMap.get(UPGRADE_REVERT_UPGRADE_ID).toString()); + UpgradeEntity revertUpgrade = m_upgradeDAO.findUpgrade(m_revertUpgradeId); + UpgradeEntity revertableUpgrade = m_upgradeDAO.findRevertable(cluster.getClusterId()); if (null == revertUpgrade) { - throw new AmbariException(String.format("Could not find Upgrade with id %s to revert.", revertUpgradeId)); + throw new AmbariException( + String.format("Could not find Upgrade with id %s to revert.", m_revertUpgradeId)); + } + + if (null == revertableUpgrade) { + throw new AmbariException( + String.format("There are no upgrades for cluster %s which are marked as revertable", + cluster.getClusterName())); } if (!revertUpgrade.getOrchestration().isRevertable()) { @@ -299,7 +312,15 @@ public class UpgradeContext { } if (revertUpgrade.getDirection() != Direction.UPGRADE) { - throw new AmbariException("Can only revert successful upgrades, not downgrades."); + throw new AmbariException( + "Only successfully completed upgrades can be reverted. Downgrades cannot be reverted."); + } + + if (revertableUpgrade.getId() != revertUpgrade.getId()) { + throw new AmbariException(String.format( + "The only upgrade which is currently allowed to be reverted for cluster %s is upgrade ID %s which was an upgrade to %s", + cluster.getClusterName(), revertableUpgrade.getId(), + revertableUpgrade.getRepositoryVersion().getVersion())); } for (UpgradeHistoryEntity history : revertUpgrade.getHistory()) { @@ -849,6 +870,10 @@ public class UpgradeContext { return m_isRevert; } + public long getPatchRevertUpgradeId() { + return m_revertUpgradeId; + } + /** * Gets a POJO of the upgrade suitable to serialize. * http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java index 7fb978b..07ae0c2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java @@ -25,6 +25,7 @@ import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.Query; + import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.orm.DBAccessor; import org.apache.ambari.server.orm.entities.ClusterConfigEntity; @@ -90,6 +91,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog { public static final String FROM_REPO_VERSION_ID_COLUMN = "from_repo_version_id"; public static final String TO_REPO_VERSION_ID_COLUMN = "to_repo_version_id"; public static final String ORCHESTRATION_COLUMN = "orchestration"; + public static final String ALLOW_REVERT_COLUMN = "revert_allowed"; public static final String FK_UPGRADE_FROM_REPO_ID = "FK_upgrade_from_repo_id"; public static final String FK_UPGRADE_TO_REPO_ID = "FK_upgrade_to_repo_id"; public static final String FK_UPGRADE_REPO_VERSION_ID = "FK_upgrade_repo_version_id"; @@ -144,6 +146,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog { /** * {@inheritDoc} */ + @Override public String getTargetVersion() { return "2.6.0"; } @@ -185,7 +188,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog { EntityManager entityManager = getEntityManagerProvider().get(); Query query = entityManager.createNamedQuery("ClusterConfigEntity.findNotMappedClusterConfigsToService",ClusterConfigEntity.class); - List<ClusterConfigEntity> notMappedConfigs = (List<ClusterConfigEntity>) query.getResultList(); + List<ClusterConfigEntity> notMappedConfigs = query.getResultList(); if (notMappedConfigs != null) { for (ClusterConfigEntity clusterConfigEntity : notMappedConfigs) { clusterConfigEntity.setUnmapped(true); @@ -241,9 +244,13 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog { dbAccessor.addColumn(UPGRADE_TABLE, new DBAccessor.DBColumnInfo(REPO_VERSION_ID_COLUMN, Long.class, null, null, false)); + dbAccessor.addColumn(UPGRADE_TABLE, new DBAccessor.DBColumnInfo(ORCHESTRATION_COLUMN, String.class, 255, STANDARD, false)); + dbAccessor.addColumn(UPGRADE_TABLE, + new DBAccessor.DBColumnInfo(ALLOW_REVERT_COLUMN, Short.class, null, 0, false)); + dbAccessor.addFKConstraint(UPGRADE_TABLE, FK_UPGRADE_REPO_VERSION_ID, REPO_VERSION_ID_COLUMN, REPO_VERSION_TABLE, REPO_VERSION_ID_COLUMN, false); } http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 2e546dc..b9c6985 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql @@ -818,6 +818,7 @@ CREATE TABLE upgrade ( skip_failures SMALLINT DEFAULT 0 NOT NULL, skip_sc_failures SMALLINT DEFAULT 0 NOT NULL, downgrade_allowed SMALLINT DEFAULT 1 NOT NULL, + revert_allowed SMALLINT DEFAULT 0 NOT NULL, suspended SMALLINT DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 fefe1dc..c53cd7b 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql @@ -835,6 +835,7 @@ CREATE TABLE upgrade ( skip_failures TINYINT(1) NOT NULL DEFAULT 0, skip_sc_failures TINYINT(1) NOT NULL DEFAULT 0, downgrade_allowed TINYINT(1) NOT NULL DEFAULT 1, + revert_allowed TINYINT(1) NOT NULL DEFAULT 0, suspended TINYINT(1) DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 35866da..6f754bb 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql @@ -814,6 +814,7 @@ CREATE TABLE upgrade ( skip_failures NUMBER(1) DEFAULT 0 NOT NULL, skip_sc_failures NUMBER(1) DEFAULT 0 NOT NULL, downgrade_allowed NUMBER(1) DEFAULT 1 NOT NULL, + revert_allowed NUMBER(1) DEFAULT 0 NOT NULL, suspended NUMBER(1) DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 1dce2ce..19c0214 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql @@ -815,6 +815,7 @@ CREATE TABLE upgrade ( skip_failures SMALLINT DEFAULT 0 NOT NULL, skip_sc_failures SMALLINT DEFAULT 0 NOT NULL, downgrade_allowed SMALLINT DEFAULT 1 NOT NULL, + revert_allowed SMALLINT DEFAULT 0 NOT NULL, suspended SMALLINT DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 5627cc1..8567d09 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql @@ -812,6 +812,7 @@ CREATE TABLE upgrade ( skip_failures BIT NOT NULL DEFAULT 0, skip_sc_failures BIT NOT NULL DEFAULT 0, downgrade_allowed BIT NOT NULL DEFAULT 1, + revert_allowed BIT NOT NULL DEFAULT 0, suspended BIT DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 0794836..fdbad09 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql @@ -833,6 +833,7 @@ CREATE TABLE upgrade ( skip_failures BIT NOT NULL DEFAULT 0, skip_sc_failures BIT NOT NULL DEFAULT 0, downgrade_allowed BIT NOT NULL DEFAULT 1, + revert_allowed BIT NOT NULL DEFAULT 0, suspended BIT DEFAULT 0 NOT NULL, CONSTRAINT PK_upgrade PRIMARY KEY CLUSTERED (upgrade_id), FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id), http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/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 52f41ca..9c961da 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 @@ -1608,6 +1608,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { sch.setVersion("2.1.1.0"); File f = new File("src/test/resources/hbase_version_test.xml"); + repoVersionEntity2112.setType(RepositoryType.PATCH); repoVersionEntity2112.setVersionXml(IOUtils.toString(new FileInputStream(f))); repoVersionEntity2112.setVersionXsd("version_definition.xsd"); repoVersionDao.merge(repoVersionEntity2112); @@ -1629,9 +1630,17 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { upgrades = upgradeDao.findUpgrades(cluster.getClusterId()); assertEquals(1, upgrades.size()); + UpgradeEntity upgradeEntity = upgrades.get(0); assertEquals(RepositoryType.PATCH, upgradeEntity.getOrchestration()); + // should be false since only finalization actually sets this bit + assertEquals(false, upgradeEntity.isRevertAllowed()); + + // fake it now so the rest of the test passes + upgradeEntity.setRevertAllowed(true); + upgradeEntity = upgradeDao.merge(upgradeEntity); + // !!! make it look like the cluster is done cluster.setUpgradeEntity(null); @@ -1671,6 +1680,59 @@ public class UpgradeResourceProviderTest extends EasyMockSupport { assertTrue(found); } + /** + * Tests that when there is no revertable upgrade, a reversion of a specific + * ugprade ID is not allowed. + */ + @Test(expected = SystemException.class) + public void testRevertFailsWhenNoRevertableUpgradeIsFound() throws Exception { + Cluster cluster = clusters.getCluster("c1"); + + // add a single ZK server and client on 2.1.1.0 + Service service = cluster.addService("HBASE", repoVersionEntity2110); + ServiceComponent component = service.addServiceComponent("HBASE_MASTER"); + ServiceComponentHost sch = component.addServiceComponentHost("h1"); + sch.setVersion("2.1.1.0"); + + File f = new File("src/test/resources/hbase_version_test.xml"); + repoVersionEntity2112.setType(RepositoryType.PATCH); + 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); + } + private String parseSingleMessage(String msgStr){ JsonParser parser = new JsonParser(); JsonArray msgArray = (JsonArray) parser.parse(msgStr); http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UpgradeDAOTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UpgradeDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UpgradeDAOTest.java index a626e07..0ea1e97 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UpgradeDAOTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UpgradeDAOTest.java @@ -39,6 +39,7 @@ import org.apache.ambari.server.orm.entities.StageEntity; import org.apache.ambari.server.orm.entities.UpgradeEntity; import org.apache.ambari.server.orm.entities.UpgradeGroupEntity; import org.apache.ambari.server.orm.entities.UpgradeItemEntity; +import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.UpgradeState; import org.apache.ambari.server.state.stack.upgrade.Direction; @@ -241,4 +242,105 @@ public class UpgradeDAOTest { Assert.assertTrue(lastUpgradeForCluster.isComponentFailureAutoSkipped()); Assert.assertTrue(lastUpgradeForCluster.isServiceCheckFailureAutoSkipped()); } + + /** + * Tests the logic that finds the one-and-only revertable upgrade. + * + * @throws Exception + */ + @Test + public void testFindRevertableUpgrade() throws Exception { + // create upgrade entities + UpgradeEntity revertable = dao.findRevertable(1L); + UpgradeEntity revertableViaJPQL = dao.findRevertableUsingJPQL(1L); + assertEquals(null, revertable); + assertEquals(null, revertableViaJPQL); + + RequestEntity requestEntity = new RequestEntity(); + requestEntity.setRequestId(1L); + requestEntity.setClusterId(clusterId.longValue()); + requestEntity.setStatus(HostRoleStatus.PENDING); + requestEntity.setStages(new ArrayList<StageEntity>()); + requestDAO.create(requestEntity); + + UpgradeEntity entity1 = new UpgradeEntity(); + entity1.setId(11L); + entity1.setClusterId(clusterId.longValue()); + entity1.setDirection(Direction.UPGRADE); + entity1.setRequestEntity(requestEntity); + entity1.setRepositoryVersion(repositoryVersion2500); + entity1.setUpgradeType(UpgradeType.ROLLING); + entity1.setUpgradePackage("test-upgrade"); + entity1.setDowngradeAllowed(true); + entity1.setOrchestration(RepositoryType.PATCH); + entity1.setRevertAllowed(true); + dao.create(entity1); + + revertable = dao.findRevertable(1L); + revertableViaJPQL = dao.findRevertableUsingJPQL(1L); + assertEquals(revertable.getId(), entity1.getId()); + assertEquals(revertableViaJPQL.getId(), entity1.getId()); + + UpgradeEntity entity2 = new UpgradeEntity(); + entity2.setId(22L); + entity2.setClusterId(clusterId.longValue()); + entity2.setDirection(Direction.UPGRADE); + entity2.setRequestEntity(requestEntity); + entity2.setRepositoryVersion(repositoryVersion2511); + entity2.setUpgradeType(UpgradeType.ROLLING); + entity2.setUpgradePackage("test-upgrade"); + entity2.setDowngradeAllowed(true); + entity2.setOrchestration(RepositoryType.MAINT); + entity2.setRevertAllowed(true); + dao.create(entity2); + + revertable = dao.findRevertable(1L); + revertableViaJPQL = dao.findRevertableUsingJPQL(1L); + assertEquals(revertable.getId(), entity2.getId()); + assertEquals(revertableViaJPQL.getId(), entity2.getId()); + + // now make it look like upgrade ID 22 was reverted + entity2.setRevertAllowed(false); + entity2 = dao.merge(entity2); + + // create a downgrade for ID 22 + UpgradeEntity entity3 = new UpgradeEntity(); + entity3.setId(33L); + entity3.setClusterId(clusterId.longValue()); + entity3.setDirection(Direction.DOWNGRADE); + entity3.setRequestEntity(requestEntity); + entity3.setRepositoryVersion(repositoryVersion2511); + entity3.setUpgradeType(UpgradeType.ROLLING); + entity3.setUpgradePackage("test-upgrade"); + entity3.setOrchestration(RepositoryType.MAINT); + entity3.setDowngradeAllowed(false); + dao.create(entity3); + + revertable = dao.findRevertable(1L); + revertableViaJPQL = dao.findRevertableUsingJPQL(1L); + assertEquals(revertable.getId(), entity1.getId()); + assertEquals(revertableViaJPQL.getId(), entity1.getId()); + + // now make it look like upgrade ID 11 was reverted + entity1.setRevertAllowed(false); + entity1 = dao.merge(entity1); + + // create a downgrade for ID 11 + UpgradeEntity entity4 = new UpgradeEntity(); + entity4.setId(44L); + entity4.setClusterId(clusterId.longValue()); + entity4.setDirection(Direction.DOWNGRADE); + entity4.setRequestEntity(requestEntity); + entity4.setRepositoryVersion(repositoryVersion2500); + entity4.setUpgradeType(UpgradeType.ROLLING); + entity4.setUpgradePackage("test-upgrade"); + entity4.setOrchestration(RepositoryType.MAINT); + entity4.setDowngradeAllowed(false); + dao.create(entity4); + + revertable = dao.findRevertable(1L); + revertableViaJPQL = dao.findRevertableUsingJPQL(1L); + assertEquals(null, revertable); + assertEquals(null, revertableViaJPQL); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeContextTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeContextTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeContextTest.java index 500d229..5cf9a4c 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeContextTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeContextTest.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.internal.UpgradeResourceProvider; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; import org.apache.ambari.server.orm.dao.UpgradeDAO; @@ -138,6 +139,7 @@ public class UpgradeContextTest extends EasyMockSupport { m_upgradeDAO.findLastUpgradeForCluster(EasyMock.anyLong(), eq(Direction.UPGRADE))).andReturn(m_completedRevertableUpgrade).anyTimes(); + expect(m_completedRevertableUpgrade.getId()).andReturn(1L).anyTimes(); expect(m_completedRevertableUpgrade.getDirection()).andReturn(Direction.UPGRADE).anyTimes(); expect(m_completedRevertableUpgrade.getRepositoryVersion()).andReturn(m_targetRepositoryVersion).anyTimes(); expect(m_completedRevertableUpgrade.getOrchestration()).andReturn(RepositoryType.PATCH).anyTimes(); @@ -309,6 +311,8 @@ public class UpgradeContextTest extends EasyMockSupport { EasyMock.anyObject(UpgradeType.class), EasyMock.anyString())).andReturn(upgradePack).once(); + expect(m_upgradeDAO.findRevertable(1L)).andReturn(m_completedRevertableUpgrade).once(); + Map<String, Object> requestMap = new HashMap<>(); requestMap.put(UpgradeResourceProvider.UPGRADE_TYPE, UpgradeType.ROLLING.name()); requestMap.put(UpgradeResourceProvider.UPGRADE_REVERT_UPGRADE_ID, "1"); @@ -327,6 +331,52 @@ public class UpgradeContextTest extends EasyMockSupport { } /** + * Tests that if a different {@link UpgradeEntity} is returned instead of the one + * specified by the + * + * @throws Exception + */ + @Test(expected = AmbariException.class) + public void testWrongUpgradeBeingReverted() throws Exception { + Long upgradeIdBeingReverted = 1L; + Long upgradeIdWhichCanBeReverted = 99L; + + UpgradeHelper upgradeHelper = createNiceMock(UpgradeHelper.class); + ConfigHelper configHelper = createNiceMock(ConfigHelper.class); + + UpgradePack upgradePack = createNiceMock(UpgradePack.class); + + expect(upgradeHelper.suggestUpgradePack(EasyMock.anyString(), EasyMock.anyObject(StackId.class), + EasyMock.anyObject(StackId.class), EasyMock.anyObject(Direction.class), + EasyMock.anyObject(UpgradeType.class), EasyMock.anyString())).andReturn(upgradePack).once(); + + RepositoryVersionEntity repositoryVersionEntity = createNiceMock(RepositoryVersionEntity.class); + expect(repositoryVersionEntity.getVersion()).andReturn("1.2.3.4").anyTimes(); + + UpgradeEntity wrongRevertableUpgrade = createNiceMock(UpgradeEntity.class); + expect(wrongRevertableUpgrade.getId()).andReturn(upgradeIdWhichCanBeReverted).atLeastOnce(); + expect(wrongRevertableUpgrade.getRepositoryVersion()).andReturn(repositoryVersionEntity).atLeastOnce(); + + expect(m_upgradeDAO.findRevertable(1L)).andReturn(wrongRevertableUpgrade).once(); + + Map<String, Object> requestMap = new HashMap<>(); + requestMap.put(UpgradeResourceProvider.UPGRADE_TYPE, UpgradeType.ROLLING.name()); + requestMap.put(UpgradeResourceProvider.UPGRADE_REVERT_UPGRADE_ID, upgradeIdBeingReverted.toString()); + + replayAll(); + + UpgradeContext context = new UpgradeContext(m_cluster, requestMap, null, upgradeHelper, + m_upgradeDAO, m_repositoryVersionDAO, configHelper); + + assertEquals(Direction.DOWNGRADE, context.getDirection()); + assertEquals(RepositoryType.PATCH, context.getOrchestrationType()); + assertEquals(1, context.getSupportedServices().size()); + assertTrue(context.isPatchRevert()); + + verifyAll(); + } + + /** * Tests that the {@link UpgradeContext} for a patch downgrade has the * correcting scope/orchestration set. * http://git-wip-us.apache.org/repos/asf/ambari/blob/313e3bf0/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java index 427cadd..2e16754 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java @@ -180,7 +180,8 @@ public class UpgradeCatalog260Test { Capture<DBColumnInfo> rvid = newCapture(); Capture<DBColumnInfo> orchestration = newCapture(); - expectUpdateUpgradeTable(rvid, orchestration); + Capture<DBColumnInfo> revertAllowed = newCapture(); + expectUpdateUpgradeTable(rvid, orchestration, revertAllowed); Capture<List<DBAccessor.DBColumnInfo>> columns = newCapture(); expectCreateUpgradeHistoryTable(columns); @@ -215,7 +216,7 @@ public class UpgradeCatalog260Test { verifyUpdateServiceComponentDesiredStateTable(scdstadd1, scdstalter1, scdstadd2, scdstalter2); verifyUpdateServiceDesiredStateTable(sdstadd, sdstalter); verifyAddSelectedCollumsToClusterconfigTable(selectedColumnInfo, selectedmappingColumnInfo, selectedTimestampColumnInfo, createTimestampColumnInfo); - verifyUpdateUpgradeTable(rvid, orchestration); + verifyUpdateUpgradeTable(rvid, orchestration, revertAllowed); verifyCreateUpgradeHistoryTable(columns); verifyUpdateRepositoryVersionTableTable(repoVersionHiddenColumnCapture); } @@ -298,7 +299,8 @@ public class UpgradeCatalog260Test { expectLastCall().once(); } - public void verifyUpdateUpgradeTable(Capture<DBColumnInfo> rvid, Capture<DBColumnInfo> orchestration) { + public void verifyUpdateUpgradeTable(Capture<DBColumnInfo> rvid, + Capture<DBColumnInfo> orchestration, Capture<DBColumnInfo> revertAllowed) { DBColumnInfo rvidValue = rvid.getValue(); Assert.assertEquals(UpgradeCatalog260.REPO_VERSION_ID_COLUMN, rvidValue.getName()); Assert.assertEquals(Long.class, rvidValue.getType()); @@ -312,25 +314,43 @@ public class UpgradeCatalog260Test { Assert.assertEquals(Integer.valueOf(255), orchestrationValue.getLength()); Assert.assertEquals(UpgradeCatalog260.STANDARD, orchestrationValue.getDefaultValue()); Assert.assertEquals(false, orchestrationValue.isNullable()); + + DBColumnInfo revertAllowedValue = revertAllowed.getValue(); + Assert.assertEquals(UpgradeCatalog260.ALLOW_REVERT_COLUMN, revertAllowedValue.getName()); + Assert.assertEquals(Short.class, revertAllowedValue.getType()); + Assert.assertEquals(null, revertAllowedValue.getLength()); + Assert.assertEquals(0, revertAllowedValue.getDefaultValue()); + Assert.assertEquals(false, revertAllowedValue.isNullable()); } - public void expectUpdateUpgradeTable(Capture<DBColumnInfo> rvid, Capture<DBColumnInfo> orchestration) throws SQLException { + public void expectUpdateUpgradeTable(Capture<DBColumnInfo> rvid, + Capture<DBColumnInfo> orchestration, Capture<DBColumnInfo> revertAllowed) + throws SQLException { + dbAccessor.clearTable(eq(UpgradeCatalog260.UPGRADE_TABLE)); expectLastCall().once(); + dbAccessor.dropFKConstraint(eq(UpgradeCatalog260.UPGRADE_TABLE), eq(UpgradeCatalog260.FK_UPGRADE_FROM_REPO_ID)); expectLastCall().once(); + dbAccessor.dropFKConstraint(eq(UpgradeCatalog260.UPGRADE_TABLE), eq(UpgradeCatalog260.FK_UPGRADE_TO_REPO_ID)); expectLastCall().once(); + dbAccessor.dropColumn(eq(UpgradeCatalog260.UPGRADE_TABLE), eq(UpgradeCatalog260.FROM_REPO_VERSION_ID_COLUMN)); expectLastCall().once(); + dbAccessor.dropColumn(eq(UpgradeCatalog260.UPGRADE_TABLE), eq(UpgradeCatalog260.TO_REPO_VERSION_ID_COLUMN)); expectLastCall().once(); dbAccessor.addColumn(eq(UpgradeCatalog260.UPGRADE_TABLE), capture(rvid)); expectLastCall().once(); + dbAccessor.addColumn(eq(UpgradeCatalog260.UPGRADE_TABLE), capture(orchestration)); expectLastCall().once(); + dbAccessor.addColumn(eq(UpgradeCatalog260.UPGRADE_TABLE), capture(revertAllowed)); + expectLastCall().once(); + dbAccessor.addFKConstraint(eq(UpgradeCatalog260.UPGRADE_TABLE), eq(UpgradeCatalog260.FK_UPGRADE_REPO_VERSION_ID), eq(UpgradeCatalog260.REPO_VERSION_ID_COLUMN), eq(UpgradeCatalog260.REPO_VERSION_TABLE), eq(UpgradeCatalog260.REPO_VERSION_ID_COLUMN), eq(false)); expectLastCall().once(); } @@ -486,7 +506,7 @@ public class UpgradeCatalog260Test { @Test public void testRemoveDruidSuperset() throws Exception { - List<Integer> current = new ArrayList<Integer>(); + List<Integer> current = new ArrayList<>(); current.add(1); expect(dbAccessor.getConnection()).andReturn(connection).anyTimes();