You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/05/31 20:12:51 UTC

[20/50] [abbrv] ambari git commit: AMBARI-21022 - Upgrades Should Be Associated With Repositories Instead of String Versions (jonathanhurley)

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 a68a2e1..db58d27 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
@@ -17,31 +17,65 @@
  */
 package org.apache.ambari.server.state;
 
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.VERSION;
+import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_CLUSTER_NAME;
+import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_DIRECTION;
+import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_FAIL_ON_CHECK_WARNINGS;
+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_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;
+import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_SC_FAILURES;
+import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_TYPE;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 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.actionmanager.HostRoleCommandFactory;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.internal.AbstractControllerResourceProvider;
+import org.apache.ambari.server.controller.internal.PreUpgradeCheckResourceProvider;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
+import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
+import org.apache.ambari.server.state.repository.VersionDefinitionXml;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 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.Grouping;
+import org.apache.ambari.server.state.stack.upgrade.HostOrderGrouping;
+import org.apache.ambari.server.state.stack.upgrade.HostOrderItem;
+import org.apache.ambari.server.state.stack.upgrade.HostOrderItem.HostOrderActionType;
 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 com.google.common.base.Objects;
 import com.google.gson.Gson;
@@ -51,11 +85,12 @@ import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 
 /**
- * Used to hold various helper objects required to process an upgrade pack.
+ * The {@link UpgradeContext} is used to hold all information pertaining to an
+ * upgrade. It is initialized directly from an existing {@link UpgradeEntity} or
+ * from a request to create an upgrade/downgrade.
  */
 public class UpgradeContext {
 
-  public static final String COMMAND_PARAM_VERSION = VERSION;
   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";
@@ -64,21 +99,6 @@ public class UpgradeContext {
   public static final String COMMAND_PARAM_UPGRADE_TYPE = "upgrade_type";
   public static final String COMMAND_PARAM_TASKS = "tasks";
   public static final String COMMAND_PARAM_STRUCT_OUT = "structured_out";
-  public static final String COMMAND_DOWNGRADE_FROM_VERSION = "downgrade_from_version";
-
-  /**
-   * The original "current" stack of the cluster before the upgrade started.
-   * This is the same regardless of whether the current direction is
-   * {@link Direction#UPGRADE} or {@link Direction#DOWNGRADE}.
-   */
-  public static final String COMMAND_PARAM_ORIGINAL_STACK = "original_stack";
-
-  /**
-   * The target upgrade stack before the upgrade started. This is the same
-   * regardless of whether the current direction is {@link Direction#UPGRADE} or
-   * {@link Direction#DOWNGRADE}.
-   */
-  public static final String COMMAND_PARAM_TARGET_STACK = "target_stack";
 
   /**
    * The cluster that the upgrade is for.
@@ -106,50 +126,37 @@ public class UpgradeContext {
   private UpgradePack m_upgradePack;
 
   /**
-   * The version being upgrade to or downgraded to.
-   */
-  private final String m_version;
-
-  /**
-   * The original "current" stack of the cluster before the upgrade started.
-   * This is the same regardless of whether the current direction is
-   * {@link Direction#UPGRADE} or {@link Direction#DOWNGRADE}.
+   * Upgrades will always have a single version being upgraded to and downgrades
+   * will have a single version being downgraded from. This repository
+   * represents that version.
+   * <p/>
+   * When the direction is {@link Direction#UPGRADE}, this represents the target
+   * repository. <br/>
+   * When the direction is {@link Direction#DOWNGRADE}, this represents the
+   * repository being downgraded from.
    */
-  private StackId m_originalStackId;
+  private final RepositoryVersionEntity m_repositoryVersion;
 
   /**
-   * The stack currently used to start/restart services during an upgrade.This is the same
-   * During a {@link UpgradeType#ROLLING} upgrade, this is always the {@link this.m_targetStackId},
-   * During a {@link UpgradeType#NON_ROLLING} upgrade, this is initially the {@link this.m_sourceStackId} while
-   * stopping services, and then changes to the {@link this.m_targetStackId} when starting services.
+   * Resolves master components on hosts.
    */
-  private StackId m_effectiveStackId;
+  private final MasterHostResolver m_resolver;
 
   /**
-   * The target upgrade stack before the upgrade started. This is the same
-   * regardless of whether the current direction is {@link Direction#UPGRADE} or
-   * {@link Direction#DOWNGRADE}.
+   * A collection of hosts in the cluster which are unhealthy and will not
+   * participate in the upgrade.
    */
-  private StackId m_targetStackId;
+  private final List<ServiceComponentHost> m_unhealthy = new ArrayList<>();
 
   /**
-   * The target repository before the upgrade started. This is the same
-   * regardless of whether the current direction is {@link Direction#UPGRADE} or
-   * {@link Direction#DOWNGRADE}.
+   * Mapping of service name to display name.
    */
-  private RepositoryVersionEntity m_targetRepositoryVersion;
+  private final Map<String, String> m_serviceNames = new HashMap<>();
 
   /**
-   * Optionally set if {@link #setDowngradeFromVersion(String)} is called.
+   * Mapping of component name to display name.
    */
-  private RepositoryVersionEntity m_downgradeFromRepositoryVersion;
-
-  private MasterHostResolver m_resolver;
-  private AmbariMetaInfo m_metaInfo;
-  private List<ServiceComponentHost> m_unhealthy = new ArrayList<>();
-  private Map<String, String> m_serviceNames = new HashMap<>();
-  private Map<String, String> m_componentNames = new HashMap<>();
-  private String m_downgradeFromVersion = null;
+  private final Map<String, String> m_componentNames = new HashMap<>();
 
   /**
    * {@code true} if slave/client component failures should be automatically
@@ -170,9 +177,19 @@ public class UpgradeContext {
    */
   private boolean m_autoSkipManualVerification = false;
 
-  private Set<String> m_supported = new HashSet<>();
+  /**
+   * A set of services which are included in this upgrade. If this is empty,
+   * then all cluster services are included.
+   */
+  private Set<String> m_services = new HashSet<>();
 
-  private UpgradeScope m_scope = UpgradeScope.ANY;
+  /**
+   * A mapping of service to target repository. On an upgrade, this will be the
+   * same for all services. On a downgrade, this may be different for each
+   * service depending on which repository the service was on before the failed
+   * upgrade.
+   */
+  private final Map<String, RepositoryVersionEntity> m_targetRepositoryMap = new HashMap<>();
 
   /**
    * Used by some {@link Grouping}s to generate commands. It is exposed here
@@ -189,45 +206,183 @@ public class UpgradeContext {
   private RoleGraphFactory m_roleGraphFactory;
 
   /**
-   * Used to lookup the reposotory version given a stack name and version.
+   * Used for serializing the upgrade type.
    */
-  final private RepositoryVersionDAO m_repoVersionDAO;
+  @Inject
+  private Gson m_gson;
 
   /**
-   * Used for serializing the upgrade type.
+   * Used for looking up information about components and services.
    */
   @Inject
-  private Gson m_gson;
+  private AmbariMetaInfo m_metaInfo;
 
   /**
-   * Constructor.
-   *
-   * @param cluster
-   *          the cluster that the upgrade is for
-   * @param type
-   *          the type of upgrade, either rolling or non_rolling
-   * @param direction
-   *          the direction for the upgrade
-   * @param upgradeRequestMap
-   *          the original map of paramters used to create the upgrade
-   *
-   * @param repoVersionDAO
-   *          the repository version DAO.
+   * Used to suggest upgrade packs during creation of an upgrade context.
+   */
+  @Inject
+  private UpgradeHelper m_upgradeHelper;
+
+  /**
+   * Used to lookup the repository version from an ID.
+   */
+  @Inject
+  private RepositoryVersionDAO m_repoVersionDAO;
+
+  /**
+   * Used to lookup a prior upgrade by ID.
    */
+  @Inject
+  private UpgradeDAO m_upgradeDAO;
+
   @AssistedInject
-  public UpgradeContext(@Assisted Cluster cluster, @Assisted UpgradeType type,
-      @Assisted Direction direction, @Assisted String version,
-      @Assisted Map<String, Object> upgradeRequestMap,
-      RepositoryVersionDAO repoVersionDAO) {
+  public UpgradeContext(@Assisted Cluster cluster,
+      @Assisted Map<String, Object> upgradeRequestMap, Gson gson, UpgradeHelper upgradeHelper,
+      UpgradeDAO upgradeDAO, RepositoryVersionDAO repoVersionDAO, ConfigHelper configHelper)
+      throws AmbariException {
+    // injected constructor dependencies
+    m_gson = gson;
+    m_upgradeHelper = upgradeHelper;
+    m_upgradeDAO = upgradeDAO;
     m_repoVersionDAO = repoVersionDAO;
+
     m_cluster = cluster;
-    m_type = type;
-    m_direction = direction;
-    m_version = version;
     m_upgradeRequestMap = upgradeRequestMap;
 
-    // sets the original/target stacks - requires direction and cluster
-    setSourceAndTargetVersions();
+    // determine direction
+    String directionProperty = (String) m_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) m_upgradeRequestMap.get(UPGRADE_TYPE);
+    if (StringUtils.isNotBlank(upgradeTypeProperty)) {
+      try {
+        m_type = UpgradeType.valueOf(m_upgradeRequestMap.get(UPGRADE_TYPE).toString());
+      } catch (Exception e) {
+        throw new AmbariException(String.format("Property %s has an incorrect value of %s.",
+            UPGRADE_TYPE, upgradeTypeProperty));
+      }
+    } else {
+      // default type
+      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) m_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));
+        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);
+            }
+
+          } 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);
+          }
+        }
+
+        // populate the target repository map for all services in the upgrade
+        for (String service : m_services) {
+          m_targetRepositoryMap.put(service, m_repositoryVersion);
+        }
+
+        break;
+      }
+      case DOWNGRADE:{
+        UpgradeEntity upgrade = m_upgradeDAO.findLastUpgradeForCluster(
+            cluster.getClusterId(), Direction.UPGRADE);
+
+        m_repositoryVersion = upgrade.getRepositoryVersion();
+
+        // populate the target repository map for all services in the upgrade
+        for (UpgradeHistoryEntity history : upgrade.getHistory()) {
+          m_services.add(history.getServiceName());
+          m_targetRepositoryMap.put(history.getServiceName(), history.getFromReposistoryVersion());
+        }
+
+        break;
+      }
+      default:
+        m_repositoryVersion = null;
+        break;
+    }
+
+
+    /**
+     * For the unit tests tests, there are multiple upgrade packs for the same
+     * type, so allow picking one of them. In prod, this is empty.
+     */
+    String preferredUpgradePackName = (String) m_upgradeRequestMap.get(UPGRADE_PACK);
+
+    @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES, comment="This is wrong")
+    String upgradePackFromVersion = cluster.getService(
+        m_services.iterator().next()).getDesiredRepositoryVersion().getVersion();
+
+    m_upgradePack = m_upgradeHelper.suggestUpgradePack(m_cluster.getClusterName(),
+        upgradePackFromVersion, m_repositoryVersion.getVersion(), m_direction, m_type,
+        preferredUpgradePackName);
+
+    // the validator will throw an exception if the upgrade request is not valid
+    UpgradeRequestValidator upgradeRequestValidator = buildValidator(m_type);
+    upgradeRequestValidator.validate(this);
+
+    // optionally skip failures - this can be supplied on either the request or
+    // in the upgrade pack explicitely, however the request will always override
+    // the upgrade pack if explicitely specified
+    boolean skipComponentFailures = m_upgradePack.isComponentFailureAutoSkipped();
+    boolean skipServiceCheckFailures = m_upgradePack.isServiceCheckFailureAutoSkipped();
+
+    // only override the upgrade pack if set on the request
+    if (m_upgradeRequestMap.containsKey(UPGRADE_SKIP_FAILURES)) {
+      skipComponentFailures = Boolean.parseBoolean(
+          (String) m_upgradeRequestMap.get(UPGRADE_SKIP_FAILURES));
+    }
+
+    // only override the upgrade pack if set on the request
+    if (m_upgradeRequestMap.containsKey(UPGRADE_SKIP_SC_FAILURES)) {
+      skipServiceCheckFailures = Boolean.parseBoolean(
+          (String) m_upgradeRequestMap.get(UPGRADE_SKIP_SC_FAILURES));
+    }
+
+    boolean skipManualVerification = false;
+    if (m_upgradeRequestMap.containsKey(UPGRADE_SKIP_MANUAL_VERIFICATION)) {
+      skipManualVerification = Boolean.parseBoolean(
+          (String) m_upgradeRequestMap.get(UPGRADE_SKIP_MANUAL_VERIFICATION));
+    }
+
+    m_autoSkipComponentFailures = skipComponentFailures;
+    m_autoSkipServiceCheckFailures = skipServiceCheckFailures;
+    m_autoSkipManualVerification = skipManualVerification;
+
+    m_resolver = new MasterHostResolver(configHelper, this);
   }
 
   /**
@@ -242,82 +397,39 @@ public class UpgradeContext {
    */
   @AssistedInject
   public UpgradeContext(@Assisted Cluster cluster, @Assisted UpgradeEntity upgradeEntity,
-      RepositoryVersionDAO repoVersionDAO) {
-    m_repoVersionDAO = repoVersionDAO;
+      AmbariMetaInfo ambariMetaInfo, ConfigHelper configHelper) {
+    m_metaInfo = ambariMetaInfo;
 
     m_cluster = cluster;
     m_type = upgradeEntity.getUpgradeType();
     m_direction = upgradeEntity.getDirection();
-
-    m_version = upgradeEntity.getToVersion();
-
-    // sets the original/target stacks - requires direction and cluster
-    setSourceAndTargetVersions();
-
-    if (m_direction == Direction.DOWNGRADE) {
-      setDowngradeFromVersion(upgradeEntity.getFromVersion());
-    }
-
-    // since this constructor is initialized from an entity, then this map is
-    // not present
-    m_upgradeRequestMap = Collections.emptyMap();
+    m_repositoryVersion = upgradeEntity.getRepositoryVersion();
 
     m_autoSkipComponentFailures = upgradeEntity.isComponentFailureAutoSkipped();
     m_autoSkipServiceCheckFailures = upgradeEntity.isServiceCheckFailureAutoSkipped();
-  }
 
-  /**
-   * Sets the source and target versions. This will also set the effective stack
-   * ID based on the already-set {@link UpgradeType} and {@link Direction}.
-   *
-   * @see #getEffectiveStackId()
-   */
-  private void setSourceAndTargetVersions() {
-    StackId sourceStackId = null;
-
-    // taret stack will not always be what it is today - tagging as experimental
-    @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-    StackId targetStackId = null;
-
-    switch (m_direction) {
-      case UPGRADE:
-        sourceStackId = m_cluster.getCurrentStackVersion();
-
-        m_targetRepositoryVersion = m_repoVersionDAO.findByStackNameAndVersion(
-            sourceStackId.getStackName(), m_version);
-
-        // !!! TODO check the repo_version for patch-ness and restrict the
-        // context to those services that require it. Consult the version
-        // definition and add the service names to supportedServices
-        targetStackId = m_targetRepositoryVersion.getStackId();
-        break;
-      case DOWNGRADE:
-        sourceStackId = m_cluster.getCurrentStackVersion();
-        targetStackId = m_cluster.getDesiredStackVersion();
-
-        m_targetRepositoryVersion = m_repoVersionDAO.findByStackNameAndVersion(
-            targetStackId.getStackName(), m_version);
-        break;
+    List<UpgradeHistoryEntity> allHistory = upgradeEntity.getHistory();
+    for (UpgradeHistoryEntity history : allHistory) {
+      String serviceName = history.getServiceName();
+      RepositoryVersionEntity targetRepositoryVersion = history.getTargetRepositoryVersion();
+      m_targetRepositoryMap.put(serviceName, targetRepositoryVersion);
+      m_services.add(serviceName);
     }
 
-    m_originalStackId = sourceStackId;
+    @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES, comment = "This is wrong")
+    String upgradePackage = upgradeEntity.getUpgradePackage();
+    StackId stackId = m_repositoryVersion.getStackId();
+    Map<String, UpgradePack> packs = m_metaInfo.getUpgradePacks(stackId.getStackName(), stackId.getStackVersion());
+    m_upgradePack = packs.get(upgradePackage);
 
-    switch (m_type) {
-      case ROLLING:
-      case HOST_ORDERED:
-        m_effectiveStackId = targetStackId;
-        break;
-      case NON_ROLLING:
-        m_effectiveStackId = (m_direction.isUpgrade()) ? sourceStackId : targetStackId;
-        break;
-      default:
-        m_effectiveStackId = targetStackId;
-        break;
-    }
+    m_resolver = new MasterHostResolver(configHelper, this);
 
-    m_targetStackId = m_targetRepositoryVersion.getStackId();
+    // since this constructor is initialized from an entity, then this map is
+    // not present
+    m_upgradeRequestMap = Collections.emptyMap();
   }
 
+
   /**
    * Gets the original mapping of key/value pairs from the request which created
    * the upgrade.
@@ -358,10 +470,49 @@ public class UpgradeContext {
   }
 
   /**
+   * Gets the version being upgraded to or downgraded to for all services
+   * participating. 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
+   * same repository version. However, {@link Direction#DOWNGRADE} will target
+   * the original repository that the service was on.
+   *
+   * @return the target version for the upgrade
+   */
+  public Map<String, RepositoryVersionEntity> getTargetVersions() {
+    return new HashMap<>(m_targetRepositoryMap);
+  }
+
+  /**
+   * Gets the repository being upgraded to or downgraded to for the given
+   * 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
+   * same repository version. However, {@link Direction#DOWNGRADE} will target
+   * the original repository that the service was on.
+   *
+   * @return the target repository for the upgrade
+   */
+  public RepositoryVersionEntity getTargetRepositoryVersion(String serviceName) {
+    return m_targetRepositoryMap.get(serviceName);
+  }
+
+  /**
+   * Gets the version being upgraded to or downgraded to for the given 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
+   * same repository version. However, {@link Direction#DOWNGRADE} will target
+   * the original repository that the service was on.
+   *
    * @return the target version for the upgrade
    */
-  public String getVersion() {
-    return m_version;
+  public String getTargetVersion(String serviceName) {
+    RepositoryVersionEntity serviceTargetVersion = m_targetRepositoryMap.get(serviceName);
+    return serviceTargetVersion.getVersion();
   }
 
   /**
@@ -379,16 +530,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Sets the host resolver.
-   *
-   * @param resolver
-   *          the resolver that also references the required cluster
-   */
-  public void setResolver(MasterHostResolver resolver) {
-    m_resolver = resolver;
-  }
-
-  /**
    * @return the resolver
    */
   public MasterHostResolver getResolver() {
@@ -403,13 +544,6 @@ public class UpgradeContext {
   }
 
   /**
-   * @param metaInfo the metainfo for access to service definitions
-   */
-  public void setAmbariMetaInfo(AmbariMetaInfo metaInfo) {
-    m_metaInfo = metaInfo;
-  }
-
-  /**
    * @param unhealthy a list of unhealthy host components
    */
   public void addUnhealthy(List<ServiceComponentHost> unhealthy) {
@@ -417,50 +551,20 @@ public class UpgradeContext {
   }
 
   /**
-   * @return the originalStackId
-   */
-  public StackId getOriginalStackId() {
-    return m_originalStackId;
-  }
-
-  /**
-   * @param originalStackId
-   *          the originalStackId to set
-   */
-  public void setOriginalStackId(StackId originalStackId) {
-    m_originalStackId = originalStackId;
-  }
-
-  /**
-   * @return the effectiveStackId that is currently in use.
-   */
-  public StackId getEffectiveStackId() {
-    return m_effectiveStackId;
-  }
-
-  /**
-   * @param effectiveStackId the effectiveStackId to set
-   */
-  public void setEffectiveStackId(StackId effectiveStackId) {
-    m_effectiveStackId = effectiveStackId;
-  }
-
-
-  /**
-   * @return the targetStackId
-   */
-  public StackId getTargetStackId() {
-    return m_targetStackId;
-  }
-
-  /**
-   * Gets the target repository version for this upgrade.
+   * Gets the single repository version for the upgrade depending on the
+   * direction.
+   * <p/>
+   * If the direction is {@link Direction#UPGRADE} then this will return the
+   * target repository which every service will be on if the upgrade is
+   * finalized. <br/>
+   * If the direction is {@link Direction#DOWNGRADE} then this will return the
+   * repository from which the downgrade is coming from.
    *
    * @return the target repository version for this upgrade (never
    *         {@code null}).
    */
-  public RepositoryVersionEntity getTargetRepositoryVersion() {
-    return m_targetRepositoryVersion;
+  public RepositoryVersionEntity getRepositoryVersion() {
+    return m_repositoryVersion;
   }
 
   /**
@@ -505,38 +609,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Optionally set if doing a downgrade. Represents the non-finalized version
-   * being downgraded from.
-   *
-   * @return version cluster is downgrading from
-   */
-  public String getDowngradeFromVersion() {
-    return m_downgradeFromVersion;
-  }
-
-  /**
-   * Optionally set if doing a downgrade. Represents the non-finalized version
-   * being downgraded from.
-   *
-   * @return
-   */
-  public RepositoryVersionEntity getDowngradeFromRepositoryVersion() {
-    return m_downgradeFromRepositoryVersion;
-  }
-
-  /**
-   * Set the HDP stack version we are downgrading from.
-   *
-   * @param downgradeFromVersion
-   */
-  public void setDowngradeFromVersion(String downgradeFromVersion) {
-    m_downgradeFromVersion = downgradeFromVersion;
-
-    m_downgradeFromRepositoryVersion = m_repoVersionDAO.findByStackAndVersion(m_targetStackId,
-        downgradeFromVersion);
-  }
-
-  /**
    * Gets whether skippable components that failed are automatically skipped.
    *
    * @return the skipComponentFailures
@@ -546,17 +618,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Sets whether skippable components that failed are automatically skipped.
-   *
-   * @param autoSkipComponentFailures
-   *          {@code true} to automatically skip component failures which are
-   *          marked as skippable.
-   */
-  public void setAutoSkipComponentFailures(boolean autoSkipComponentFailures) {
-    m_autoSkipComponentFailures = autoSkipComponentFailures;
-  }
-
-  /**
    * Gets whether skippable service checks that failed are automatically
    * skipped.
    *
@@ -567,18 +628,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Sets whether skippable service checks that failed are automatically
-   * skipped.
-   *
-   * @param autoSkipServiceCheckFailures
-   *          {@code true} to automatically skip service check failures which
-   *          are marked as being skippable.
-   */
-  public void setAutoSkipServiceCheckFailures(boolean autoSkipServiceCheckFailures) {
-    m_autoSkipServiceCheckFailures = autoSkipServiceCheckFailures;
-  }
-
-  /**
    * Gets whether manual verification tasks can be automatically skipped.
    *
    * @return the skipManualVerification
@@ -588,58 +637,43 @@ public class UpgradeContext {
   }
 
   /**
-   * Sets whether manual verification checks are automatically skipped.
-   *
-   * @param autoSkipManualVerification
-   *          {@code true} to automatically skip manual verification tasks.
-   */
-  public void setAutoSkipManualVerification(boolean autoSkipManualVerification) {
-    m_autoSkipManualVerification = autoSkipManualVerification;
-  }
-
-  /**
-   * Sets the service names that are supported by an upgrade.  This is used for
-   * {@link RepositoryType#PATCH} and {@link RepositoryType#SERVICE}.
+   * Gets the services participating in the upgrade.
    *
-   * @param services  the set of specific services
-   */
-  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
-  public void setSupportedServices(Set<String> services) {
-    m_supported = services;
-  }
-
-  /**
-   * @return the set of supported services, or an empty set if ALL services
-   * are supported
+   * @return the set of supported services. This collection should never be
+   *         empty.
    */
   @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
   public Set<String> getSupportedServices() {
-    return Collections.unmodifiableSet(m_supported);
+    return Collections.unmodifiableSet(m_services);
   }
 
   /**
-   * Gets if a service is supported.  If there are no services marked for the context,
-   * then ALL services are supported
-   * @param serviceName the service name to check.
+   * Gets if a service is supported.
+   *
+   * @param serviceName
+   *          the service name to check.
    * @return {@code true} when the service is supported
    */
   @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
   public boolean isServiceSupported(String serviceName) {
-    if (m_supported.isEmpty() || m_supported.contains(serviceName)) {
+    return m_services.contains(serviceName);
+  }
+
+  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
+  public boolean isScoped(UpgradeScope scope) {
+    if (scope == UpgradeScope.ANY) {
       return true;
     }
 
-    return false;
-  }
-
-  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
-  public void setScope(UpgradeScope scope) {
-    m_scope = scope;
-  }
+    switch (m_repositoryVersion.getType()) {
+      case PATCH:
+      case SERVICE:
+        return scope == UpgradeScope.PARTIAL;
+      case STANDARD:
+        return scope == UpgradeScope.COMPLETE;
+    }
 
-  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
-  public boolean isScoped(UpgradeScope scope) {
-    return m_scope.isScoped(scope);
+    return false;
   }
 
   /**
@@ -661,15 +695,21 @@ public class UpgradeContext {
   }
 
   /**
+   * Gets the repository type to determine if this upgrade is a complete upgrade
+   * or a service/patch.
+   *
+   * @return the repository type.
+   */
+  public RepositoryType getRepositoryType() {
+    return m_repositoryVersion.getType();
+  }
+
+  /**
    * Gets a map initialized with parameters required for upgrades to work. The
    * following properties are already set:
    * <ul>
    * <li>{@link #COMMAND_PARAM_CLUSTER_NAME}
-   * <li>{@link #COMMAND_PARAM_VERSION}
    * <li>{@link #COMMAND_PARAM_DIRECTION}
-   * <li>{@link #COMMAND_PARAM_ORIGINAL_STACK}
-   * <li>{@link #COMMAND_PARAM_TARGET_STACK}
-   * <li>{@link #COMMAND_DOWNGRADE_FROM_VERSION}
    * <li>{@link #COMMAND_PARAM_UPGRADE_TYPE}
    * <li>{@link KeyNames#REFRESH_CONFIG_TAGS_BEFORE_EXECUTION} - necessary in
    * order to have the commands contain the correct configurations. Otherwise,
@@ -685,11 +725,7 @@ public class UpgradeContext {
     Map<String, String> parameters = new HashMap<>();
 
     parameters.put(COMMAND_PARAM_CLUSTER_NAME, m_cluster.getClusterName());
-    parameters.put(COMMAND_PARAM_VERSION, getVersion());
     parameters.put(COMMAND_PARAM_DIRECTION, getDirection().name().toLowerCase());
-    parameters.put(COMMAND_PARAM_ORIGINAL_STACK, getOriginalStackId().getStackId());
-    parameters.put(COMMAND_PARAM_TARGET_STACK, getTargetStackId().getStackId());
-    parameters.put(COMMAND_DOWNGRADE_FROM_VERSION, getDowngradeFromVersion());
 
     if (null != getType()) {
       // use the serialized attributes of the enum to convert it to a string,
@@ -712,6 +748,328 @@ public class UpgradeContext {
     return Objects.toStringHelper(this)
         .add("direction", m_direction)
         .add("type", m_type)
-        .add("target",m_targetRepositoryVersion).toString();
+        .add("target", m_repositoryVersion).toString();
+  }
+
+  /**
+   * Builds a chain of {@link UpgradeRequestValidator}s to ensure that the
+   * incoming request to create a new upgrade is valid.
+   *
+   * @param upgradeType
+   *          the type of upgrade to build the validator for.
+   * @return the validator which can check to ensure that the properties are
+   *         valid.
+   */
+  private UpgradeRequestValidator buildValidator(UpgradeType upgradeType){
+    UpgradeRequestValidator validator = new BasicUpgradePropertiesValidator();
+    UpgradeRequestValidator preReqValidator = new PreReqCheckValidator();
+    validator.setNextValidator(preReqValidator);
+
+    final UpgradeRequestValidator upgradeTypeValidator;
+    switch( upgradeType ){
+      case HOST_ORDERED:
+        upgradeTypeValidator = new HostOrderedUpgradeValidator();
+        break;
+      case NON_ROLLING:
+      case ROLLING:
+      default:
+        upgradeTypeValidator = null;
+        break;
+    }
+
+    preReqValidator.setNextValidator(upgradeTypeValidator);
+    return validator;
+  }
+
+  /**
+   * The {@link UpgradeRequestValidator} contains the logic to check for correct
+   * upgrade request properties and then pass the responsibility onto the next
+   * validator in the chain.
+   */
+  private abstract class UpgradeRequestValidator {
+    /**
+     * The next validator.
+     */
+    UpgradeRequestValidator m_nextValidator;
+
+    /**
+     * Sets the next validator in the chain.
+     *
+     * @param nextValidator
+     *          the next validator to run, or {@code null} for none.
+     */
+    void setNextValidator(UpgradeRequestValidator nextValidator) {
+      m_nextValidator = nextValidator;
+    }
+
+    /**
+     * Validates the upgrade request from this point in the chain.
+     *
+     * @param upgradeContext
+     * @param upgradePack
+     * @throws AmbariException
+     */
+    final void validate(UpgradeContext upgradeContext)
+        throws AmbariException {
+
+      // run this instance's check
+      check(upgradeContext, upgradeContext.getUpgradePack());
+
+      // pass along to the next
+      if( null != m_nextValidator ) {
+        m_nextValidator.validate(upgradeContext);
+      }
+    }
+
+    /**
+     * Checks to ensure that upgrade request is valid given the specific
+     * arguments.
+     *
+     * @param upgradeContext
+     * @param upgradePack
+     *
+     * @throws AmbariException
+     */
+    abstract void check(UpgradeContext upgradeContext, UpgradePack upgradePack)
+        throws AmbariException;
+  }
+
+  /**
+   * The {@link BasicUpgradePropertiesValidator} ensures that the basic required
+   * properties are present on the upgrade request.
+   */
+  private final class BasicUpgradePropertiesValidator extends UpgradeRequestValidator {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void check(UpgradeContext upgradeContext, UpgradePack upgradePack)
+        throws AmbariException {
+      Map<String, Object> requestMap = upgradeContext.getUpgradeRequest();
+
+      String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);
+      String direction = (String) requestMap.get(UPGRADE_DIRECTION);
+
+      if (StringUtils.isBlank(clusterName)) {
+        throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
+      }
+
+      if (StringUtils.isBlank(direction)) {
+        throw new AmbariException(String.format("%s is required", UPGRADE_DIRECTION));
+      }
+
+      if (Direction.valueOf(direction) == Direction.UPGRADE) {
+        String repositoryVersionId = (String) requestMap.get(UPGRADE_REPO_VERSION_ID);
+        if (StringUtils.isBlank(repositoryVersionId)) {
+          throw new AmbariException(
+              String.format("%s is required for upgrades", UPGRADE_REPO_VERSION_ID));
+        }
+      }
+    }
+  }
+
+  /**
+   * The {@link PreReqCheckValidator} ensures that the upgrade pre-requisite
+   * checks have passed.
+   */
+  private final class PreReqCheckValidator extends UpgradeRequestValidator {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    void check(UpgradeContext upgradeContext, UpgradePack upgradePack) throws AmbariException {
+      Cluster cluster = upgradeContext.getCluster();
+      Direction direction = upgradeContext.getDirection();
+      Map<String, Object> requestMap = upgradeContext.getUpgradeRequest();
+      UpgradeType upgradeType = upgradeContext.getType();
+
+      String repositoryVersionId = (String) requestMap.get(UPGRADE_REPO_VERSION_ID);
+      boolean skipPrereqChecks = Boolean.parseBoolean((String) requestMap.get(UPGRADE_SKIP_PREREQUISITE_CHECKS));
+      boolean failOnCheckWarnings = Boolean.parseBoolean((String) requestMap.get(UPGRADE_FAIL_ON_CHECK_WARNINGS));
+      String preferredUpgradePack = requestMap.containsKey(UPGRADE_PACK) ? (String) requestMap.get(UPGRADE_PACK) : null;
+
+      // verify that there is not an upgrade or downgrade that is in progress or suspended
+      UpgradeEntity existingUpgrade = cluster.getUpgradeInProgress();
+      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),
+                existingUpgrade.getRequestId()));
+      }
+
+      // skip this check if it's a downgrade or we are instructed to skip it
+      if( direction.isDowngrade() || skipPrereqChecks ){
+        return;
+      }
+
+      RepositoryVersionEntity repositoryVersion = m_repoVersionDAO.findByPK(
+          Long.valueOf(repositoryVersionId));
+
+      // Validate pre-req checks pass
+      PreUpgradeCheckResourceProvider provider = (PreUpgradeCheckResourceProvider) AbstractControllerResourceProvider.getResourceProvider(
+          Resource.Type.PreUpgradeCheck);
+
+      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_UPGRADE_TYPE_PROPERTY_ID).equals(upgradeType).and().property(
+          PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID).equals(preferredUpgradePack).toPredicate();
+
+      Request preUpgradeCheckRequest = PropertyHelper.getReadRequest();
+
+      Set<Resource> preUpgradeCheckResources;
+      try {
+        preUpgradeCheckResources = provider.getResources(
+            preUpgradeCheckRequest, preUpgradeCheckPredicate);
+      } catch (NoSuchResourceException|SystemException|UnsupportedPropertyException|NoSuchParentResourceException e) {
+        throw new AmbariException(
+            String.format("Unable to perform %s. Prerequisite checks could not be run",
+                direction.getText(false), e));
+      }
+
+      List<Resource> failedResources = new LinkedList<>();
+      if (preUpgradeCheckResources != null) {
+        for (Resource res : preUpgradeCheckResources) {
+          PrereqCheckStatus prereqCheckStatus = (PrereqCheckStatus) res.getPropertyValue(
+              PreUpgradeCheckResourceProvider.UPGRADE_CHECK_STATUS_PROPERTY_ID);
+
+          if (prereqCheckStatus == PrereqCheckStatus.FAIL
+              || (failOnCheckWarnings && prereqCheckStatus == PrereqCheckStatus.WARNING)) {
+            failedResources.add(res);
+          }
+        }
+      }
+
+      if (!failedResources.isEmpty()) {
+        throw new AmbariException(
+            String.format("Unable to perform %s. Prerequisite checks failed %s",
+                direction.getText(false), m_gson.toJson(failedResources)));
+      }
+    }
+  }
+
+  /**
+   * Ensures that for {@link UpgradeType#HOST_ORDERED}, the properties supplied
+   * are valid.
+   */
+  @SuppressWarnings("unchecked")
+  private final class HostOrderedUpgradeValidator extends UpgradeRequestValidator {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    void check(UpgradeContext upgradeContext, UpgradePack upgradePack) throws AmbariException {
+      Cluster cluster = upgradeContext.getCluster();
+      Direction direction = upgradeContext.getDirection();
+      Map<String, Object> requestMap = upgradeContext.getUpgradeRequest();
+
+      String skipFailuresRequestProperty = (String) requestMap.get(UPGRADE_SKIP_FAILURES);
+      if (Boolean.parseBoolean(skipFailuresRequestProperty)) {
+        throw new AmbariException(
+            String.format("The %s property is not valid when creating a %s upgrade.",
+                UPGRADE_SKIP_FAILURES, UpgradeType.HOST_ORDERED));
+      }
+
+      String skipManualVerification = (String) requestMap.get(UPGRADE_SKIP_MANUAL_VERIFICATION);
+      if (Boolean.parseBoolean(skipManualVerification)) {
+        throw new AmbariException(
+            String.format("The %s property is not valid when creating a %s upgrade.",
+                UPGRADE_SKIP_MANUAL_VERIFICATION, UpgradeType.HOST_ORDERED));
+      }
+
+      if (!requestMap.containsKey(UPGRADE_HOST_ORDERED_HOSTS)) {
+        throw new AmbariException(
+            String.format("The %s property is required when creating a %s upgrade.",
+                UPGRADE_HOST_ORDERED_HOSTS, UpgradeType.HOST_ORDERED));
+      }
+
+      List<HostOrderItem> hostOrderItems = extractHostOrderItemsFromRequest(requestMap);
+      List<String> hostsFromRequest = new ArrayList<>(hostOrderItems.size());
+      for (HostOrderItem hostOrderItem : hostOrderItems) {
+        if (hostOrderItem.getType() == HostOrderActionType.HOST_UPGRADE) {
+          hostsFromRequest.addAll(hostOrderItem.getActionItems());
+        }
+      }
+
+      // ensure that all hosts for this cluster are accounted for
+      Collection<Host> hosts = cluster.getHosts();
+      Set<String> clusterHostNames = new HashSet<>(hosts.size());
+      for (Host host : hosts) {
+        clusterHostNames.add(host.getHostName());
+      }
+
+      Collection<String> disjunction = CollectionUtils.disjunction(hostsFromRequest,
+          clusterHostNames);
+
+      if (CollectionUtils.isNotEmpty(disjunction)) {
+        throw new AmbariException(String.format(
+            "The supplied list of hosts must match the cluster hosts in an upgrade of type %s. The following hosts are either missing or invalid: %s",
+            UpgradeType.HOST_ORDERED, StringUtils.join(disjunction, ", ")));
+      }
+
+      // verify that the upgradepack has the required grouping and set the
+      // action items on it
+      HostOrderGrouping hostOrderGrouping = null;
+      List<Grouping> groupings = upgradePack.getGroups(direction);
+      for (Grouping grouping : groupings) {
+        if (grouping instanceof HostOrderGrouping) {
+          hostOrderGrouping = (HostOrderGrouping) grouping;
+          hostOrderGrouping.setHostOrderItems(hostOrderItems);
+        }
+      }
+    }
+  }
+
+  /**
+   * Builds the list of {@link HostOrderItem}s from the upgrade request. If the
+   * upgrade request does not contain the hosts
+   *
+   * @param requestMap
+   *          the map of properties from the request (not {@code null}).
+   * @return the ordered list of actions to orchestrate for the
+   *         {@link UpgradeType#HOST_ORDERED} upgrade.
+   * @throws AmbariException
+   *           if the request properties are not valid.
+   */
+  @SuppressWarnings("unchecked")
+  private List<HostOrderItem> extractHostOrderItemsFromRequest(Map<String, Object> requestMap)
+      throws AmbariException {
+    // ewwww
+    Set<Map<String, List<String>>> hostsOrder = (Set<Map<String, List<String>>>) requestMap.get(
+        UPGRADE_HOST_ORDERED_HOSTS);
+
+    if (CollectionUtils.isEmpty(hostsOrder)) {
+      throw new AmbariException(
+          String.format("The %s property must be specified when using a %s upgrade type.",
+              UPGRADE_HOST_ORDERED_HOSTS, UpgradeType.HOST_ORDERED));
+    }
+
+    List<HostOrderItem> hostOrderItems = new ArrayList<>();
+
+    // extract all of the hosts so that we can ensure they are all accounted for
+    Iterator<Map<String, List<String>>> iterator = hostsOrder.iterator();
+    while (iterator.hasNext()) {
+      Map<String, List<String>> grouping = iterator.next();
+      List<String> hosts = grouping.get("hosts");
+      List<String> serviceChecks = grouping.get("service_checks");
+
+      if (CollectionUtils.isEmpty(hosts) && CollectionUtils.isEmpty(serviceChecks)) {
+        throw new AmbariException(String.format(
+            "The %s property must contain at least one object with either a %s or %s key",
+            UPGRADE_HOST_ORDERED_HOSTS, "hosts", "service_checks"));
+      }
+
+      if (CollectionUtils.isNotEmpty(hosts)) {
+        hostOrderItems.add(new HostOrderItem(HostOrderActionType.HOST_UPGRADE, hosts));
+      }
+
+      if (CollectionUtils.isNotEmpty(serviceChecks)) {
+        hostOrderItems.add(new HostOrderItem(HostOrderActionType.SERVICE_CHECK, serviceChecks));
+      }
+    }
+
+    return hostOrderItems;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContextFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContextFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContextFactory.java
index 4f15ee2..eaccd53 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContextFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContextFactory.java
@@ -19,9 +19,8 @@ package org.apache.ambari.server.state;
 
 import java.util.Map;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
-import org.apache.ambari.server.state.stack.upgrade.Direction;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 /**
  * The {@link UpgradeContextFactory} is used to create dependency-injected
@@ -34,22 +33,14 @@ public interface UpgradeContextFactory {
    *
    * @param cluster
    *          the cluster that the upgrade is for (not {@code null}).
-   * @param type
-   *          the type of upgrade, either rolling or non_rolling (not
-   *          {@code null}).
-   * @param direction
-   *          the direction for the upgrade
-   * @param version
-   *          the version being upgrade-to or downgraded-from (not
-   *          {@code null}).
    * @param upgradeRequestMap
    *          the original map of parameters used to create the upgrade (not
    *          {@code null}).
    *
    * @return an initialized {@link UpgradeContext}.
    */
-  UpgradeContext create(Cluster cluster, UpgradeType type, Direction direction,
-      String version, Map<String, Object> upgradeRequestMap);
+  UpgradeContext create(Cluster cluster, Map<String, Object> upgradeRequestMap)
+      throws AmbariException;
 
   /**
    * Creates an {@link UpgradeContext} which is injected with dependencies.

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
index 3ec907f..0f39e60 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
@@ -19,9 +19,9 @@ package org.apache.ambari.server.state;
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -263,7 +263,6 @@ public class UpgradeHelper {
   public List<UpgradeGroupHolder> createSequence(UpgradePack upgradePack,
       UpgradeContext context) throws AmbariException {
 
-    context.setAmbariMetaInfo(m_ambariMetaInfo.get());
     Cluster cluster = context.getCluster();
     MasterHostResolver mhr = context.getResolver();
 
@@ -541,7 +540,6 @@ public class UpgradeHelper {
   private String tokenReplace(UpgradeContext ctx, String source, String service, String component) {
     Cluster cluster = ctx.getCluster();
     MasterHostResolver mhr = ctx.getResolver();
-    String version = ctx.getVersion();
 
     String result = source;
 
@@ -578,7 +576,7 @@ public class UpgradeHelper {
           break;
         }
         case VERSION:
-          value = version;
+          value = ctx.getRepositoryVersion().getVersion();
           break;
         case DIRECTION_VERB:
         case DIRECTION_VERB_PROPER:
@@ -732,29 +730,17 @@ public class UpgradeHelper {
   @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
   public void putComponentsToUpgradingState(UpgradeContext upgradeContext) throws AmbariException {
 
-    // determine which services/components will participate in the upgrade
     Cluster cluster = upgradeContext.getCluster();
-    Set<Service> services = new HashSet<>(cluster.getServices().values());
-    Map<Service, Set<ServiceComponent>> targetServices = new HashMap<>();
-    for (Service service : services) {
-      if (upgradeContext.isServiceSupported(service.getName())) {
-        Set<ServiceComponent> serviceComponents = new HashSet<>(
-            service.getServiceComponents().values());
-
-        targetServices.put(service, serviceComponents);
-      }
-    }
+    Set<String> services = upgradeContext.getSupportedServices();
 
-    RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion();
-    StackId targetStack = targetRepositoryVersion.getStackId();
-
-    for (Map.Entry<Service, Set<ServiceComponent>> entry: targetServices.entrySet()) {
-      // set service desired repo
-      Service service = entry.getKey();
+    for (String serviceName : services) {
+      Service service = cluster.getService(serviceName);
+      RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
+      StackId targetStack = targetRepositoryVersion.getStackId();
       service.setDesiredRepositoryVersion(targetRepositoryVersion);
 
-      for (ServiceComponent serviceComponent: entry.getValue()) {
-
+      Collection<ServiceComponent> components = service.getServiceComponents().values();
+      for (ServiceComponent serviceComponent : components) {
         boolean versionAdvertised = false;
         try {
           ComponentInfo ci = m_ambariMetaInfo.get().getComponent(targetStack.getStackName(),
@@ -773,12 +759,13 @@ public class UpgradeHelper {
           upgradeStateToSet = UpgradeState.NONE;
         }
 
-        for (ServiceComponentHost serviceComponentHost: serviceComponent.getServiceComponentHosts().values()) {
+        for (ServiceComponentHost serviceComponentHost : serviceComponent.getServiceComponentHosts().values()) {
           if (serviceComponentHost.getUpgradeState() != upgradeStateToSet) {
             serviceComponentHost.setUpgradeState(upgradeStateToSet);
           }
 
-          // !!! if we aren't version advertised, but there IS a version, set it.
+          // !!! if we aren't version advertised, but there IS a version, set
+          // it.
           if (!versionAdvertised && !StringUtils.equals(StackVersionListener.UNKNOWN_VERSION,
               serviceComponentHost.getVersion())) {
             serviceComponentHost.setVersion(StackVersionListener.UNKNOWN_VERSION);

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/state/services/RetryUpgradeActionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/services/RetryUpgradeActionService.java b/ambari-server/src/main/java/org/apache/ambari/server/state/services/RetryUpgradeActionService.java
index c43d3ba..cc9c168 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/services/RetryUpgradeActionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/services/RetryUpgradeActionService.java
@@ -31,9 +31,11 @@ import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
+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.Clusters;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -168,12 +170,17 @@ public class RetryUpgradeActionService extends AbstractScheduledService {
     // May be null, and either upgrade or downgrade
     UpgradeEntity currentUpgrade = cluster.getUpgradeInProgress();
     if (currentUpgrade == null) {
-      LOG.debug("There is no active stack upgrade in progress. Skip retrying failed tasks.");
+      LOG.debug("There is no active upgrade in progress. Skip retrying failed tasks.");
       return null;
     }
-    LOG.debug("Found an active stack upgrade with id: {}, direction: {}, type: {}, from version: {}, to version: {}",
-        currentUpgrade.getId(), currentUpgrade.getDirection(), currentUpgrade.getUpgradeType(),
-        currentUpgrade.getFromVersion(), currentUpgrade.getToVersion());
+
+    Direction direction = currentUpgrade.getDirection();
+    RepositoryVersionEntity repositoryVersion = currentUpgrade.getRepositoryVersion();
+
+    LOG.debug(
+        "Found an active upgrade with id: {}, direction: {}, {} {}", currentUpgrade.getId(),
+        direction, currentUpgrade.getUpgradeType(), direction.getPreposition(),
+        repositoryVersion.getVersion());
 
     return currentUpgrade.getRequestId();
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
index cb4f501..9bdfe5d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
@@ -79,4 +79,13 @@ public enum Direction {
   }
 
 
+  /**
+   * Gets the preposition based on the direction. Since the repository is
+   * singular, it will either be "to repo" or "from repo".
+   *
+   * @return "to" or "from"
+   */
+  public String getPreposition() {
+    return (this == UPGRADE) ? "to" : "from";
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/HostOrderGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/HostOrderGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/HostOrderGrouping.java
index d19406e..5fb4c76 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/HostOrderGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/HostOrderGrouping.java
@@ -33,6 +33,7 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleCommandFactory;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
@@ -173,9 +174,14 @@ public class HostOrderGrouping extends Grouping {
           // either doesn't exist or the downgrade is to the current target version.
           // hostsType better not be null either, but check anyway
           if (null != hostsType && !hostsType.hosts.contains(hostName)) {
+            RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
+                sch.getServiceName());
+
             LOG.warn("Host {} could not be orchestrated. Either there are no components for {}/{} " +
                 "or the target version {} is already current.",
-                hostName, sch.getServiceName(), sch.getServiceComponentName(), upgradeContext.getVersion());
+                hostName, sch.getServiceName(), sch.getServiceComponentName(),
+                targetRepositoryVersion.getVersion());
+
             continue;
           }
 
@@ -225,7 +231,7 @@ public class HostOrderGrouping extends Grouping {
           // create task wrappers
           List<TaskWrapper> taskWrappers = new ArrayList<>();
           for (HostRoleCommand command : stageCommandsForHost) {
-            StackId stackId = upgradeContext.getEffectiveStackId();
+            StackId stackId = upgradeContext.getRepositoryVersion().getStackId();
             String componentName = command.getRole().name();
 
             String serviceName = null;
@@ -328,7 +334,10 @@ public class HostOrderGrouping extends Grouping {
      * @return                {@code true} if the host component advertises its version
      */
     private boolean isVersionAdvertised(UpgradeContext upgradeContext, ServiceComponentHost sch) {
-      StackId targetStack = upgradeContext.getTargetStackId();
+      RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
+          sch.getServiceName());
+
+      StackId targetStack = targetRepositoryVersion.getStackId();
 
       try {
         ComponentInfo component = upgradeContext.getAmbariMetaInfo().getComponent(

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
index a11fd96..9cf7bbd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
@@ -312,9 +312,7 @@ public class UpgradeCatalog220 extends AbstractUpgradeCatalog {
       // apply changes
       upgradeDAO.merge(upgrade);
 
-      LOG.info(String.format("Updated upgrade id %s, upgrade pack %s from version %s to %s",
-        upgrade.getId(), upgrade.getUpgradePackage(), upgrade.getFromVersion(),
-        upgrade.getToVersion()));
+      LOG.info(String.format("Updated upgrade id %s", upgrade.getId()));
     }
 
     // make the columns nullable now that they have defaults

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 a2a1ea9..36a46cf 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -812,18 +812,18 @@ CREATE TABLE upgrade (
   upgrade_id BIGINT NOT NULL,
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
-  from_version VARCHAR(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR(255) DEFAULT '' NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
+  repo_version_id BIGINT NOT NULL,
   skip_failures SMALLINT DEFAULT 0 NOT NULL,
   skip_sc_failures SMALLINT DEFAULT 0 NOT NULL,
   downgrade_allowed SMALLINT DEFAULT 1 NOT NULL,
   suspended SMALLINT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -847,17 +847,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
+CREATE TABLE upgrade_history(
   id BIGINT NOT NULL,
-  component_id BIGINT NOT NULL,
   upgrade_id BIGINT NOT NULL,
-  from_stack_id BIGINT NOT NULL,
-  to_stack_id BIGINT NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+  service_name VARCHAR(255) NOT NULL,
+  component_name VARCHAR(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(
@@ -1131,7 +1132,7 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value)
   union all
   select 'servicecomponentdesiredstate_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all
-  select 'servicecomponent_history_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+  select 'upgrade_history_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all
   select 'blueprint_setting_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 6dcbf3d..21200bf 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -830,18 +830,18 @@ CREATE TABLE upgrade (
   upgrade_id BIGINT NOT NULL,
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
-  from_version VARCHAR(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR(255) DEFAULT '' NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
+  repo_version_id BIGINT NOT NULL,
   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,
   suspended TINYINT(1) DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -865,17 +865,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
+CREATE TABLE upgrade_history(
   id BIGINT NOT NULL,
-  component_id BIGINT NOT NULL,
   upgrade_id BIGINT NOT NULL,
-  from_stack_id BIGINT NOT NULL,
-  to_stack_id BIGINT NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+  service_name VARCHAR(255) NOT NULL,
+  component_name VARCHAR(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 15de29c..d148781 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -809,18 +809,18 @@ CREATE TABLE upgrade (
   upgrade_id NUMBER(19) NOT NULL,
   cluster_id NUMBER(19) NOT NULL,
   request_id NUMBER(19) NOT NULL,
-  from_version VARCHAR2(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR2(255) DEFAULT '' NOT NULL,
   direction VARCHAR2(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_package VARCHAR2(255) NOT NULL,
   upgrade_type VARCHAR2(32) NOT NULL,
+  repo_version_id NUMBER(19) NOT NULL,
   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,
   suspended NUMBER(1) DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -844,17 +844,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
-  id NUMBER(19) NOT NULL,
-  component_id NUMBER(19) NOT NULL,
-  upgrade_id NUMBER(19) NOT NULL,
-  from_stack_id NUMBER(19) NOT NULL,
-  to_stack_id NUMBER(19) NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+CREATE TABLE upgrade_history(
+  id BIGINT NOT NULL,
+  upgrade_id BIGINT NOT NULL,
+  service_name VARCHAR2(255) NOT NULL,
+  component_name VARCHAR2(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(
@@ -1081,7 +1082,7 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('topology_ho
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('setting_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('hostcomponentstate_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponentdesiredstate_id_seq', 0);
-INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponent_history_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('blueprint_setting_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('ambari_operation_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_id_seq', 0);

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 9e2f2a7..fc40d44 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -811,18 +811,18 @@ CREATE TABLE upgrade (
   upgrade_id BIGINT NOT NULL,
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
-  from_version VARCHAR(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR(255) DEFAULT '' NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
+  repo_version_id BIGINT NOT NULL,
   skip_failures SMALLINT DEFAULT 0 NOT NULL,
   skip_sc_failures SMALLINT DEFAULT 0 NOT NULL,
   downgrade_allowed SMALLINT DEFAULT 1 NOT NULL,
   suspended SMALLINT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -846,17 +846,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
+CREATE TABLE upgrade_history(
   id BIGINT NOT NULL,
-  component_id BIGINT NOT NULL,
   upgrade_id BIGINT NOT NULL,
-  from_stack_id BIGINT NOT NULL,
-  to_stack_id BIGINT NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+  service_name VARCHAR(255) NOT NULL,
+  component_name VARCHAR(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(
@@ -1082,7 +1083,7 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value) VALUES
   ('setting_id_seq', 0),
   ('hostcomponentstate_id_seq', 0),
   ('servicecomponentdesiredstate_id_seq', 0),
-  ('servicecomponent_history_id_seq', 0),
+  ('upgrade_history_id_seq', 0),
   ('blueprint_setting_id_seq', 0),
   ('ambari_operation_history_id_seq', 0),
   ('remote_cluster_id_seq', 0),

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 473e8ca..d654016 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -807,10 +807,9 @@ CREATE TABLE upgrade (
   upgrade_id NUMERIC(19) NOT NULL,
   cluster_id NUMERIC(19) NOT NULL,
   request_id NUMERIC(19) NOT NULL,
-  from_version VARCHAR(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR(255) DEFAULT '' NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
+  repo_version_id NUMERIC(19) NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   skip_failures BIT NOT NULL DEFAULT 0,
   skip_sc_failures BIT NOT NULL DEFAULT 0,
@@ -818,7 +817,8 @@ CREATE TABLE upgrade (
   suspended BIT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -842,17 +842,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
-  id NUMERIC(19) NOT NULL,
-  component_id NUMERIC(19) NOT NULL,
-  upgrade_id NUMERIC(19) NOT NULL,
-  from_stack_id NUMERIC(19) NOT NULL,
-  to_stack_id NUMERIC(19) NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+CREATE TABLE upgrade_history(
+  id BIGINT NOT NULL,
+  upgrade_id BIGINT NOT NULL,
+  service_name VARCHAR(255) NOT NULL,
+  component_name VARCHAR(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(
@@ -1079,7 +1080,7 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('topology_ho
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('setting_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('hostcomponentstate_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponentdesiredstate_id_seq', 0);
-INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponent_history_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('blueprint_setting_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('ambari_operation_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_id_seq', 0);

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/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 72189aa..f89e720 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -829,18 +829,18 @@ CREATE TABLE upgrade (
   upgrade_id BIGINT NOT NULL,
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
-  from_version VARCHAR(255) DEFAULT '' NOT NULL,
-  to_version VARCHAR(255) DEFAULT '' NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
+  repo_version_id BIGINT NOT NULL,
   skip_failures BIT NOT NULL DEFAULT 0,
   skip_sc_failures BIT NOT NULL DEFAULT 0,
   downgrade_allowed BIT NOT NULL DEFAULT 1,
   suspended BIT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY CLUSTERED (upgrade_id),
   FOREIGN KEY (cluster_id) REFERENCES clusters(cluster_id),
-  FOREIGN KEY (request_id) REFERENCES request(request_id)
+  FOREIGN KEY (request_id) REFERENCES request(request_id),
+  FOREIGN KEY (repo_version_id) REFERENCES repo_version(repo_version_id)
 );
 
 CREATE TABLE upgrade_group (
@@ -864,17 +864,18 @@ CREATE TABLE upgrade_item (
   FOREIGN KEY (upgrade_group_id) REFERENCES upgrade_group(upgrade_group_id)
 );
 
-CREATE TABLE servicecomponent_history(
+CREATE TABLE upgrade_history(
   id BIGINT NOT NULL,
-  component_id BIGINT NOT NULL,
   upgrade_id BIGINT NOT NULL,
-  from_stack_id BIGINT NOT NULL,
-  to_stack_id BIGINT NOT NULL,
-  CONSTRAINT PK_sc_history PRIMARY KEY (id),
-  CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id),
-  CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id),
-  CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)
+  service_name VARCHAR(255) NOT NULL,
+  component_name VARCHAR(255) NOT NULL,
+  from_repo_version_id BIGINT NOT NULL,
+  target_repo_version_id BIGINT NOT NULL,
+  CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
+  CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
+  CONSTRAINT FK_upgrade_hist_from_repo FOREIGN KEY (from_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT FK_upgrade_hist_target_repo FOREIGN KEY (target_repo_version_id) REFERENCES repo_version (repo_version_id),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name)
 );
 
 CREATE TABLE servicecomponent_version(
@@ -1106,7 +1107,7 @@ BEGIN TRANSACTION
     ('setting_id_seq', 0),
     ('hostcomponentstate_id_seq', 0),
     ('servicecomponentdesiredstate_id_seq', 0),
-    ('servicecomponent_history_id_seq', 0),
+    ('upgrade_history_id_seq', 0),
     ('blueprint_setting_id_seq', 0),
     ('ambari_operation_history_id_seq', 0),
     ('remote_cluster_id_seq', 0),

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 8fd539a..e4045ef 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -64,7 +64,6 @@
     <class>org.apache.ambari.server.orm.entities.ResourceTypeEntity</class>
     <class>org.apache.ambari.server.orm.entities.RoleSuccessCriteriaEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity</class>
-    <class>org.apache.ambari.server.orm.entities.ServiceComponentHistoryEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceConfigEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity</class>
@@ -73,6 +72,7 @@
     <class>org.apache.ambari.server.orm.entities.UpgradeEntity</class>
     <class>org.apache.ambari.server.orm.entities.UpgradeGroupEntity</class>
     <class>org.apache.ambari.server.orm.entities.UpgradeItemEntity</class>
+    <class>org.apache.ambari.server.orm.entities.UpgradeHistoryEntity</class>
     <class>org.apache.ambari.server.orm.entities.UserEntity</class>
     <class>org.apache.ambari.server.orm.entities.WidgetEntity</class>
     <class>org.apache.ambari.server.orm.entities.ViewEntity</class>

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java b/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java
index b361418..4542bb3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java
@@ -52,6 +52,7 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.easymock.EasyMock;
 import org.easymock.EasyMockSupport;
 import org.junit.After;
@@ -225,7 +226,7 @@ public class ComponentVersionAlertRunnableTest extends EasyMockSupport {
   @Test
   public void testUpgradeInProgress() throws Exception {
     UpgradeEntity upgrade = createNiceMock(UpgradeEntity.class);
-    expect(upgrade.getToVersion()).andReturn("VERSION").once();
+    expect(upgrade.getDirection()).andReturn(Direction.UPGRADE).atLeastOnce();
     expect(m_cluster.getUpgradeInProgress()).andReturn(upgrade).once();
 
     replayAll();

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/UpgradeEventCreatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/UpgradeEventCreatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/UpgradeEventCreatorTest.java
index db76d4e..a8e21f6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/UpgradeEventCreatorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/UpgradeEventCreatorTest.java
@@ -40,7 +40,7 @@ public class UpgradeEventCreatorTest extends AuditEventCreatorTestBase{
     UpgradeEventCreator creator = new UpgradeEventCreator();
 
     Map<String,Object> properties = new HashMap<>();
-    properties.put(UpgradeResourceProvider.UPGRADE_VERSION, "1.9");
+    properties.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID, "1234");
     properties.put(UpgradeResourceProvider.UPGRADE_TYPE, "ROLLING");
     properties.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "mycluster");
 
@@ -50,7 +50,7 @@ public class UpgradeEventCreatorTest extends AuditEventCreatorTestBase{
     AuditEvent event = AuditEventCreatorTestHelper.getEvent(creator, request, result);
 
     String actual = event.getAuditMessage();
-    String expected = "User(" + userName + "), RemoteIp(1.2.3.4), Operation(Upgrade addition), RequestType(POST), url(http://example.com:8080/api/v1/test), ResultStatus(200 OK), Repository version(1.9), Upgrade type(ROLLING), Cluster name(mycluster)";
+    String expected = "User(" + userName + "), RemoteIp(1.2.3.4), Operation(Upgrade addition), RequestType(POST), url(http://example.com:8080/api/v1/test), ResultStatus(200 OK), Repository version ID(1234), Upgrade type(ROLLING), Cluster name(mycluster)";
 
     Assert.assertTrue("Class mismatch", event instanceof AddUpgradeRequestAuditEvent);
     Assert.assertEquals(expected, actual);

http://git-wip-us.apache.org/repos/asf/ambari/blob/522039eb/ambari-server/src/test/java/org/apache/ambari/server/checks/PreviousUpgradeCompletedTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/PreviousUpgradeCompletedTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/PreviousUpgradeCompletedTest.java
index 4bfa8d4..3233e55 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/checks/PreviousUpgradeCompletedTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/PreviousUpgradeCompletedTest.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.checks;
 
 import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.state.Cluster;
@@ -49,6 +50,8 @@ public class PreviousUpgradeCompletedTest {
   private PrereqCheckRequest checkRequest = new PrereqCheckRequest(clusterName);
   private PreviousUpgradeCompleted puc = new PreviousUpgradeCompleted();
 
+  private RepositoryVersionEntity toRepsitoryVersion;
+
   /**
    *
    */
@@ -75,6 +78,8 @@ public class PreviousUpgradeCompletedTest {
       }
     };
 
+    toRepsitoryVersion = Mockito.mock(RepositoryVersionEntity.class);
+    Mockito.when(toRepsitoryVersion.getVersion()).thenReturn(destRepositoryVersion);
   }
 
   @Test
@@ -89,8 +94,7 @@ public class PreviousUpgradeCompletedTest {
     UpgradeEntity upgradeInProgress = Mockito.mock(UpgradeEntity.class);
     Mockito.when(upgradeInProgress.getDirection()).thenReturn(Direction.UPGRADE);
     Mockito.when(upgradeInProgress.getClusterId()).thenReturn(1L);
-    Mockito.when(upgradeInProgress.getFromVersion()).thenReturn(sourceRepositoryVersion);
-    Mockito.when(upgradeInProgress.getToVersion()).thenReturn(destRepositoryVersion);
+    Mockito.when(upgradeInProgress.getRepositoryVersion()).thenReturn(toRepsitoryVersion);
 
     Mockito.when(cluster.getUpgradeInProgress()).thenReturn(upgradeInProgress);
     check = new PrerequisiteCheck(null, null);